makepad_widgets/
scroll_bars.rs

1use crate::{
2    makepad_draw::*,
3    scroll_bar::*
4};
5
6live_design!{
7    ScrollBarsBase = {{ScrollBars}} {}
8}
9
10#[derive(Live, LiveHook)]
11pub struct ScrollBars {
12    #[live] show_scroll_x: bool,
13    #[live] show_scroll_y: bool,
14    #[live] scroll_bar_x: ScrollBar,
15    #[live] scroll_bar_y: ScrollBar,
16    #[rust] nav_scroll_index: Option<NavScrollIndex>,
17    #[rust] scroll: DVec2,
18    #[rust] area: Area,
19}
20
21pub enum ScrollBarsAction {
22    ScrollX(f64),
23    ScrollY(f64),
24    None
25}
26
27impl ScrollBars {
28    
29    pub fn set_scroll_x(&mut self, _cx: &mut Cx, value: f64) {
30        self.scroll.x = value;
31    }
32    
33    pub fn set_scroll_y(&mut self, _cx: &mut Cx, value: f64) {
34        self.scroll.y = value;
35    }
36    
37    pub fn get_scroll_pos(&self) -> DVec2 {
38        self.scroll
39    }
40
41    pub fn handle_event_with(&mut self, cx: &mut Cx, event: &Event,  dispatch_action: &mut dyn FnMut(&mut Cx, ScrollBarsAction)) {
42        self.handle_main_event(cx, event, dispatch_action);
43        self.handle_scroll_event(cx, event, dispatch_action);
44    }
45    
46    pub fn handle_main_event(&mut self, cx: &mut Cx, event: &Event,  dispatch_action: &mut dyn FnMut(&mut Cx, ScrollBarsAction)) {
47        if let Event::Trigger(te) = event{
48            if let Some(triggers) = te.triggers.get(&self.area){
49                if let Some(trigger) = triggers.iter().find(|t| t.id == live_id!(scroll_focus_nav)){
50                    let self_rect = self.area.get_rect(cx);
51                    self.scroll_into_view(
52                        cx,
53                        trigger.from.get_rect(cx)
54                        .translate(-self_rect.pos + self.scroll)
55                        .add_margin(dvec2(5.0,5.0))
56                    );
57                }
58            }
59        }
60        
61        if self.show_scroll_x {
62            let mut ret_x = None;
63            self.scroll_bar_x.handle_event_with(cx, event, &mut | cx, action | {
64                match action {
65                    ScrollBarAction::Scroll {scroll_pos, ..} => {
66                        ret_x = Some(scroll_pos);
67                        dispatch_action(cx, ScrollBarsAction::ScrollX(scroll_pos))
68                    }
69                    _ => ()
70                }
71            });
72            if let Some(x) = ret_x {self.scroll.x = x; self.redraw(cx);}
73        }
74        if self.show_scroll_y {
75            let mut ret_y = None;
76            self.scroll_bar_y.handle_event_with(cx, event, &mut | cx, action | {
77                match action {
78                    ScrollBarAction::Scroll {scroll_pos, ..} => {
79                        ret_y = Some(scroll_pos);
80                        dispatch_action(cx, ScrollBarsAction::ScrollY(scroll_pos))
81                    }
82                    _ => ()
83                }
84            });
85            if let Some(y) = ret_y {self.scroll.y = y; self.redraw(cx);}
86        }
87    }
88    
89    pub fn handle_scroll_event(&mut self, cx: &mut Cx, event: &Event, dispatch_action: &mut dyn FnMut(&mut Cx, ScrollBarsAction)) {
90        
91        if self.show_scroll_x {
92            let mut ret_x = None;
93            self.scroll_bar_x.handle_scroll_event(cx, event, self.area, &mut | cx, action | {
94                match action {
95                    ScrollBarAction::Scroll {scroll_pos, ..} => {
96                        ret_x = Some(scroll_pos);
97                        dispatch_action(cx, ScrollBarsAction::ScrollX(scroll_pos))
98                    }
99                    _ => ()
100                }
101            });
102            if let Some(x) = ret_x {self.scroll.x = x; self.redraw(cx);}
103        }
104        if self.show_scroll_y {
105            let mut ret_y = None;
106            self.scroll_bar_y.handle_scroll_event(cx, event, self.area, &mut | cx, action | {
107                match action {
108                    ScrollBarAction::Scroll {scroll_pos, ..} => {
109                        ret_y = Some(scroll_pos);
110                        dispatch_action(cx, ScrollBarsAction::ScrollY(scroll_pos))
111                    }
112                    _ => ()
113                }
114            });
115            if let Some(y) = ret_y {self.scroll.y = y; self.redraw(cx);}
116        }
117    }
118    
119    pub fn set_scroll_pos(&mut self, cx: &mut Cx, pos: DVec2) -> bool {
120        //let view_area = Area::DrawList(DrawListArea{draw_list_id:draw_list_id, redraw_id:cx.redraw_id});
121        let mut changed = false;
122        if self.show_scroll_x {
123            if self.scroll_bar_x.set_scroll_pos(cx, pos.x) {
124                changed = true;
125            }
126            let scroll_pos = self.scroll_bar_x.get_scroll_pos();
127            self.set_scroll_x(cx, scroll_pos);
128        }
129        if self.show_scroll_y {
130            if self.scroll_bar_y.set_scroll_pos(cx, pos.y) {
131                changed = true;
132            }
133            let scroll_pos = self.scroll_bar_y.get_scroll_pos();
134            self.set_scroll_y(cx, scroll_pos);
135        }
136        changed
137    }
138    
139    pub fn set_scroll_pos_no_clip(&mut self, cx: &mut Cx, pos: DVec2) -> bool {
140        let mut changed = false;
141        if self.show_scroll_x {
142            if self.scroll_bar_x.set_scroll_pos_no_clip(cx, pos.x) {
143                changed = true;
144            }
145            self.set_scroll_x(cx, pos.x);
146        }
147        if self.show_scroll_y {
148            if self.scroll_bar_y.set_scroll_pos_no_clip(cx, pos.y) {
149                changed = true;
150            }
151            self.set_scroll_y(cx, pos.y);
152        }
153        changed
154    }
155    
156    pub fn get_scroll_view_total(&mut self) -> DVec2 {
157        DVec2 {
158            x: if self.show_scroll_x {
159                self.scroll_bar_x.get_scroll_view_total()
160            }else {0.},
161            y: if self.show_scroll_y {
162                self.scroll_bar_y.get_scroll_view_total()
163            }else {0.}
164        }
165    }
166    
167    pub fn get_scroll_view_visible(&mut self) -> DVec2 {
168        DVec2 {
169            x: if self.show_scroll_x {
170                self.scroll_bar_x.get_scroll_view_visible()
171            }else {0.},
172            y: if self.show_scroll_y {
173                self.scroll_bar_y.get_scroll_view_visible()
174            }else {0.}
175        }
176    }
177    
178    pub fn get_viewport_rect(&mut self, _cx: &mut Cx) -> Rect {
179        let pos = self.get_scroll_pos();
180        let size = self.get_scroll_view_visible();
181        Rect {pos, size}
182    }
183    
184    pub fn scroll_into_view(&mut self, cx: &mut Cx, rect: Rect) {
185        if self.show_scroll_x {
186            self.scroll_bar_x.scroll_into_view(cx, rect.pos.x, rect.size.x, true);
187        }
188        if self.show_scroll_y {
189            self.scroll_bar_y.scroll_into_view(cx, rect.pos.y, rect.size.y, true);
190        }
191    }
192    
193    pub fn scroll_into_view_no_smooth(&mut self, cx: &mut Cx, rect: Rect) {
194        if self.show_scroll_x {
195            self.scroll_bar_x.scroll_into_view(cx, rect.pos.x, rect.size.x, false);
196        }
197        if self.show_scroll_y {
198            self.scroll_bar_y.scroll_into_view(cx, rect.pos.y, rect.size.y, false);
199        }
200    }
201    
202    pub fn scroll_into_view_abs(&mut self, cx: &mut Cx, rect: Rect) {
203        let self_rect = self.area.get_rect(cx);
204        if self.show_scroll_x {
205            self.scroll_bar_x.scroll_into_view(cx, rect.pos.x - self_rect.pos.x, rect.size.x, true);
206        }
207        if self.show_scroll_y {
208            self.scroll_bar_y.scroll_into_view(cx, rect.pos.y - self_rect.pos.y, rect.size.y, true);
209        }
210    }
211    
212    pub fn set_scroll_target(&mut self, cx: &mut Cx, pos: DVec2) {
213        if self.show_scroll_x {
214            self.scroll_bar_x.set_scroll_target(cx, pos.x);
215        }
216        if self.show_scroll_y {
217            self.scroll_bar_y.set_scroll_target(cx, pos.y);
218        }
219    }
220    
221    
222    // all in one scrollbar api
223    
224    pub fn begin(&mut self, cx: &mut Cx2d, walk: Walk, layout: Layout) {
225        cx.begin_turtle(walk, layout.with_scroll(self.scroll));
226        self.begin_nav_area(cx);
227    }
228    
229    pub fn end(&mut self, cx: &mut Cx2d) {
230        self.draw_scroll_bars(cx);
231        // this needs to be a rect_area
232        cx.end_turtle_with_area(&mut self.area);
233        self.end_nav_area(cx);
234    }
235    
236    
237    pub fn end_with_shift(&mut self, cx: &mut Cx2d) {
238        self.draw_scroll_bars(cx);
239        // this needs to be a rect_area
240        cx.end_turtle_with_area(&mut self.area);
241        self.end_nav_area(cx);
242    }
243    // separate API
244    
245    pub fn begin_nav_area(&mut self, cx: &mut Cx2d) {
246        self. nav_scroll_index = Some(cx.add_begin_scroll());
247    }
248    
249    pub fn end_nav_area(&mut self, cx: &mut Cx2d) {
250        if !self.area.is_valid(cx) {
251            panic!("Call set area before end_nav_area")
252        }
253        cx.add_end_scroll(self.nav_scroll_index.take().unwrap(), self.area);
254    }
255    
256    pub fn draw_scroll_bars(&mut self, cx: &mut Cx2d) {
257        // lets ask the turtle our actual bounds
258        let view_total = cx.turtle().used();
259        let mut rect_now = cx.turtle().rect();
260        
261        if rect_now.size.y.is_nan() {
262            rect_now.size.y = view_total.y;
263        }
264        if rect_now.size.x.is_nan() {
265            rect_now.size.x = view_total.x;
266        }
267        
268        if self.show_scroll_x {
269            let scroll_pos = self.scroll_bar_x.draw_scroll_bar(cx, Axis::Horizontal, rect_now, view_total);
270            self.set_scroll_x(cx, scroll_pos);
271        }
272        if self.show_scroll_y {
273            //println!("SET SCROLLBAR {} {}", rect_now.h, view_total.y);
274            let scroll_pos = self.scroll_bar_y.draw_scroll_bar(cx, Axis::Vertical, rect_now, view_total);
275            self.set_scroll_y(cx, scroll_pos);
276        }
277    }
278    
279    pub fn set_area(&mut self, area: Area) {
280        self.area = area;
281    }
282    
283    pub fn area(&self) -> Area {
284        self.area
285    }
286    
287    pub fn redraw(&self, cx: &mut Cx) {
288        self.area.redraw(cx);
289    }
290}