makepad_widgets/
scroll_bars.rs

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