makepad_widgets/
desktop_button.rs

1use {
2    crate::{
3        makepad_derive_widget::*,
4        button::ButtonAction,
5        makepad_draw::*,
6        widget::*
7    }
8};
9
10live_design!{
11    link widgets;
12    use link::theme::*;
13    use makepad_draw::shader::std::*;
14    
15    pub DrawDesktopButton = {{DrawDesktopButton}} {}
16    pub DesktopButtonBase = {{DesktopButton}} {}
17    
18    pub DesktopButton = <DesktopButtonBase> {
19        draw_bg: {
20            uniform color: (THEME_COLOR_LABEL_INNER)
21            uniform color_hover: (THEME_COLOR_LABEL_INNER_HOVER)
22            uniform color_down: (THEME_COLOR_LABEL_INNER_DOWN)
23
24            fn pixel(self) -> vec4 {
25                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
26                sdf.aa *= 3.0;
27                let sz = 4.5;
28                let c = self.rect_size * vec2(0.5, 0.5);
29                
30                // WindowsMin
31                match self.button_type {
32                    DesktopButtonType::WindowsMin => {
33                        sdf.move_to(c.x - sz, c.y);
34                        sdf.line_to(c.x + sz, c.y);
35                        sdf.stroke(
36                            mix(
37                                self.color,
38                                mix(
39                                    self.color_hover,
40                                    self.color_down,
41                                    self.down
42                                ), 
43                                self.hover
44                            ),
45                            0.5 + 0.5 * self.dpi_dilate
46                        );
47                        return sdf.result;
48                    }
49                    DesktopButtonType::WindowsMax => {
50                        sdf.rect(c.x - sz, c.y - sz, 2. * sz, 2. * sz);
51                        sdf.stroke(
52                            mix(
53                                self.color,
54                                mix(
55                                    self.color_hover,
56                                    self.color_down,
57                                    self.down
58                                ), 
59                                self.hover
60                            ),
61                            0.5 + 0.5 * self.dpi_dilate
62                        );
63                        return sdf.result;
64                    }
65                    DesktopButtonType::WindowsMaxToggled => {
66                        let sz = 5.;
67                        sdf.rect(c.x - sz + 1., c.y - sz - 1., 2. * sz, 2. * sz);
68                        sdf.stroke(#f, 0.5 + 0.5 * self.dpi_dilate);
69                        sdf.rect(c.x - sz - 1., c.y - sz + 1., 2. * sz, 2. * sz);
70                        sdf.stroke(
71                            mix(
72                                self.color,
73                                mix(
74                                    self.color_hover,
75                                    self.color_down,
76                                    self.down
77                                ), 
78                                self.hover
79                            ),
80                            0.5 + 0.5 * self.dpi_dilate
81                        );
82                        return sdf.result;
83                    }
84                    DesktopButtonType::WindowsClose => {
85                        sdf.move_to(c.x - sz, c.y - sz);
86                        sdf.line_to(c.x + sz, c.y + sz);
87                        sdf.move_to(c.x - sz, c.y + sz);
88                        sdf.line_to(c.x + sz, c.y - sz);
89                        sdf.stroke(
90                            mix(
91                                self.color,
92                                mix(
93                                    self.color_hover,
94                                    self.color_down,
95                                    self.down
96                                ), 
97                                self.hover
98                            ),
99                            0.5 + 0.5 * self.dpi_dilate
100                        );
101                        return sdf.result;
102                    }
103                    DesktopButtonType::XRMode => {
104                        let w = 12.;
105                        let h = 8.;
106                        sdf.box(c.x - w, c.y - h, 2. * w, 2. * h, 2.);
107                        // subtract 2 eyes
108                        sdf.circle(c.x - 5.5, c.y, 3.5);
109                        sdf.subtract();
110                        sdf.circle(c.x + 5.5, c.y, 3.5);
111                        sdf.subtract();
112                        sdf.circle(c.x, c.y + h - 0.75, 2.5);
113                        sdf.subtract();
114                        sdf.fill(
115                            mix(
116                                self.color,
117                                mix(
118                                    self.color_hover,
119                                    self.color_down,
120                                    self.down
121                                ), 
122                                self.hover
123                            )
124
125                        ); //, 0.5 + 0.5 * dpi_dilate);
126                        
127                        return sdf.result;
128                    }
129                    DesktopButtonType::Fullscreen => {
130                        sz = 8.;
131                        sdf.rect(c.x - sz, c.y - sz, 2. * sz, 2. * sz);
132                        sdf.rect(c.x - sz + 1.5, c.y - sz + 1.5, 2. * (sz - 1.5), 2. * (sz - 1.5));
133                        sdf.subtract();
134                        sdf.rect(c.x - sz + 4., c.y - sz - 2., 2. * (sz - 4.), 2. * (sz + 2.));
135                        sdf.subtract();
136                        sdf.rect(c.x - sz - 2., c.y - sz + 4., 2. * (sz + 2.), 2. * (sz - 4.));
137                        sdf.subtract();
138                        sdf.fill(
139                            mix(
140                                self.color,
141                                mix(
142                                    self.color_hover,
143                                    self.color_down,
144                                    self.down
145                                ), 
146                                self.hover
147                            )
148
149                        ); //, 0.5 + 0.5 * dpi_dilate);
150                        
151                        return sdf.result;
152                    }
153                }
154                return #f00;
155            }
156        }
157        animator: {
158            hover = {
159                default: off,
160                off = {
161                    from: {all: Forward {duration: 0.1}}
162                    apply: {
163                        draw_bg: {down: 0.0, hover: 0.0}
164                    }
165                }
166                
167                on = {
168                    from: {
169                        all: Forward {duration: 0.1}
170                        state_down: Snap
171                    }
172                    apply: {
173                        draw_bg: {
174                            down: 0.0,
175                            hover: 1.0,
176                        }
177                    }
178                }
179                
180                down = {
181                    from: {all: Snap}
182                    apply: {
183                        draw_bg: {
184                            down: 1.0,
185                            hover: 1.0,
186                        }
187                    }
188                }
189            }
190        }
191    }
192    
193} 
194
195#[derive(Live, Widget)]
196pub struct DesktopButton {
197    #[animator] animator: Animator,
198    #[walk] walk: Walk,
199    #[redraw] #[live] draw_bg: DrawDesktopButton,
200
201}
202
203impl Widget for DesktopButton{
204    fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
205        let uid = self.widget_uid();
206        self.animator_handle_event(cx, event);
207        
208        match event.hits(cx, self.draw_bg.area()) {
209            Hit::FingerDown(fe) => {
210                cx.widget_action(uid, &scope.path, ButtonAction::Pressed(fe.modifiers));
211                self.animator_play(cx, id!(hover.down));
212            },
213            Hit::FingerHoverIn(_) => {
214                cx.set_cursor(MouseCursor::Hand);
215                self.animator_play(cx, id!(hover.on));
216            }
217            Hit::FingerHoverOut(_) => {
218                self.animator_play(cx, id!(hover.off));
219            }
220            Hit::FingerLongPress(_) => {
221                cx.widget_action(uid, &scope.path, ButtonAction::LongPressed);
222            }
223            Hit::FingerUp(fe) => if fe.is_over {
224                cx.widget_action(uid, &scope.path, ButtonAction::Clicked(fe.modifiers));
225                if fe.device.has_hovers() {
226                    self.animator_play(cx, id!(hover.on));
227                }
228                else{
229                    self.animator_play(cx, id!(hover.off));
230                }
231            }
232            else {
233                cx.widget_action(uid, &scope.path, ButtonAction::Released(fe.modifiers));
234                self.animator_play(cx, id!(hover.off));
235            }
236            _ => ()
237        };
238    }
239    
240    fn draw_walk(&mut self, cx: &mut Cx2d, _scope:&mut Scope, walk: Walk) -> DrawStep {
241        let _ = self.draw_bg.draw_walk(cx, walk);
242        DrawStep::done()
243    }
244}
245
246#[derive(Live, LiveHook)]
247#[live_ignore]
248#[repr(u32)]
249pub enum DesktopButtonType {
250    WindowsMin = shader_enum(1),
251    WindowsMax = shader_enum(2),
252    WindowsMaxToggled = shader_enum(3),
253    WindowsClose = shader_enum(4),
254    XRMode = shader_enum(5),
255    #[pick] Fullscreen = shader_enum(6),
256}
257
258#[derive(Live, LiveHook, LiveRegister)]
259#[repr(C)]
260pub struct DrawDesktopButton {
261    #[deref] draw_super: DrawQuad,
262    #[live] hover: f32,
263    #[live] down: f32,
264    #[live] button_type: DesktopButtonType
265}
266
267impl LiveHook for DesktopButton {
268    fn after_apply_from_doc(&mut self, _cx: &mut Cx) {
269        let (w, h) = match self.draw_bg.button_type {
270            DesktopButtonType::WindowsMin
271                | DesktopButtonType::WindowsMax
272                | DesktopButtonType::WindowsMaxToggled
273                | DesktopButtonType::WindowsClose => (46., 29.),
274            DesktopButtonType::XRMode => (50., 36.),
275            DesktopButtonType::Fullscreen => (50., 36.),
276        };
277        self.walk = Walk::fixed_size(dvec2(w, h))
278    }
279}
280
281impl DesktopButtonRef{
282    pub fn clicked(&self, actions: &Actions) -> bool {
283        if let ButtonAction::Clicked(_) = actions.find_widget_action(self.widget_uid()).cast() {
284            true
285        } else {
286            false
287        }
288    }
289}