makepad_widgets/
fold_header.rs

1use crate::{
2    makepad_derive_widget::*,
3    makepad_draw::*,
4    widget::*,
5    fold_button::*
6};
7
8live_design!{
9    link widgets;
10    use link::theme::*;
11    
12    pub FoldHeaderBase = {{FoldHeader}} {}
13    pub FoldHeader = <FoldHeaderBase> {
14        width: Fill, height: Fit,
15        body_walk: { width: Fill, height: Fit}
16        
17        flow: Down,
18        
19        animator: {
20            active = {
21                default: on
22                off = {
23                    from: {all: Forward {duration: 0.2}}
24                    ease: ExpDecay {d1: 0.96, d2: 0.97}
25                    redraw: true
26                    apply: {
27                        opened: [{time: 0.0, value: 1.0}, {time: 1.0, value: 0.0}]
28                    }
29                }
30                on = {
31                    from: {all: Forward {duration: 0.2}}
32                    ease: ExpDecay {d1: 0.98, d2: 0.95}
33                    redraw: true
34                    apply: {
35                        opened: [{time: 0.0, value: 0.0}, {time: 1.0, value: 1.0}]
36                    }
37                }
38            }
39        }
40    }
41    
42}
43
44#[derive(Live, LiveHook, Widget)]
45pub struct FoldHeader {
46    #[rust] draw_state: DrawStateWrap<DrawState>,
47    #[rust] rect_size: f64,
48    #[rust] area: Area,
49    #[find] #[redraw] #[live] header: WidgetRef,
50    #[find] #[redraw] #[live] body: WidgetRef,
51    #[animator] animator: Animator,
52
53    #[live] opened: f64,
54    #[layout] layout: Layout,
55    #[walk] walk: Walk,
56    #[live] body_walk: Walk,
57}
58
59#[derive(Clone)]
60enum DrawState {
61    DrawHeader,
62    DrawBody
63}
64
65impl Widget for FoldHeader {
66    fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
67        if self.animator_handle_event(cx, event).must_redraw() {
68            if self.animator.is_track_animating(cx, id!(active)) {
69                self.area.redraw(cx);
70            }
71        };
72        
73        self.header.handle_event(cx,  event, scope);
74        
75        if let Event::Actions(actions) = event{
76            match actions.find_widget_action(self.header.widget(id!(fold_button)).widget_uid()).cast() {
77                FoldButtonAction::Opening => {
78                    self.animator_play(cx, id!(active.on))
79                }
80                FoldButtonAction::Closing => {
81                    self.animator_play(cx, id!(active.off))
82                }
83                _ => ()
84            }
85        }
86    }
87
88    
89    fn draw_walk(&mut self, cx: &mut Cx2d, scope:&mut Scope, walk: Walk) -> DrawStep {
90        if self.draw_state.begin(cx, DrawState::DrawHeader) {
91            cx.begin_turtle(walk, self.layout);
92        }
93        if let Some(DrawState::DrawHeader) = self.draw_state.get() {
94            let walk = self.header.walk(cx);
95            self.header.draw_walk(cx, scope, walk) ?;
96            cx.begin_turtle(
97                self.body_walk,
98                Layout::flow_down()
99                .with_scroll(dvec2(0.0, self.rect_size * (1.0 - self.opened)))
100            );
101            self.draw_state.set(DrawState::DrawBody);
102        }
103        if let Some(DrawState::DrawBody) = self.draw_state.get() {
104            let walk = self.body.walk(cx);
105            self.body.draw_walk(cx, scope, walk) ?;
106            self.rect_size = cx.turtle().used().y;
107            cx.end_turtle();
108            cx.end_turtle_with_area(&mut self.area);
109            self.draw_state.end();
110        }
111        DrawStep::done()
112    }
113}
114
115#[derive(Clone, DefaultNone)]
116pub enum FoldHeaderAction {
117    Opening,
118    Closing,
119    None
120}