1use kas::event::{CursorIcon, Scroll, components::ScrollComponent};
9use kas::prelude::*;
10use std::fmt::Debug;
11
12#[impl_self]
13mod ScrollRegion {
14 #[derive(Clone, Debug, Default)]
32 #[widget]
33 pub struct ScrollRegion<W: Widget> {
34 core: widget_core!(),
35 min_child_size: Size,
36 offset: Offset,
37 frame_size: Size,
38 scroll: ScrollComponent,
39 #[widget]
40 inner: W,
41 }
42
43 impl Self {
44 #[inline]
46 pub fn new(inner: W) -> Self {
47 ScrollRegion {
48 core: Default::default(),
49 min_child_size: Size::ZERO,
50 offset: Default::default(),
51 frame_size: Default::default(),
52 scroll: Default::default(),
53 inner,
54 }
55 }
56
57 #[inline]
59 pub fn inner(&self) -> &W {
60 &self.inner
61 }
62
63 #[inline]
65 pub fn inner_mut(&mut self) -> &mut W {
66 &mut self.inner
67 }
68 }
69
70 impl Scrollable for Self {
71 #[inline]
72 fn content_size(&self) -> Size {
73 self.min_child_size
74 }
75
76 #[inline]
77 fn max_scroll_offset(&self) -> Offset {
78 self.scroll.max_offset()
79 }
80
81 #[inline]
82 fn scroll_offset(&self) -> Offset {
83 self.scroll.offset()
84 }
85
86 #[inline]
87 fn set_scroll_offset(&mut self, cx: &mut EventCx, offset: Offset) -> Offset {
88 let action = self.scroll.set_offset(offset);
89 cx.action(&self, action);
90 self.scroll.offset()
91 }
92 }
93
94 impl Layout for Self {
95 fn size_rules(&mut self, sizer: SizeCx, mut axis: AxisInfo) -> SizeRules {
96 axis.sub_other(self.frame_size.extract(axis.flipped()));
97
98 let mut rules = self.inner.size_rules(sizer.re(), axis);
99 self.min_child_size.set_component(axis, rules.min_size());
100 rules.reduce_min_to(sizer.min_scroll_size(axis));
101
102 let frame = kas::layout::FrameRules::ZERO;
104 let (rules, offset, size) = frame.surround(rules);
105 self.offset.set_component(axis, offset);
106 self.frame_size.set_component(axis, size);
107 rules
108 }
109
110 fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
111 widget_set_rect!(rect);
112 let child_size = (rect.size - self.frame_size).max(self.min_child_size);
113 let child_rect = Rect::new(rect.pos, child_size);
114 self.inner.set_rect(cx, child_rect, hints);
115 let _ = self
116 .scroll
117 .set_sizes(rect.size, child_size + self.frame_size);
118 }
119
120 fn draw(&self, mut draw: DrawCx) {
121 draw.with_clip_region(self.rect(), self.scroll_offset(), |mut draw| {
123 self.inner.draw(draw.re());
124 });
125 }
126 }
127
128 impl Tile for Self {
129 fn role(&self, _: &mut dyn RoleCx) -> Role<'_> {
130 Role::ScrollRegion {
131 offset: self.scroll_offset(),
132 max_offset: self.max_scroll_offset(),
133 }
134 }
135
136 #[inline]
137 fn translation(&self, _: usize) -> Offset {
138 self.scroll_offset()
139 }
140
141 fn probe(&self, coord: Coord) -> Id {
142 if self.scroll.is_kinetic_scrolling() {
143 return self.id();
144 }
145
146 self.inner
147 .try_probe(coord + self.scroll_offset())
148 .unwrap_or_else(|| self.id())
149 }
150 }
151
152 impl Events for Self {
153 type Data = W::Data;
154
155 fn mouse_over_icon(&self) -> Option<CursorIcon> {
156 self.scroll
157 .is_kinetic_scrolling()
158 .then_some(CursorIcon::AllScroll)
159 }
160
161 fn configure(&mut self, cx: &mut ConfigCx) {
162 cx.register_nav_fallback(self.id());
163 }
164
165 fn handle_event(&mut self, cx: &mut EventCx, _: &Self::Data, event: Event) -> IsUsed {
166 self.scroll
167 .scroll_by_event(cx, event, self.id(), self.rect())
168 }
169
170 fn handle_messages(&mut self, cx: &mut EventCx, _: &Self::Data) {
171 if let Some(kas::messages::SetScrollOffset(offset)) = cx.try_pop() {
172 self.set_scroll_offset(cx, offset);
173 }
174 }
175
176 fn handle_scroll(&mut self, cx: &mut EventCx, _: &Self::Data, scroll: Scroll) {
177 self.scroll.scroll(cx, self.id(), self.rect(), scroll);
178 }
179 }
180}