1 module rpui.widgets.list_menu_item.widget; 2 3 import rpui.events; 4 import rpui.widget_events; 5 import rpui.input; 6 import rpui.math; 7 import rpui.primitives; 8 import rpui.widget; 9 import rpui.widgets.button.widget; 10 import rpui.widgets.list_menu.widget; 11 import rpui.widgets.list_menu_item.renderer; 12 import rpui.widgets.drop_list_menu.drop_menu_delegate; 13 14 interface MenuActions { 15 void hideMenu(); 16 17 MenuActions parentActions(); 18 } 19 20 class ListMenuItem : Button, MenuActions { 21 @field string shortcut = ""; 22 23 private ListMenu parentMenu = null; 24 package ListMenu menu = null; 25 private DropMenuDelegate dropMenuDelegate; 26 27 this(in string style = "ListMenuItem") { 28 super(style); 29 30 this.renderer = new ListMenuItemRenderer(); 31 this.textAlign = Align.left; 32 this.widthType = SizeType.matchParent; 33 this.focusable = false; 34 } 35 36 protected override void onPostCreate() { 37 super.onPostCreate(); 38 39 if (menu !is null) 40 return; 41 42 // Because item places in wrapper called Cell. 43 parentMenu = cast(ListMenu) parent.parent; 44 assert(parentMenu !is null); 45 46 if (parentMenu.isPopup) { 47 uselessIconArea = 1; 48 } 49 50 events.subscribe!ClickEvent(&onClick); 51 attachShortcut(); 52 53 if (children.empty) 54 return; 55 56 menu = cast(ListMenu)(children.front); 57 58 if (menu is null) 59 return; 60 61 menu.isVisible = false; 62 menu.focusable = false; 63 view.moveWidgetToFront(menu); 64 65 dropMenuDelegate.attach(menu, this); 66 67 // submenuDisplayTimeout = createTimeout(menu.displayDelay, delegate() { 68 if (isEnter) { 69 dropMenuDelegate.dropMenu(vec2(size.x, 0) + menu.measure.rightPopupOffset); 70 } 71 // }); 72 } 73 74 void attachShortcut() { 75 if (shortcut.length == 0) 76 return; 77 78 if (shortcut[0] == '@') { 79 const shortcutPath = shortcut[1 .. $]; 80 view.shortcuts.attachByPath(shortcutPath, () => events.notify(ClickEvent())); 81 } else { 82 view.shortcuts.attach(shortcut, () => events.notify(ClickEvent())); 83 } 84 } 85 86 override void onProgress(in ProgressEvent event) { 87 super.onProgress(event); 88 89 // submenuDisplayTimeout.onProgress(app.deltaTime); 90 91 if (isEnter) { 92 parentMenu.hideAllSubMenusExcept(this); 93 } 94 95 // if (isEnter && !submenuDisplayTimeout.isStarted()) { 96 // submenuDisplayTimeout.start(); 97 // } 98 99 if (dropMenuDelegate.isAttached()) { 100 dropMenuDelegate.onProgress(vec2(size.x, 0) + menu.measure.rightPopupOffset); 101 overrideIsEnter = dropMenuDelegate.isInVisibilityArea && menu.isVisible; 102 } 103 } 104 105 private void onClick() { 106 if (menu is null) 107 hideRootMenu(); 108 109 if (dropMenuDelegate.isAttached()) { 110 dropMenuDelegate.dropMenu(vec2(size.x, 0) + menu.measure.rightPopupOffset); 111 } 112 } 113 114 override void focus() { 115 /* Ignore */ 116 } 117 118 override void hideMenu() { 119 if (dropMenuDelegate.isAttached()) { 120 dropMenuDelegate.hideMenu(); 121 } 122 } 123 124 private void hideRootMenu() { 125 MenuActions currentMenuActions = this; 126 MenuActions parentMenuActions = parentActions(); 127 128 while (parentMenuActions !is null) { 129 currentMenuActions = parentMenuActions; 130 parentMenuActions = parentMenuActions.parentActions(); 131 } 132 133 currentMenuActions.hideMenu(); 134 } 135 136 override MenuActions parentActions() { 137 auto actions = cast(MenuActions) parentMenu.owner; 138 return actions; 139 } 140 }