diff --git a/examples/example1/main.d b/examples/example1/main.d index 80620b6f..f59957c7 100644 --- a/examples/example1/main.d +++ b/examples/example1/main.d @@ -54,10 +54,19 @@ extern (C) int UIAppMain(string[] args) { fileItem.add(new Action(10, "Open..."d)); fileItem.add(new Action(11, "Save..."d)); fileItem.add(new Action(12, "Exit"d)); + MenuItem editItem = new MenuItem(new Action(2, "Edit"d)); + editItem.add(new Action(20, "Copy"d)); + editItem.add(new Action(21, "Paste"d)); + editItem.add(new Action(22, "Cut"d)); + MenuItem windowItem = new MenuItem(new Action(3, "Window"d)); + windowItem.add(new Action(30, "Preferences"d)); + MenuItem helpItem = new MenuItem(new Action(4, "Help"d)); + helpItem.add(new Action(40, "View Help"d)); + helpItem.add(new Action(41, "About"d)); mainMenuItems.add(fileItem); - mainMenuItems.add(new Action(2, "Edit"d)); - mainMenuItems.add(new Action(3, "Window"d)); - mainMenuItems.add(new Action(4, "Help"d)); + mainMenuItems.add(editItem); + mainMenuItems.add(windowItem); + mainMenuItems.add(helpItem); MainMenu mainMenu = new MainMenu(mainMenuItems); contentLayout.addChild(mainMenu); diff --git a/src/dlangui/platforms/windows/winapp.d b/src/dlangui/platforms/windows/winapp.d index 73fa791d..a2465a90 100644 --- a/src/dlangui/platforms/windows/winapp.d +++ b/src/dlangui/platforms/windows/winapp.d @@ -418,6 +418,7 @@ class Win32Window : Window { /// request window redraw override void invalidate() { InvalidateRect(_hwnd, null, FALSE); + UpdateWindow(_hwnd); } /// after drawing, call to schedule redraw if animation is active diff --git a/src/dlangui/widgets/lists.d b/src/dlangui/widgets/lists.d index 16edece2..57e19236 100644 --- a/src/dlangui/widgets/lists.d +++ b/src/dlangui/widgets/lists.d @@ -80,6 +80,13 @@ class ListWidget : WidgetGroup, OnScrollHandler { /// item with Selected state, -1 if no such item protected int _selectedItemIndex; + /// when true, mouse hover selects underlying item + protected bool _selectOnHover; + /// when true, mouse hover selects underlying item + @property bool selectOnHover() { return _selectOnHover; } + /// when true, mouse hover selects underlying item + @property ListWidget selectOnHover(bool select) { _selectOnHover = select; return this; } + /// returns rectangle for item (not scrolled, first item starts at 0,0) Rect itemRectNoScroll(int index) { Rect res; @@ -173,6 +180,10 @@ class ListWidget : WidgetGroup, OnScrollHandler { } } + /// override to handle change of selection + protected void selectionChanged(int index, int previouslySelectedItem = -1, MouseEvent event = null) { + } + protected void selectItem(int index) { if (_selectedItemIndex == index) return; @@ -475,9 +486,13 @@ class ListWidget : WidgetGroup, OnScrollHandler { itemrc.top += rc.top - scrollOffset.y; itemrc.bottom += rc.top - scrollOffset.y; if (itemrc.isPointInside(Point(event.x, event.y))) { - if (event.flags & (MouseFlag.LButton || MouseFlag.RButton)) { + if ((event.flags & (MouseFlag.LButton || MouseFlag.RButton)) || _selectOnHover) { + if (_selectedItemIndex == i) + return true; + int prevSelection = _selectedItemIndex; selectItem(i); setHoverItem(-1); + selectionChanged(_selectedItemIndex, prevSelection, event); } else setHoverItem(i); } diff --git a/src/dlangui/widgets/menu.d b/src/dlangui/widgets/menu.d index ee2e2d56..4eb42b9f 100644 --- a/src/dlangui/widgets/menu.d +++ b/src/dlangui/widgets/menu.d @@ -77,117 +77,64 @@ class MenuItemWidget : HorizontalLayout { addChild(_label); trackHover = true; } - - /// process mouse event; return true if event is processed by widget. - override bool onMouseEvent(MouseEvent event) { - Log.d("onMouseEvent ", id, " ", event.action, " (", event.x, ",", event.y, ")"); - // support onClick - if (_handler !is null) { - if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) { - setState(State.Selected); - _handler.onItemMouseDown(this, event); - return true; - } - if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) { - resetState(State.Selected); - _handler.onItemMouseDown(this, event); - return true; - } - /* - if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) { - resetState(State.Pressed); - _onClickListener(this); - return true; - } - if (event.action == MouseAction.FocusOut || event.action == MouseAction.Cancel) { - resetState(State.Pressed); - resetState(State.Hovered); - return true; - } - if (event.action == MouseAction.FocusIn) { - setState(State.Pressed); - return true; - } - */ - } - return super.onMouseEvent(event); - } - } -class MainMenu : HorizontalLayout, MenuItemWidgetHandler { +class MenuWidgetBase : ListWidget { protected MenuItem _item; + protected PopupMenu _openedMenu; protected PopupWidget _openedPopup; - protected MenuItemWidget _openedMenu; - - - override protected bool onItemMouseDown(MenuItemWidget itemWidget, MouseEvent ev) { - PopupMenu popupMenu = new PopupMenu(itemWidget.item); - PopupWidget popup = window.showPopup(popupMenu, itemWidget, PopupAlign.Below); - ev.track(popupMenu); - return true; - } - override protected bool onItemMouseUp(MenuItemWidget itemWidget, MouseEvent ev) { - return true; - } - - /* - protected bool onItemClick(Widget w) { - MenuItemWidget itemWidget = cast(MenuItemWidget)w; - Log.d("onItemClick ", w.id); - window.showPopup(new PopupMenu(itemWidget.item), itemWidget, PopupAlign.Below); - return true; - } - */ - this(MenuItem item) { - id = "MAIN_MENU"; - styleId = "MAIN_MENU"; + this(MenuItem item, Orientation orientation) { _item = item; - for (int i = 0; i < item.subitemCount; i++) { - MenuItemWidget subitem = new MenuItemWidget(item.subitem(i)); - //subitem.onClickListener = &onItemClick; - subitem.handler = this; - addChild(subitem); - } - addChild((new Widget()).layoutWidth(FILL_PARENT)); - } -} - -class PopupMenu : ListWidget, MenuItemWidgetHandler { - protected MenuItem _item; - this(MenuItem item) { + this.orientation = orientation; id = "popup_menu"; styleId = "POPUP_MENU"; - _item = item; WidgetListAdapter adapter = new WidgetListAdapter(); for (int i=0; i < _item.subitemCount; i++) { MenuItem subitem = _item.subitem(i); MenuItemWidget widget = new MenuItemWidget(subitem); - widget.handler = this; + //widget.handler = this; adapter.widgets.add(widget); } ownAdapter = adapter; } - override protected bool onItemMouseDown(MenuItemWidget itemWidget, MouseEvent ev) { + /// override to handle change of selection + override protected void selectionChanged(int index, int previouslySelectedItem = -1, MouseEvent event = null) { + MenuItemWidget itemWidget = index >= 0 ? cast(MenuItemWidget)_adapter.itemWidget(index) : null; if (itemWidget.item.isSubmenu()) { + if (_openedPopup !is null) + _openedPopup.close(); PopupMenu popupMenu = new PopupMenu(itemWidget.item); PopupWidget popup = window.showPopup(popupMenu, itemWidget, PopupAlign.Below); - ev.track(popupMenu); + if (event !is null && (event.flags & (MouseFlag.LButton || MouseFlag.RButton))) + event.track(popupMenu); + _openedPopup = popup; + _openedMenu = popupMenu; + selectOnHover = true; } else { // normal item } - return true; - } - - override protected bool onItemMouseUp(MenuItemWidget itemWidget, MouseEvent ev) { - if (itemWidget.item.isSubmenu()) { - } else { - // normal item - // TODO: action - } - return true; - } + } } + +class MainMenu : MenuWidgetBase { + + this(MenuItem item) { + super(item, Orientation.Horizontal); + id = "MAIN_MENU"; + styleId = "MAIN_MENU"; + } +} + +class PopupMenu : MenuWidgetBase { + + this(MenuItem item) { + super(item, Orientation.Vertical); + id = "POPUP_MENU"; + styleId = "POPUP_MENU"; + selectOnHover = true; + } +} + diff --git a/src/dlangui/widgets/popup.d b/src/dlangui/widgets/popup.d index b68e487a..0f65b699 100644 --- a/src/dlangui/widgets/popup.d +++ b/src/dlangui/widgets/popup.d @@ -32,6 +32,10 @@ class PopupWidget : LinearLayout { override void measure(int parentWidth, int parentHeight) { super.measure(parentWidth, parentHeight); } + /// close and destroy popup + void close() { + window.removePopup(this); + } /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout). override void layout(Rect rc) {