use crate::component::{Component, EventCx, LayoutCx, MeasureCx};
use crate::event::Event;
use crate::geom::{Rect, Size};
use crate::layout::Constraint;
use crate::node::Node;
use crate::render::RenderCx;
use crate::style::Style;
pub struct Scroll {
child: Option<Node>,
scroll_y: u16,
content_height: u16,
}
impl Scroll {
pub fn new(child: impl Component + 'static) -> Self {
Self {
child: Some(Node::new(child)),
scroll_y: 0,
content_height: 0,
}
}
}
impl Component for Scroll {
fn render(&self, cx: &mut RenderCx) {
if let Some(child) = &self.child {
let viewport = cx.rect;
let max_scroll = self.content_height.saturating_sub(viewport.height);
let scroll = self.scroll_y.min(max_scroll);
fn offset_all(node: &Node, delta: i16) {
let mut r = node.rect();
if delta >= 0 {
r.y = r.y.wrapping_add(delta as u16);
} else {
r.y = r.y.wrapping_sub((-delta) as u16);
}
node.set_rect(r);
node.component.for_each_child(&mut |c: &Node| offset_all(c, delta));
}
let delta = -(scroll as i16);
offset_all(child, delta);
child.render_with_clip(cx.buffer, cx.focused_id, Some(viewport));
offset_all(child, -delta); }
}
fn measure(&self, constraint: Constraint, _cx: &mut MeasureCx) -> Size {
Size {
width: constraint.max.width,
height: constraint.max.height,
}
}
fn focusable(&self) -> bool {
false
}
fn event(&mut self, event: &Event, cx: &mut EventCx) {
if matches!(event, Event::Focus | Event::Blur) {
return;
}
if let Event::Key(key_event) = event {
match &key_event.key {
crate::event::Key::Up => {
self.scroll_y = self.scroll_y.saturating_sub(1);
cx.invalidate_paint();
return;
}
crate::event::Key::Down => {
self.scroll_y = self.scroll_y.saturating_add(1);
cx.invalidate_paint();
return;
}
_ => {}
}
}
if let Event::Mouse(mouse_event) = event {
match mouse_event.kind {
crate::event::MouseKind::ScrollUp => {
self.scroll_y = self.scroll_y.saturating_sub(1);
cx.invalidate_paint();
return;
}
crate::event::MouseKind::ScrollDown => {
self.scroll_y = self.scroll_y.saturating_add(1);
cx.invalidate_paint();
return;
}
_ => {}
}
}
if let Some(child) = &mut self.child {
let mut child_cx = EventCx::new(
&mut child.dirty,
cx.global_dirty,
cx.quit,
cx.phase,
cx.propagation_stopped,
);
child.component.event(event, &mut child_cx);
}
}
fn layout(&mut self, rect: Rect, _cx: &mut LayoutCx) {
if let Some(child) = &mut self.child {
let child_size = child.measure(Constraint::loose(rect.width, 65535));
self.content_height = child_size.height;
let child_rect = Rect {
x: rect.x,
y: rect.y,
width: rect.width,
height: child_size.height,
};
child.layout(child_rect);
}
}
fn for_each_child(&self, f: &mut dyn FnMut(&Node)) {
if let Some(child) = &self.child {
f(child);
}
}
fn for_each_child_mut(&mut self, f: &mut dyn FnMut(&mut Node)) {
if let Some(child) = &mut self.child {
f(child);
}
}
fn style(&self) -> Style {
Style::default()
}
}