makepad_widgets/
popup_menu.rs

1use {
2    crate::{
3        makepad_draw::*,
4    },
5};
6
7live_design!{
8    link widgets;
9    use link::theme::*;
10    use makepad_draw::shader::std::*;
11    
12    pub PopupMenuItemBase = {{PopupMenuItem}} {}
13    pub PopupMenuBase = {{PopupMenu}} {}
14        
15    pub PopupMenuItem = <PopupMenuItemBase> {
16        width: Fill, height: Fit,
17        align: { y: 0.5 }
18        padding: <THEME_MSPACE_1> { left: 15. }
19        
20        draw_text: {
21            instance active: 0.0
22            instance hover: 0.0
23            instance disabled: 0.0
24
25            uniform color: (THEME_COLOR_LABEL_INNER)
26            uniform color_hover: (THEME_COLOR_LABEL_INNER_HOVER)
27            uniform color_active: (THEME_COLOR_LABEL_INNER_ACTIVE)
28            uniform color_disabled: (THEME_COLOR_LABEL_INNER_DISABLED)
29
30            text_style: <THEME_FONT_REGULAR> {
31                font_size: (THEME_FONT_SIZE_P),
32            }
33
34            fn get_color(self) -> vec4 {
35                return mix(
36                    mix(
37                        mix(
38                            self.color,
39                            self.color_active,
40                            self.active
41                        ),
42                        self.color_hover,
43                        self.hover
44                    ),
45                    self.color_disabled,
46                    self.disabled
47                )
48            }
49        }
50        
51        draw_bg: {
52            instance active: 0.0
53            instance hover: 0.0
54            instance disabled: 0.0
55
56            uniform border_size: (THEME_BEVELING)
57            uniform border_radius: (THEME_CORNER_RADIUS)
58
59            uniform color_dither: 1.0
60
61            uniform color: (THEME_COLOR_U_HIDDEN)
62            uniform color_hover: (THEME_COLOR_OUTSET_HOVER)
63            uniform color_active: (THEME_COLOR_OUTSET_ACTIVE)
64            uniform color_disabled: (THEME_COLOR_OUTSET_ACTIVE)
65
66            uniform border_color_1: (THEME_COLOR_U_HIDDEN)
67            uniform border_color_1_hover: (THEME_COLOR_U_HIDDEN)
68            uniform border_color_1_active: (THEME_COLOR_U_HIDDEN)
69            uniform border_color_1_disabled: (THEME_COLOR_U_HIDDEN)
70
71            uniform border_color_2: (THEME_COLOR_U_HIDDEN)
72            uniform border_color_2_hover: (THEME_COLOR_U_HIDDEN)
73            uniform border_color_2_active: (THEME_COLOR_U_HIDDEN)
74            uniform border_color_2_disabled: (THEME_COLOR_U_HIDDEN)
75
76            uniform mark_color: (THEME_COLOR_U_HIDDEN)
77            uniform mark_color_active: (THEME_COLOR_MARK_ACTIVE)
78            uniform mark_color_disabled: (THEME_COLOR_MARK_DISABLED)
79            
80            fn pixel(self) -> vec4 {
81                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
82                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
83
84                let border_sz_uv = vec2(
85                    self.border_size / self.rect_size.x,
86                    self.border_size / self.rect_size.y
87                )
88
89                let gradient_border = vec2(
90                    self.pos.x + dither,
91                    self.pos.y + dither
92                )
93
94                let sz_inner_px = vec2(
95                    self.rect_size.x - self.border_size * 2.,
96                    self.rect_size.y - self.border_size * 2.
97                );
98
99                let scale_factor_fill = vec2(
100                    self.rect_size.x / sz_inner_px.x,
101                    self.rect_size.y / sz_inner_px.y
102                );
103
104                let gradient_fill = vec2(
105                    self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
106                    self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
107                )
108                
109                // Background
110                sdf.box(
111                    self.border_size,
112                    self.border_size,
113                    self.rect_size.x - self.border_size * 2.,
114                    self.rect_size.y - self.border_size * 2.,
115                    self.border_radius
116                );
117
118                sdf.fill_keep(
119                    mix(
120                        mix(
121                            mix(
122                                self.color,
123                                self.color_active,
124                                self.active
125                            ),
126                            self.color_hover,
127                            self.hover
128                        ),
129                        self.color_disabled,
130                        self.disabled
131                    )
132                );
133
134                sdf.stroke(
135                    mix(
136                        mix(
137                            mix(
138                                mix(self.border_color_1, self.border_color_2, gradient_border.y),
139                                mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
140                                self.hover
141                            ),
142                            mix(self.border_color_1_active, self.border_color_2_active, gradient_border.y),
143                            self.active
144                        ),
145                        mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
146                        self.disabled
147                    ), self.border_size
148                );
149
150                // Mark
151                let sz = 3.;
152                let dx = 2.0;
153                let c = vec2(8.0, 0.5 * self.rect_size.y);
154                sdf.move_to(c.x - sz + dx * 0.5, c.y - sz + dx);
155                sdf.line_to(c.x, c.y + sz);
156                sdf.line_to(c.x + sz, c.y - sz);
157
158                sdf.stroke(
159                    mix(
160                        mix(
161                            self.mark_color,
162                            self.mark_color_active,
163                            self.active
164                        ),
165                        self.mark_color_disabled,
166                        self.disabled
167                    ), 1.
168                );
169                
170                return sdf.result;
171            }
172        }
173        
174        animator: {
175            disabled = {
176                default: off,
177                off = {
178                    from: {all: Forward {duration: 0.}}
179                    apply: {
180                        draw_bg: {disabled: 0.0}
181                        draw_text: {disabled: 0.0}
182                    }
183                }
184                on = {
185                    from: {all: Forward {duration: 0.2}}
186                    apply: {
187                        draw_bg: {disabled: 1.0}
188                        draw_text: {disabled: 1.0}
189                    }
190                }
191            }
192            hover = {
193                default: off
194                off = {
195                    from: {all: Snap}
196                    apply: {
197                        draw_bg: {hover: 0.0}
198                        draw_text: {hover: 0.0}
199                    }
200                }
201                on = {
202                    cursor: Hand
203                    from: {all: Snap}
204                    apply: {
205                        draw_bg: {hover: 1.0}
206                        draw_text: {hover: 1.0}
207                    }
208                }
209            }
210            
211            active = {
212                default: off
213                off = {
214                    from: {all: Snap}
215                    apply: {
216                        draw_bg: {active: 0.0,}
217                        draw_text: {active: 0.0,}
218                    }
219                }
220                on = {
221                    from: {all: Snap}
222                    apply: {
223                        draw_bg: {active: 1.0,}
224                        draw_text: {active: 1.0,}
225                    }
226                }
227            }
228        }
229        indent_width: 10.0
230    }
231
232    PopupMenuItemGradientX = <PopupMenuItem> {
233        draw_bg: {
234            uniform color_1: (THEME_COLOR_U_HIDDEN)
235            uniform color_1_hover: (THEME_COLOR_OUTSET_1_HOVER)
236            uniform color_1_active: (THEME_COLOR_OUTSET_1_ACTIVE)
237            uniform color_1_disabled: (THEME_COLOR_OUTSET_1_DISABLED)
238
239            uniform color_2: (THEME_COLOR_U_HIDDEN)
240            uniform color_2_hover: (THEME_COLOR_OUTSET_2_HOVER)
241            uniform color_2_active: (THEME_COLOR_OUTSET_2_ACTIVE)
242            uniform color_2_disabled: (THEME_COLOR_OUTSET_2_DISABLED)
243
244            uniform border_color_1: (THEME_COLOR_U_HIDDEN)
245            uniform border_color_1_hover: (THEME_COLOR_U_HIDDEN)
246            uniform border_color_1_active: (THEME_COLOR_U_HIDDEN)
247            uniform border_color_1_disabled: (THEME_COLOR_U_HIDDEN)
248
249            uniform border_color_2: (THEME_COLOR_U_HIDDEN)
250            uniform border_color_2_hover: (THEME_COLOR_U_HIDDEN)
251            uniform border_color_2_active: (THEME_COLOR_U_HIDDEN)
252            uniform border_color_2_disabled: (THEME_COLOR_U_HIDDEN)
253
254            uniform mark_color: (THEME_COLOR_U_HIDDEN)
255            uniform mark_color_active: (THEME_COLOR_MARK_ACTIVE)
256            uniform mark_color_disabled: (THEME_COLOR_MARK_DISABLED)
257            
258            fn pixel(self) -> vec4 {
259                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
260                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
261                
262                let border_sz_uv = vec2(
263                    self.border_size / self.rect_size.x,
264                    self.border_size / self.rect_size.y
265                )
266
267                let gradient_border = vec2(
268                    self.pos.x + dither,
269                    self.pos.y + dither
270                )
271
272                let sz_inner_px = vec2(
273                    self.rect_size.x - self.border_size * 2.,
274                    self.rect_size.y - self.border_size * 2.
275                );
276
277                let scale_factor_fill = vec2(
278                    self.rect_size.x / sz_inner_px.x,
279                    self.rect_size.y / sz_inner_px.y
280                );
281
282                let gradient_fill = vec2(
283                    self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
284                    self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
285                )
286
287                // Background
288                sdf.box(
289                    self.border_size,
290                    self.border_size,
291                    self.rect_size.x - self.border_size * 2.,
292                    self.rect_size.y - self.border_size * 2.,
293                    self.border_radius
294                );
295
296                sdf.fill_keep(
297                    mix(
298                        mix(
299                            mix(
300                                mix(self.color_1, self.color_2, self.pos.x),
301                                mix(self.color_1_active, self.color_2_active, self.pos.x),
302                                self.active
303                            ),
304                            mix(self.color_1_hover, self.color_2_hover, self.pos.x),
305                            self.hover
306                        ),
307                        mix(self.color_1_disabled, self.color_2_disabled, self.pos.x),
308                        self.disabled
309                    )
310                );
311
312                sdf.stroke(
313                    mix(
314                        mix(
315                            mix(
316                                mix(self.border_color_1, self.border_color_2, self.pos.y + dither),
317                                mix(self.border_color_1_hover, self.border_color_2_hover, self.pos.y + dither),
318                                self.hover
319                            ),
320                            mix(self.border_color_1_active, self.border_color_2_active, self.pos.y + dither),
321                            self.active
322                        ),
323                        mix(self.border_color_1_disabled, self.border_color_2_disabled, self.pos.y + dither),
324                        self.disabled
325                    ), self.border_size
326                );
327
328                // Mark
329                let sz = 3.;
330                let dx = 2.0;
331                let c = vec2(8.0, 0.5 * self.rect_size.y);
332                sdf.move_to(c.x - sz + dx * 0.5, c.y - sz + dx);
333                sdf.line_to(c.x, c.y + sz);
334                sdf.line_to(c.x + sz, c.y - sz);
335
336                sdf.stroke(
337                    mix(
338                        mix(
339                            self.mark_color,
340                            self.mark_color_active,
341                            self.active
342                        ),
343                        self.mark_color_disabled,
344                        self.disabled
345                    ), 1.);
346                
347                return sdf.result;
348            }
349        }
350    }
351
352    PopupMenuItemGradientY = <PopupMenuItemGradientX> {
353        draw_bg: {
354            fn pixel(self) -> vec4 {
355                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
356                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
357                
358                let border_sz_uv = vec2(
359                    self.border_size / self.rect_size.x,
360                    self.border_size / self.rect_size.y
361                )
362
363                let gradient_border = vec2(
364                    self.pos.x + dither,
365                    self.pos.y + dither
366                )
367
368                let sz_inner_px = vec2(
369                    self.rect_size.x - self.border_size * 2.,
370                    self.rect_size.y - self.border_size * 2.
371                );
372
373                let scale_factor_fill = vec2(
374                    self.rect_size.x / sz_inner_px.x,
375                    self.rect_size.y / sz_inner_px.y
376                );
377
378                let gradient_fill = vec2(
379                    self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
380                    self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
381                )
382
383                // Background
384                sdf.box(
385                    self.border_size,
386                    self.border_size,
387                    self.rect_size.x - self.border_size * 2.,
388                    self.rect_size.y - self.border_size * 2.,
389                    self.border_radius
390                );
391
392                sdf.fill_keep(
393                    mix(
394                        mix(
395                            mix(
396                                mix(self.color_1, self.color_2, gradient_fill.y),
397                                mix(self.color_1_active, self.color_2_active, gradient_fill.y),
398                                self.active
399                            ),
400                            mix(self.color_1_hover, self.color_2_hover, gradient_fill.y),
401                            self.hover
402                        ),
403                        mix(self.color_1_disabled, self.color_2_disabled, gradient_fill.y),
404                        self.disabled
405                    )
406                );
407
408                sdf.stroke(
409                    mix(
410                        mix(
411                            mix(
412                                mix(self.border_color_1, self.border_color_2, gradient_border.y),
413                                mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
414                                self.hover
415                            ),
416                            mix(self.border_color_1_active, self.border_color_2_active, gradient_border.y),
417                            self.active
418                        ),
419                        mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
420                        self.disabled
421                    ), self.border_size
422                );
423
424                // Mark
425                let sz = 3.;
426                let dx = 2.0;
427                let c = vec2(8.0, 0.5 * self.rect_size.y);
428                sdf.move_to(c.x - sz + dx * 0.5, c.y - sz + dx);
429                sdf.line_to(c.x, c.y + sz);
430                sdf.line_to(c.x + sz, c.y - sz);
431
432                sdf.stroke(
433                    mix(
434                        mix( self.mark_color, self.mark_color_active, self.active),
435                        self.mark_color_disabled,
436                        self.disabled
437                    ), 1.
438                );
439                
440                return sdf.result;
441            }
442        }
443    }
444
445    pub PopupMenu = <PopupMenuBase> {
446        width: 150., height: Fit,
447        flow: Down,
448        padding: <THEME_MSPACE_1> {}
449        
450        menu_item: <PopupMenuItem> {}
451        
452        draw_bg: {
453            uniform color_dither: 1.0
454            uniform color: (THEME_COLOR_FG_APP)
455
456            uniform border_radius: (THEME_CORNER_RADIUS)
457            uniform border_size: (THEME_BEVELING)
458            uniform border_color_1: (THEME_COLOR_BEVEL_OUTSET_1)
459            uniform border_color_2: (THEME_COLOR_BEVEL_OUTSET_2)
460            
461            fn pixel(self) -> vec4 {
462                let sdf = Sdf2d::viewport(self.pos * self.rect_size)
463                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
464
465                let border_sz_uv = vec2(
466                    self.border_size / self.rect_size.x,
467                    self.border_size / self.rect_size.y
468                )
469
470                let gradient_border = vec2(
471                    self.pos.x + dither,
472                    self.pos.y + dither
473                )
474
475                let sz_inner_px = vec2(
476                    self.rect_size.x - self.border_size * 2.,
477                    self.rect_size.y - self.border_size * 2.
478                );
479
480                let scale_factor_fill = vec2(
481                    self.rect_size.x / sz_inner_px.x,
482                    self.rect_size.y / sz_inner_px.y
483                );
484
485                let gradient_fill = vec2(
486                    self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
487                    self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
488                )
489
490                sdf.box(
491                    self.border_size,
492                    self.border_size,
493                    self.rect_size.x - self.border_size * 2.,
494                    self.rect_size.y - self.border_size * 2.,
495                    self.border_radius
496                )
497
498                sdf.fill_keep(self.color);
499
500                if self.border_size > 0.0 {
501                    sdf.stroke(
502                        mix(
503                            self.border_color_1,
504                            self.border_color_2,
505                            gradient_border.y
506                        ), self.border_size
507                    );
508                }
509
510                return sdf.result;
511            }
512        }
513    }
514    pub PopupMenuFlat = <PopupMenu> {
515        menu_item: <PopupMenuItem> {}
516
517        draw_bg: {
518            uniform border_color_1: (THEME_COLOR_BEVEL)
519            uniform border_color_2: (THEME_COLOR_BEVEL)
520        }
521    }
522
523    pub PopupMenuFlatter = <PopupMenuFlat> {
524        draw_bg: { border_size: 0. }
525    }
526    
527    pub PopupMenuGradientY = <PopupMenu> {
528        menu_item: <PopupMenuItemGradientY> {}
529        
530        draw_bg: {
531            uniform color_1: (THEME_COLOR_FG_APP)
532            uniform color_2: (THEME_COLOR_FG_APP * 1.2)
533
534            fn pixel(self) -> vec4 {
535                let sdf = Sdf2d::viewport(self.pos * self.rect_size)
536                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
537
538                let border_sz_uv = vec2(
539                    self.border_size / self.rect_size.x,
540                    self.border_size / self.rect_size.y
541                )
542
543                let gradient_border = vec2(
544                    self.pos.x + dither,
545                    self.pos.y + dither
546                )
547
548                let sz_inner_px = vec2(
549                    self.rect_size.x - self.border_size * 2.,
550                    self.rect_size.y - self.border_size * 2.
551                );
552
553                let scale_factor_fill = vec2(
554                    self.rect_size.x / sz_inner_px.x,
555                    self.rect_size.y / sz_inner_px.y
556                );
557
558                let gradient_fill = vec2(
559                    self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
560                    self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
561                )
562
563                sdf.box(
564                    self.border_size,
565                    self.border_size,
566                    self.rect_size.x - self.border_size * 2.,
567                    self.rect_size.y - self.border_size * 2.,
568                    self.border_radius
569                )
570
571                sdf.fill_keep(mix(self.color_1, self.color_2, gradient_fill.y));
572
573                if self.border_size > 0.0 {
574                    sdf.stroke(
575                        mix(
576                            self.border_color_1,
577                            self.border_color_2,
578                            gradient_border.y
579                        ), self.border_size
580                    );
581                }
582
583                return sdf.result;
584            }
585        }
586    }
587
588    pub PopupMenuGradientX = <PopupMenuGradientY> {
589        menu_item: <PopupMenuItemGradientX> {}
590        
591        draw_bg: {
592            fn pixel(self) -> vec4 {
593                let sdf = Sdf2d::viewport(self.pos * self.rect_size)
594                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
595
596                let border_sz_uv = vec2(
597                    self.border_size / self.rect_size.x,
598                    self.border_size / self.rect_size.y
599                )
600
601                let gradient_border = vec2(
602                    self.pos.x + dither,
603                    self.pos.y + dither
604                )
605
606                let sz_inner_px = vec2(
607                    self.rect_size.x - self.border_size * 2.,
608                    self.rect_size.y - self.border_size * 2.
609                );
610
611                let scale_factor_fill = vec2(
612                    self.rect_size.x / sz_inner_px.x,
613                    self.rect_size.y / sz_inner_px.y
614                );
615
616                let gradient_fill = vec2(
617                    self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
618                    self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
619                )
620
621                sdf.box(
622                    self.border_size,
623                    self.border_size,
624                    self.rect_size.x - self.border_size * 2.,
625                    self.rect_size.y - self.border_size * 2.,
626                    self.border_radius
627                )
628
629                sdf.fill_keep(mix(self.color_1, self.color_2, gradient_fill.x));
630
631                if self.border_size > 0.0 {
632                    sdf.stroke(
633                        mix(
634                            self.border_color_1,
635                            self.border_color_2,
636                            gradient_border.y
637                        ), self.border_size
638                    );
639                }
640
641                return sdf.result;
642            }
643        }
644    }
645
646
647}
648
649
650#[derive(Live, LiveHook, LiveRegister)]
651pub struct PopupMenuItem {
652    
653    #[live] draw_bg: DrawQuad,
654    #[live] draw_text: DrawText,
655    
656    #[layout] layout: Layout,
657    #[animator] animator: Animator,
658    #[walk] walk: Walk,
659    
660    #[live] indent_width: f32,
661    #[live] icon_walk: Walk,
662    
663    #[live] opened: f32,
664    #[live] hover: f32,
665    #[live] active: f32,
666}
667
668#[derive(Live, LiveRegister)]
669pub struct PopupMenu {
670    #[live] draw_list: DrawList2d,
671    #[live] menu_item: Option<LivePtr>,
672    
673    #[live] draw_bg: DrawQuad,
674    #[layout] layout: Layout,
675    #[walk] walk: Walk,
676    #[live] items: Vec<String>,
677    #[rust] first_tap: bool,
678    #[rust] menu_items: ComponentMap<PopupMenuItemId, PopupMenuItem>,
679    #[rust] init_select_item: Option<PopupMenuItemId>,
680    
681    #[rust] count: usize,
682}
683
684impl LiveHook for PopupMenu {
685    fn after_apply(&mut self, cx: &mut Cx, apply: &mut Apply, index: usize, nodes: &[LiveNode]) {
686        if let Some(index) = nodes.child_by_name(index, live_id!(list_node).as_field()) {
687            for (_, node) in self.menu_items.iter_mut() {
688                node.apply(cx, apply, index, nodes);
689            }
690        }
691        self.draw_list.redraw(cx);
692    }
693}
694
695pub enum PopupMenuItemAction {
696    WasSweeped,
697    WasSelected,
698    MightBeSelected,
699    None
700}
701
702#[derive(Clone, DefaultNone)]
703pub enum PopupMenuAction {
704    WasSweeped(PopupMenuItemId),
705    WasSelected(PopupMenuItemId),
706    None,
707}
708
709#[derive(Clone, Debug, Default, Eq, Hash, Copy, PartialEq, FromLiveId)]
710pub struct PopupMenuItemId(pub LiveId);
711
712impl PopupMenuItem {
713    
714    pub fn draw_item(
715        &mut self,
716        cx: &mut Cx2d,
717        label: &str,
718    ) {
719        self.draw_bg.begin(cx, self.walk, self.layout);
720        self.draw_text.draw_walk(cx, Walk::fit(), Align::default(), label);
721        self.draw_bg.end(cx);
722    }
723    
724    pub fn handle_event_with(
725        &mut self,
726        cx: &mut Cx,
727        event: &Event,
728        sweep_area: Area,
729        dispatch_action: &mut dyn FnMut(&mut Cx, PopupMenuItemAction),
730    ) {
731        if self.animator_handle_event(cx, event).must_redraw() {
732            self.draw_bg.area().redraw(cx);
733        }
734        
735        match event.hits_with_options(
736            cx,
737            self.draw_bg.area(),
738            HitOptions::new().with_sweep_area(sweep_area)
739        ) {
740            Hit::FingerHoverIn(_) => {
741                self.animator_play(cx, id!(hover.on));
742            }
743            Hit::FingerHoverOut(_) => {
744                self.animator_play(cx, id!(hover.off));
745            }
746            Hit::FingerDown(fe) if fe.is_primary_hit() => {
747                dispatch_action(cx, PopupMenuItemAction::WasSweeped);
748                self.animator_play(cx, id!(hover.on));
749                self.animator_play(cx, id!(active.on));
750            }
751            Hit::FingerUp(se) if se.is_primary_hit() => {
752                if !se.is_sweep {
753                    //if se.was_tap() { // ok this only goes for the first time
754                    //    dispatch_action(cx, PopupMenuItemAction::MightBeSelected);
755                    //    println!("MIGHTBESELECTED");
756                    // }
757                    //else {
758                    dispatch_action(cx, PopupMenuItemAction::WasSelected);
759                    //}
760                }
761                else {
762                    self.animator_play(cx, id!(hover.off));
763                    self.animator_play(cx, id!(active.off));
764                }
765            }
766            _ => {}
767        }
768    }
769}
770
771impl PopupMenu {
772    
773    pub fn menu_contains_pos(&self, cx: &mut Cx, pos: DVec2) -> bool {
774        self.draw_bg.area().clipped_rect(cx).contains(pos)
775    }
776    
777    pub fn begin(&mut self, cx: &mut Cx2d) {
778        self.draw_list.begin_overlay_reuse(cx);
779        
780        let size = cx.current_pass_size();
781        cx.begin_sized_turtle(size, Layout::flow_down());
782        
783        // ok so. this thing needs a complete position reset
784        self.draw_bg.begin(cx, self.walk, self.layout);
785        self.count = 0;
786    }
787    
788    pub fn end(&mut self, cx: &mut Cx2d, shift_area: Area, shift: DVec2) {
789        // ok so.
790        /*
791        let menu_rect1 = cx.turtle().padded_rect_used();
792        let pass_rect = Rect {pos: dvec2(0.0, 0.0), size: cx.current_pass_size()};
793        let menu_rect2 = pass_rect.add_margin(-dvec2(10.0, 10.0)).contain(menu_rect1);
794        */
795        //cx.turtle_mut().set_shift(shift + (menu_rect2.pos - menu_rect1.pos));
796        //let menu_rect1 = cx.turtle().padded_rect_used();
797        self.draw_bg.end(cx);
798        
799        cx.end_pass_sized_turtle_with_shift(shift_area, shift);
800        //cx.debug.rect_r(self.draw_bg.area().get_rect(cx));
801        self.draw_list.end(cx);
802        self.menu_items.retain_visible();
803        if let Some(init_select_item) = self.init_select_item.take() {
804            self.select_item_state(cx, init_select_item);
805        }
806    }
807    
808    pub fn redraw(&mut self, cx: &mut Cx) {
809        self.draw_list.redraw(cx);
810    }
811    
812    pub fn draw_item(
813        &mut self,
814        cx: &mut Cx2d,
815        item_id: PopupMenuItemId,
816        label: &str,
817    ) {
818        self.count += 1;
819        
820        let menu_item = self.menu_item;
821        let menu_item = self.menu_items.get_or_insert(cx, item_id, | cx | {
822            PopupMenuItem::new_from_ptr(cx, menu_item)
823        });
824        menu_item.draw_item(cx, label);
825    }
826    
827    pub fn init_select_item(&mut self, which_id: PopupMenuItemId) {
828        self.init_select_item = Some(which_id);
829        self.first_tap = true;
830    }
831    
832    fn select_item_state(&mut self, cx: &mut Cx, which_id: PopupMenuItemId) {
833        for (id, item) in &mut *self.menu_items {
834            if *id == which_id {
835                item.animator_cut(cx, id!(active.on));
836                item.animator_cut(cx, id!(hover.on));
837            }
838            else {
839                item.animator_cut(cx, id!(active.off));
840                item.animator_cut(cx, id!(hover.off));
841            }
842        }
843    }
844    
845    pub fn handle_event_with(
846        &mut self,
847        cx: &mut Cx,
848        event: &Event,
849        sweep_area: Area,
850        dispatch_action: &mut dyn FnMut(&mut Cx, PopupMenuAction),
851    ) {
852        let mut actions = Vec::new();
853        for (item_id, node) in self.menu_items.iter_mut() {
854            node.handle_event_with(cx, event, sweep_area, &mut | _, e | actions.push((*item_id, e)));
855        }
856        
857        for (node_id, action) in actions {
858            match action {
859                PopupMenuItemAction::MightBeSelected => {
860                    if self.first_tap {
861                        self.first_tap = false;
862                    }
863                    else {
864                        self.select_item_state(cx, node_id);
865                        dispatch_action(cx, PopupMenuAction::WasSelected(node_id));
866                    }
867                }
868                PopupMenuItemAction::WasSweeped => {
869                    self.select_item_state(cx, node_id);
870                    dispatch_action(cx, PopupMenuAction::WasSweeped(node_id));
871                }
872                PopupMenuItemAction::WasSelected => {
873                    self.select_item_state(cx, node_id);
874                    dispatch_action(cx, PopupMenuAction::WasSelected(node_id));
875                }
876                _ => ()
877            }
878        }
879    }
880}
881