1 module rpui.widgets.drop_list_menu.drop_menu_delegate;
2 
3 import rpui.primitives;
4 import rpui.math;
5 import rpui.widget;
6 import rpui.widgets.list_menu.widget;
7 
8 struct DropMenuDelegate {
9     private ListMenu menu;
10     private Widget widget;
11 
12     bool isInVisibilityArea = false;
13     bool isInMenuArea = false;
14     private bool isAttached_ = false;
15 
16     bool isAttached() const {
17         return isAttached_;
18     }
19 
20     void attach(ListMenu menu, Widget widget) {
21         this.menu = menu;
22         this.widget = widget;
23         isAttached_ = true;
24     }
25 
26     void onProgress(in vec2 dropOffset) {
27         const visibleBorderStart = vec2(
28             menu.measure.extraMenuVisibleBorder.left,
29             menu.measure.extraMenuVisibleBorder.top
30         );
31         const visibleBorderEnd = vec2(
32             menu.measure.extraMenuVisibleBorder.right,
33             menu.measure.extraMenuVisibleBorder.bottom
34         );
35 
36         const extraStartArea = vec2(menu.measure.popupExtraPadding.left, menu.measure.popupExtraPadding.top);
37         const extraEndArea = vec2(menu.measure.popupExtraPadding.right, menu.measure.popupExtraPadding.bottom);
38 
39         const visibileArea = Rect(
40             widget.absolutePosition - visibleBorderStart,
41             dropOffset + menu.size + visibleBorderEnd + visibleBorderStart
42         );
43 
44         const menuArea = Rect(
45             menu.absolutePosition + extraStartArea,
46             menu.size - extraStartArea - extraEndArea
47         );
48 
49         bool oneOfItemIsEnter = false;
50 
51         foreach (Widget child; menu.children) {
52             const row = child.associatedWidget;
53             oneOfItemIsEnter = oneOfItemIsEnter || row.isEnter || row.overrideIsEnter;
54         }
55 
56         isInVisibilityArea = pointInRect(menu.view.mousePos, visibileArea) || oneOfItemIsEnter;
57         isInMenuArea = pointInRect(menu.view.mousePos, menuArea);
58 
59         if (!isInVisibilityArea) {
60             hideMenu();
61         }
62     }
63 
64     void toggleMenu(in vec2 dropOffset) {
65         if (!menu.isVisible) {
66             dropMenu(dropOffset);
67         } else {
68             hideMenu();
69         }
70     }
71 
72     void dropMenu(in vec2 dropOffset) {
73         menu.position = widget.absolutePosition + dropOffset + menu.measure.downPopupOffset;
74         menu.isVisible = true;
75     }
76 
77     void hideMenu() {
78         menu.isVisible = false;
79         menu.hideAllSubMenus();
80     }
81 }