Skip to content

Commit

Permalink
bounded scrolling when overflowing
Browse files Browse the repository at this point in the history
  • Loading branch information
achristmascarl committed Jul 4, 2024
1 parent 3a0f18c commit 89b5d3f
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 16 deletions.
1 change: 0 additions & 1 deletion src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ impl App {
}
state.data = Some(results);
}
action_consumed = true;
},
_ => {},
}
Expand Down
10 changes: 10 additions & 0 deletions src/components/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ impl<'a> Component for Data<'a> {
Ok(None)
}

fn update(&mut self, action: Action) -> Result<Option<Action>> {
match action {
Action::Query(query) => {
self.scrollable.reset_scroll();
},
_ => {},
}
Ok(None)
}

fn draw(&mut self, f: &mut Frame<'_>, area: Rect) -> Result<()> {
let mut state = self.state.lock().unwrap();
let focused = state.focus == Focus::Data;
Expand Down
71 changes: 56 additions & 15 deletions src/components/scrollable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,6 @@ use ratatui::{

use super::Component;

#[derive(Debug, Clone, Default)]
pub struct Scrollable<'a> {
child_buffer: Buffer,
block: Option<Block<'a>>,
pub x_offset: u16,
pub y_offset: u16,
}

pub enum ScrollXDirection {
Left,
Right,
Expand All @@ -25,9 +17,26 @@ pub enum ScrollYDirection {
Down,
}

#[derive(Debug, Clone, Default)]
pub struct Scrollable<'a> {
child_buffer: Buffer,
parent_area: Rect,
block: Option<Block<'a>>,
x_offset: u16,
y_offset: u16,
max_offsets: MaxOffsets,
}

impl<'a> Scrollable<'a> {
pub fn new() -> Self {
Self { child_buffer: Buffer::empty(Rect::new(0, 0, 0, 0)), block: None, x_offset: 0, y_offset: 0 }
Self {
child_buffer: Buffer::empty(Rect::new(0, 0, 0, 0)),
parent_area: Rect::new(0, 0, 0, 0),
block: None,
x_offset: 0,
y_offset: 0,
max_offsets: MaxOffsets { max_x_offset: 0, max_y_offset: 0 },
}
}

pub fn child(&mut self, child_widget: Box<dyn WidgetRef>, max_height: u16, max_width: u16) -> &mut Self {
Expand All @@ -51,7 +60,9 @@ impl<'a> Scrollable<'a> {
}
},
ScrollXDirection::Right => {
self.x_offset += 1;
if self.x_offset < self.max_offsets.max_x_offset {
self.x_offset += 1;
}
},
}
self
Expand All @@ -65,12 +76,20 @@ impl<'a> Scrollable<'a> {
}
},
ScrollYDirection::Down => {
self.y_offset += 1;
if self.y_offset < self.max_offsets.max_y_offset {
self.y_offset += 1;
}
},
}
self
}

pub fn reset_scroll(&mut self) -> &mut Self {
self.x_offset = 0;
self.y_offset = 0;
self
}

fn widget(&'a self) -> impl Widget + 'a {
Renderer::new(self)
}
Expand Down Expand Up @@ -115,11 +134,35 @@ impl<'a> Scrollable<'a> {

impl<'a> Component for Scrollable<'a> {
fn draw(&mut self, f: &mut Frame<'_>, area: Rect) -> Result<()> {
self.parent_area = area;
self.max_offsets = get_max_offsets(&self.child_buffer, &self.parent_area, &self.block);
f.render_widget(self.widget(), area);
Ok(())
}
}

#[derive(Debug, Clone, Default)]
struct MaxOffsets {
max_x_offset: u16,
max_y_offset: u16,
}

fn get_max_offsets(child_buffer: &Buffer, parent_area: &Rect, parent_block: &Option<Block>) -> MaxOffsets {
parent_block.render_ref(*parent_area, &mut child_buffer.clone());
let render_area = parent_block.inner_if_some(*parent_area);
if render_area.is_empty() {
return MaxOffsets { max_x_offset: 0, max_y_offset: 0 };
}
let parent_width = render_area.width as i32;
let parent_height = render_area.height as i32;
let content_height = child_buffer.area.height as i32;
let content_width = child_buffer.area.width as i32;
MaxOffsets {
max_x_offset: Ord::max(content_width - parent_width, 0) as u16,
max_y_offset: Ord::max(content_height - parent_height, 0) as u16,
}
}

fn clamp(buf: Buffer) -> Buffer {
let height = buf.area.height;
let width = buf.area.width;
Expand Down Expand Up @@ -163,13 +206,11 @@ impl<'a> Widget for Renderer<'a> {
if render_area.is_empty() {
return;
}
log::info!("render area: {}", render_area);
let area = render_area.intersection(buf.area);
log::info!("intersection area: {}", area);
let max_x = Ord::min(area.x.saturating_add(area.width), buf.area.right());
let max_y = Ord::min(area.y.saturating_add(area.height), buf.area.bottom());
let content_height = scrollable.child_buffer.area.height;
let content_width = scrollable.child_buffer.area.width;
let max_x = Ord::min(area.x.saturating_add(area.width), area.x.saturating_add(content_width));
let max_y = Ord::min(area.y.saturating_add(area.height), area.y.saturating_add(content_height));
for y in area.y..max_y {
let content_y = y + scrollable.y_offset - area.y;
let row = get_row(&scrollable.child_buffer.content, content_y, content_width);
Expand Down

0 comments on commit 89b5d3f

Please sign in to comment.