makepad_widgets/
link_label.rs

1use crate::{
2    makepad_derive_widget::*,
3    widget::*,
4    makepad_draw::*,
5    button::Button,
6};
7
8live_design!{
9    link widgets;
10    
11    use link::theme::*;
12    use makepad_draw::shader::std::*;
13    use crate::button::ButtonBase
14    
15    pub LinkLabelBase = {{LinkLabel}}<ButtonBase> {}
16    pub LinkLabel = <LinkLabelBase> {
17        width: Fit, height: Fit,
18        margin: <THEME_MSPACE_V_2> {}
19        padding: 0.,
20        
21        label_walk: { width: Fit, height: Fit },
22
23        draw_icon: {
24            instance hover: 0.0
25            instance down: 0.0
26            instance focus: 0.0
27            instance disabled: 0.0
28
29            uniform color: (THEME_COLOR_LABEL_INNER)
30            uniform color_hover: (THEME_COLOR_LABEL_INNER_HOVER)
31            uniform color_down: (THEME_COLOR_LABEL_INNER_DOWN)
32            uniform color_focus: (THEME_COLOR_LABEL_INNER_FOCUS)
33            uniform color_disabled: (THEME_COLOR_LABEL_INNER_DISABLED)
34
35            fn get_color(self) -> vec4 {
36                return mix(
37                    mix(
38                        mix(
39                            mix(self.color, self.color_focus, self.focus),
40                            self.color_hover,
41                            self.hover
42                        ),
43                        self.color_down,
44                        self.down
45                    ),
46                    self.color_disabled,
47                    self.disabled
48                )
49            }
50        }
51        
52        draw_bg: {
53            instance down: 0.0
54            instance hover: 0.0
55            instance focus: 0.0
56            instance disabled: 0.0
57
58            uniform color: (THEME_COLOR_LABEL_INNER)
59            uniform color_hover: (THEME_COLOR_LABEL_INNER_HOVER)
60            uniform color_down: (THEME_COLOR_LABEL_INNER_DOWN)
61            uniform color_focus: (THEME_COLOR_LABEL_INNER_FOCUS)
62            uniform color_disabled: (THEME_COLOR_LABEL_INNER_DISABLED)
63            
64            fn pixel(self) -> vec4 {
65                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
66                let offset_y = 1.0
67                sdf.move_to(0., self.rect_size.y - offset_y);
68                sdf.line_to(self.rect_size.x, self.rect_size.y - offset_y);
69                return sdf.stroke(
70                    mix(
71                        mix(
72                            mix(
73                                mix(self.color, self.color_focus, self.focus),
74                                self.color_hover,
75                                self.hover
76                            ),
77                            self.color_down,
78                            self.down
79                        ),
80                        self.color_disabled,
81                        self.disabled
82                    ), mix(.7, 1., self.hover)
83                );
84            }
85        }
86        
87        draw_text: {
88            instance down: 0.0
89            instance hover: 0.0
90            instance focus: 0.0,
91            instance disabled: 0.0
92
93            uniform color: (THEME_COLOR_LABEL_INNER),
94            uniform color_hover: (THEME_COLOR_LABEL_INNER_HOVER),
95            uniform color_down: (THEME_COLOR_LABEL_INNER_DOWN),
96            uniform color_focus: (THEME_COLOR_LABEL_INNER_FOCUS)
97            uniform color_disabled: (THEME_COLOR_LABEL_INNER_DISABLED)
98
99            wrap: Word
100            text_style: <THEME_FONT_REGULAR>{
101                font_size: (THEME_FONT_SIZE_P)
102            }
103            fn get_color(self) -> vec4 {
104                return
105                mix(
106                    mix(
107                        mix(
108                            mix(self.color, self.color_focus, self.focus),
109                            self.color_hover,
110                            self.hover
111                        ),
112                        self.color_down,
113                        self.down
114                    ),
115                    self.color_disabled,
116                    self.disabled
117                )
118            }
119        }
120        
121        animator: {
122            disabled = {
123                default: off,
124                off = {
125                    from: {all: Forward {duration: 0.}}
126                    apply: {
127                        draw_bg: {disabled: 0.0}
128                        draw_text: {disabled: 0.0}
129                        draw_icon: {disabled: 0.0}
130                    }
131                }
132                on = {
133                    from: {all: Forward {duration: 0.2}}
134                    apply: {
135                        draw_bg: {disabled: 1.0}
136                        draw_text: {disabled: 1.0}
137                        draw_icon: {disabled: 1.0}
138                    }
139                }
140            }
141            time = {
142                default: off,
143                off = {
144                    from: {all: Forward {duration: 0.}}
145                    apply: {
146                        //draw_bg: {anim_time: 0.0}
147                    }
148                }
149                on = {
150                    from: {all: Loop {duration: 1.0, end:1000000000.0}}
151                    apply: {
152                        draw_bg: {anim_time: [{time: 0.0, value: 0.0},{time:1.0, value:1.0}]}
153                    }
154                }
155            }
156            hover = {
157                default: off,
158                off = {
159                    from: {all: Forward {duration: 0.1}}
160                    apply: {
161                        draw_bg: {down: 0.0, hover: 0.0}
162                        draw_icon: {down: 0.0, hover: 0.0}
163                        draw_text: {down: 0.0, hover: 0.0}
164                    }
165                }
166                
167                on = {
168                    from: {
169                        all: Forward {duration: 0.1}
170                        down: Forward {duration: 0.01}
171                    }
172                    apply: {
173                        draw_bg: {down: 0.0, hover: [{time: 0.0, value: 1.0}],}
174                        draw_icon: {down: 0.0, hover: [{time: 0.0, value: 1.0}],}
175                        draw_text: {down: 0.0, hover: [{time: 0.0, value: 1.0}],}
176                    }
177                }
178                
179                down = {
180                    from: {all: Forward {duration: 0.2}}
181                    apply: {
182                        draw_bg: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
183                        draw_icon: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
184                        draw_text: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
185                    }
186                }
187            }
188            focus = {
189                default: off
190                off = {
191                    from: {all: Forward {duration: 0.2}}
192                    apply: {
193                        draw_bg: {focus: 0.0}
194                        draw_icon: {focus: 0.0}
195                        draw_text: {focus: 0.0}
196                    }
197                }
198                on = {
199                    cursor: Arrow,
200                    from: {all: Forward {duration: 0.0}}
201                    apply: {
202                        draw_bg: {focus: 1.0}
203                        draw_icon: {focus: 1.0}
204                        draw_text: {focus: 1.0}
205                    }
206                }
207            }
208        }
209        
210    }
211
212    pub LinkLabelGradientY = <LinkLabel> {
213        draw_bg: {
214            instance down: 0.0
215            instance hover: 0.0
216            instance focus: 0.0
217            instance disabled: 0.0
218
219            uniform color_1: #0ff,
220            uniform color_1_hover: #0ff,
221            uniform color_1_down: #0ff,
222            uniform color_1_focus: #0ff,
223            uniform color_1_disabled: (THEME_COLOR_TEXT_DISABLED)
224
225            uniform color_2: #A00
226            uniform color_2_hover: #F00
227            uniform color_2_down: #000
228            uniform color_2_focus: #f00
229            uniform color_2_disabled: (THEME_COLOR_TEXT_DISABLED)
230            
231            fn pixel(self) -> vec4 {
232                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
233                let offset_y = 1.0
234                sdf.move_to(0., self.rect_size.y - offset_y);
235                sdf.line_to(self.rect_size.x, self.rect_size.y - offset_y);
236                return sdf.stroke(
237                    mix(
238                        mix(
239                            mix(
240                                mix(
241                                    mix(self.color_1, self.color_2, self.pos.y),
242                                    mix(self.color_1_focus, self.color_2_focus, self.pos.y),
243                                    self.focus
244                                ),
245                                mix(self.color_1_hover, self.color_2_hover, self.pos.y),
246                                self.hover
247                            ),
248                            mix(self.color_1_down, self.color_2_down, self.pos.y),
249                            self.down
250                        ),
251                        mix(self.color_1_disabled, self.color_2_disabled, self.pos.y),
252                        self.disabled
253                    ), mix(.7, 1., self.hover));
254            }
255        }
256        
257        draw_text: {
258            instance down: 0.0
259            instance hover: 0.0
260            instance focus: 0.0
261            instance disabled: 0.0
262
263            uniform color_1: #0ff,
264            uniform color_1_hover: #0ff,
265            uniform color_1_down: #0ff,
266            uniform color_1_focus: #f00,
267            uniform color_1_disabled: (THEME_COLOR_TEXT_DISABLED)
268
269            uniform color_2: #A40
270            uniform color_2_hover: #FA0
271            uniform color_2_down: #0A0
272            uniform color_2_focus: #0F0
273            uniform color_2_disabled: (THEME_COLOR_TEXT_DISABLED)
274
275            wrap: Word
276            text_style: <THEME_FONT_REGULAR>{
277                font_size: (THEME_FONT_SIZE_P)
278            }
279            fn get_color(self) -> vec4 {
280                return
281                    mix(
282                        mix(
283                            mix(
284                                mix(
285                                    mix(self.color_1, self.color_2, self.pos.y),
286                                    mix(self.color_1_focus, self.color_2_focus, self.pos.y),
287                                    self.focus
288                                ),
289                                mix(self.color_1_hover, self.color_2_hover, self.pos.y),
290                                self.hover
291                            ),
292                            mix(self.color_1_down, self.color_2_down, self.pos.y),
293                            self.down
294                        ),
295                        mix(self.color_1_disabled, self.color_2_disabled, self.pos.y),
296                        self.disabled
297                    );
298            }
299        }
300    }
301    
302    pub LinkLabelGradientX = <LinkLabelGradientY> {
303        draw_text: {
304            fn get_color(self) -> vec4 {
305                return
306                mix(
307                    mix(
308                        mix(
309                            mix(
310                                mix(self.color_1, self.color_2, self.pos.x),
311                                mix(self.color_1_focus, self.color_2_focus, self.pos.x),
312                                self.focus
313                            ),
314                            mix(self.color_1_hover, self.color_2_hover, self.pos.x),
315                            self.hover
316                        ),
317                        mix(self.color_1_down, self.color_2_down, self.pos.x),
318                        self.down
319                    ),
320                    mix(self.color_1_disabled, self.color_2_disabled, self.pos.x),
321                    self.disabled
322                );
323            }
324        }
325    }
326
327
328    pub LinkLabelIcon = <LinkLabel> {
329        padding: { bottom: 2. }
330        align: {x: 0.0, y: 0.0 }
331        label_walk: { margin: { left: (THEME_SPACE_2) } }
332    }
333
334}
335
336/// A clickable label widget that opens a URL when clicked.
337///
338/// This is a wrapper around (and derefs to) a [`Button`] widget.
339#[derive(Live, LiveHook, Widget)]
340pub struct LinkLabel {
341    #[deref] button: Button,
342    #[live] pub url: String,
343    #[live] pub open_in_place: bool,
344}
345
346impl Widget for LinkLabel {
347    fn handle_event(
348        &mut self,
349        cx: &mut Cx,
350        event: &Event,
351        scope: &mut Scope,
352    ) {
353        let actions = cx.capture_actions(|cx|{
354            self.button.handle_event(cx, event, scope);
355        });
356        if self.url.len()>0 && self.clicked(&actions){
357            cx.open_url(&self.url, if self.open_in_place{OpenUrlInPlace::Yes}else{OpenUrlInPlace::No});
358        }
359        cx.extend_actions(actions);
360    }
361    
362    fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
363        self.button.draw_walk(cx, scope, walk)
364    }
365    
366    fn text(&self)->String{
367        self.button.text()
368    }
369    
370    fn set_text(&mut self, cx:&mut Cx, v:&str){
371        self.button.set_text(cx, v);
372    }
373}
374
375impl LinkLabelRef {
376    /// See [`Button::clicked()`].
377    pub fn clicked(&self, actions: &Actions) -> bool {
378        self.borrow().map_or(false, |b| b.clicked(actions))
379    }
380
381    /// See [`Button::pressed()`].
382    pub fn pressed(&self, actions: &Actions) -> bool {
383        self.borrow().map_or(false, |b| b.pressed(actions))
384    }
385
386    /// See [`Button::released()`].
387    pub fn released(&self, actions: &Actions) -> bool {
388        self.borrow().map_or(false, |b| b.released(actions))
389    }
390
391    /// See [`Button::clicked_modifiers()`].
392    pub fn clicked_modifiers(&self, actions: &Actions) -> Option<KeyModifiers> {
393        self.borrow().and_then(|b| b.clicked_modifiers(actions))
394    }
395
396    /// See [`Button::pressed_modifiers()`].
397    pub fn pressed_modifiers(&self, actions: &Actions) -> Option<KeyModifiers> {
398        self.borrow().and_then(|b| b.pressed_modifiers(actions))
399    }
400
401    /// See [`Button::released_modifiers()`].
402    pub fn released_modifiers(&self, actions: &Actions) -> Option<KeyModifiers> {
403        self.borrow().and_then(|b| b.released_modifiers(actions))
404    }
405}