makepad_widgets/
fold_button.rs

1use crate::{
2    makepad_derive_widget::*,
3    makepad_draw::*,
4    widget::*,
5};
6
7live_design!{
8    link widgets;
9    use link::theme::*;
10    use link::shaders::*;
11    
12    pub FoldButtonBase = {{FoldButton}} {}
13    
14    pub FoldButton = <FoldButtonBase> {
15        height: 20, width: 15,
16        margin: { left: 0. }
17        
18        draw_bg: {
19            instance active: 0.0
20            instance hover: 0.0
21
22            uniform color: (THEME_COLOR_LABEL_INNER)
23            uniform color_hover: (THEME_COLOR_LABEL_INNER_HOVER)
24            uniform color_active: (THEME_COLOR_LABEL_INNER_ACTIVE)
25
26            uniform fade: 1.0
27            
28            fn pixel(self) -> vec4 {
29                let sz = 2.5;
30                let c = vec2(5.0, self.rect_size.y * 0.4);
31                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
32                sdf.clear(vec4(0.));
33                    
34                // we have 3 points, and need to rotate around its center
35                sdf.rotate(self.active * 0.5 * PI + 0.5 * PI, c.x, c.y);
36                sdf.move_to(c.x - sz, c.y + sz);
37                sdf.line_to(c.x, c.y - sz);
38                sdf.line_to(c.x + sz, c.y + sz);
39                sdf.close_path();
40                sdf.fill(
41                    mix(
42                        mix(self.color, self.color_hover, self.hover),
43                        mix(self.color_active, self.color_hover, self.hover),
44                        self.active
45                    )
46                );
47                return sdf.result * self.fade;
48            }
49        }
50        
51        animator: {
52            hover = {
53                default: off
54                off = {
55                    from: {all: Forward {duration: 0.1}}
56                    apply: {draw_bg: {hover: 0.0}}
57                }
58                
59                on = {
60                    from: {all: Snap}
61                    apply: {draw_bg: {hover: 1.0}}
62                }
63            }
64            
65            active = {
66                default: on
67                off = {
68                    from: {all: Forward {duration: 0.2}}
69                    ease: ExpDecay {d1: 0.96, d2: 0.97}
70                    redraw: true
71                    apply: {
72                        active: 0.0
73                        draw_bg: {active: [{time: 0.0, value: 1.0}, {time: 1.0, value: 0.0}]}
74                    }
75                }
76                on = {
77                    from: {all: Forward {duration: 0.2}}
78                    ease: ExpDecay {d1: 0.98, d2: 0.95}
79                    redraw: true
80                    apply: {
81                        active: 1.0
82                        draw_bg: {active: [{time: 0.0, value: 0.0}, {time: 1.0, value: 1.0}]}
83                    }
84                }
85            }
86        }
87    }
88}
89
90#[derive(Live, LiveHook, Widget)]
91pub struct FoldButton {
92    #[animator] animator: Animator,
93    
94    #[redraw] #[live] draw_bg: DrawQuad,
95    #[live] abs_size: DVec2,
96    #[live] abs_offset: DVec2,
97    #[walk] walk: Walk,
98    #[live] active: f64,
99    #[action_data] #[rust] action_data: WidgetActionData,
100}
101
102#[derive(Clone, Debug, DefaultNone)]
103pub enum FoldButtonAction {
104    None,
105    Opening,
106    Closing,
107    Animating(f64)
108}
109
110impl FoldButton {
111    
112    pub fn set_is_open(&mut self, cx: &mut Cx, is_open: bool, animate: Animate) {
113        self.animator_toggle(cx, is_open, animate, id!(active.on), id!(active.off))
114    }
115    
116    pub fn draw_walk_fold_button(&mut self, cx: &mut Cx2d, walk: Walk) {
117        self.draw_bg.draw_walk(cx, walk);
118    }
119    
120    pub fn area(&mut self)->Area{
121        self.draw_bg.area()
122    }
123    
124    pub fn draw_abs(&mut self, cx: &mut Cx2d, pos: DVec2, fade: f64) {
125        self.draw_bg.apply_over(cx, live!{fade: (fade)});
126        self.draw_bg.draw_abs(cx, Rect {
127            pos: pos + self.abs_offset,
128            size: self.abs_size
129        });
130    }
131    
132    pub fn opening(&self, actions:&Actions) -> bool {
133        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
134            if let FoldButtonAction::Opening = item.cast() {
135                return true
136            }
137        }
138        false
139    }
140    
141    pub fn closing(&self, actions:&Actions) -> bool {
142        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
143            if let FoldButtonAction::Closing = item.cast() {
144                return true
145            }
146        }
147        false
148    }
149        
150    pub fn animating(&self, actions:&Actions) -> Option<f64> {
151        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
152            if let FoldButtonAction::Animating(v) = item.cast() {
153                return Some(v)
154            }
155        }
156        None
157    }
158}
159
160impl Widget for FoldButton {
161
162    fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope:&mut Scope) {
163        let uid = self.widget_uid();
164        let res = self.animator_handle_event(cx, event);
165        if res.is_animating() {
166            if self.animator.is_track_animating(cx, id!(active)) {
167                let mut value = [0.0];
168                self.draw_bg.get_instance(cx, id!(active),&mut value);
169                cx.widget_action(uid, &scope.path, FoldButtonAction::Animating(value[0] as f64))
170            }
171            if res.must_redraw(){
172                self.draw_bg.redraw(cx);
173            }
174        };
175                
176        match event.hits(cx, self.draw_bg.area()) {
177            Hit::FingerDown(_fe) => {
178                if self.animator_in_state(cx, id!(active.on)) {
179                    self.animator_play(cx, id!(active.off));
180                    cx.widget_action(uid, &scope.path, FoldButtonAction::Closing)
181                }
182                else {
183                    self.animator_play(cx, id!(active.on));
184                    cx.widget_action(uid, &scope.path, FoldButtonAction::Opening)
185                }
186                self.animator_play(cx, id!(hover.on));
187            },
188            Hit::FingerHoverIn(_) => {
189                cx.set_cursor(MouseCursor::Hand);
190                self.animator_play(cx, id!(hover.on));
191            }
192            Hit::FingerHoverOut(_) => {
193                self.animator_play(cx, id!(hover.off));
194            }
195            Hit::FingerUp(fe) => if fe.is_over {
196                if fe.device.has_hovers() {
197                    self.animator_play(cx, id!(hover.on));
198                }
199                else{
200                    self.animator_play(cx, id!(hover.off));
201                }
202            }
203            else {
204                self.animator_play(cx, id!(hover.off));
205            }
206            _ => ()
207        };
208    }
209    
210    fn draw_walk(&mut self, cx: &mut Cx2d, _scope:&mut Scope, walk: Walk) -> DrawStep {
211        self.draw_walk_fold_button(cx, walk);
212        DrawStep::done()
213    }
214}
215
216
217impl FoldButtonRef {
218    
219    pub fn opening(&self, actions:&Actions) -> bool {
220        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
221            if let FoldButtonAction::Opening = item.cast() {
222                return true
223            }
224        }
225        false
226    }
227
228    pub fn closing(&self, actions:&Actions) -> bool {
229        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
230            if let FoldButtonAction::Closing = item.cast() {
231                return true
232            }
233        }
234        false
235    }
236    
237    pub fn animating(&self, actions:&Actions) -> Option<f64> {
238        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
239            if let FoldButtonAction::Animating(v) = item.cast() {
240                return Some(v)
241            }
242        }
243        None
244    }
245    
246    pub fn open_float(&self) -> f64 {
247        if let Some(inner) = self.borrow(){
248            inner.active
249        }
250        else{
251            1.0
252        }
253    }
254}
255