# HG changeset patch # User Diggory Hardy # Date 1239369586 -7200 # Node ID c67d074a711118bcd67dcc55e126975d6efd516a # Parent e785e98d3b78ab4e1a1e9681b9143ae4845a90f8 Menu placement now takes into account left/right placement of parent menus. diff -r e785e98d3b78 -r c67d074a7111 mde/gui/WMScreen.d --- a/mde/gui/WMScreen.d Sat Apr 04 17:32:18 2009 +0200 +++ b/mde/gui/WMScreen.d Fri Apr 10 15:19:46 2009 +0200 @@ -110,7 +110,7 @@ // NOTE: Creates new widgets every time; not optimal popupContext = makeWidget (this, "context", contextContent); popupContext.setup (0, 3); - positionPopup (underMouse, popupContext, 0); + positionPopup (underMouse, popupContext); requestRedraw; } else // post other button presses to clickEvent if (underMouse.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state) & 1) { diff -r e785e98d3b78 -r c67d074a7111 mde/gui/WidgetManager.d --- a/mde/gui/WidgetManager.d Sat Apr 04 17:32:18 2009 +0200 +++ b/mde/gui/WidgetManager.d Fri Apr 10 15:19:46 2009 +0200 @@ -308,21 +308,21 @@ if (childIPPW !is ippw) return false; childIPPW.removedIPPW; childIPPW = null; - mAIPPW = false; + mAIPPW = MenuPosition.INACTIVE; requestRedraw; return false; } - override void menuActive (bool mA) { + override void menuActive (MenuPosition mA) { mAIPPW = mA; if (childIPPW) childIPPW.menuActive = mA; } - override bool menuActive () { + override MenuPosition menuActive () { return mAIPPW; } - override bool parentMenuActive () { - return false; + override MenuPosition parentMenuActive () { + return MenuPosition.INACTIVE; } // Don't do anything. E.g. can get called by non-popup buttons. @@ -333,7 +333,8 @@ if (popupContext.onSelf (cx, cy)) return popupContext; if (closePopup) { - menuActive = (childIPPW !is null); + if (childIPPW is null) + menuActive = MenuPosition.INACTIVE; popupContext = null; requestRedraw; } @@ -343,7 +344,7 @@ childIPPW.getPopupWidget (cx, cy, closePopup); if (ret) return ret; if (closePopup) { - menuActive = false; + menuActive = MenuPosition.INACTIVE; removeChildIPPW (childIPPW); } } @@ -409,26 +410,43 @@ return rend; } - void positionPopup (IChildWidget parent, IChildWidget popup, int flags = 0) { + MenuPosition positionPopup (IChildWidget parent, IChildWidget popup, MenuPosition position = MenuPosition.INACTIVE) { debug assert (parent && popup, "positionPopup: null widget"); wdim w = popup.width, h = popup.height, x, y; - if (flags & 1) { - y = parent.yPos; // height flush with top + if (position & MenuPosition.ACTIVE) { + y = parent.yPos; // height flush with top if (y+h > this.h) y += parent.height - h; // or bottom - x = parent.xPos + parent.width; // on right - if (x+w > this.w) x = parent.xPos - w; // or left edge + if (position & MenuPosition.LEFT) { // previously left + x = parent.xPos - w; // on left + if (x < 0) { + x = parent.xPos + parent.width; // on right + position = MenuPosition.RIGHT; + } + } else { // previously right or above/below + x = parent.xPos + parent.width; // on right + position = MenuPosition.RIGHT; + if (x+w > this.w) { + x = parent.xPos - w; // or left + position = MenuPosition.LEFT; + } + } } else { - x = parent.xPos; // align on left edge - if (x+w > this.w) x += parent.width - w; // align on right edge + wdim pw = parent.width; + if (w < pw && popup.minWidth <= pw) + popup.setWidth (pw, -1); // neatness + x = parent.xPos; // align on left edge + if (x+w > this.w) x += pw - w; // align on right edge y = parent.yPos + parent.height; // place below if (y+h > this.h) y = parent.yPos - h; // or above + position = MenuPosition.ACTIVE; } if (x < 0) x = 0; // may be placed partially off-screen if (y < 0) y = 0; popup.setPosition (x, y); //debug logger.trace ("placed popup at {},{}; size: {},{}", x,y, w,h); + return position; } void requestRedraw () { @@ -616,7 +634,7 @@ scope IChildWidget child; // The primary widget. uint setupN; // n to pass to IChildWidget.setup - bool mAIPPW; // IPPW variable + MenuPosition mAIPPW; // IPPW variable IPopupParentWidget childIPPW; // child IPPW, if any active // Popup(s) handled directly by AWidgetManager: diff -r e785e98d3b78 -r c67d074a7111 mde/gui/widget/AParentWidget.d --- a/mde/gui/widget/AParentWidget.d Sat Apr 04 17:32:18 2009 +0200 +++ b/mde/gui/widget/AParentWidget.d Fri Apr 10 15:19:46 2009 +0200 @@ -130,7 +130,7 @@ childIPPW.removedIPPW; childIPPW = null; mgr.requestRedraw; - mAIPPW = false; + mAIPPW = MenuPosition.INACTIVE; return true; } @@ -141,18 +141,18 @@ childIPPW.removedIPPW; childIPPW = null; } - mAIPPW = false; + mAIPPW = MenuPosition.INACTIVE; } - override void menuActive (bool mA) { + override void menuActive (MenuPosition mA) { mAIPPW = mA; if (childIPPW) childIPPW.menuActive = mA; } - override bool menuActive () { + override MenuPosition menuActive () { return mAIPPW; } - override bool parentMenuActive () { + override MenuPosition parentMenuActive () { return parentIPPW.menuActive; } @@ -166,7 +166,7 @@ if (childIPPW) { ret = childIPPW.getPopupWidget (cx, cy, closePopup); if (closePopup && ret is null) { - menuActive = false; + menuActive = MenuPosition.INACTIVE; removeChildIPPW (childIPPW); } } @@ -208,5 +208,5 @@ IPopupParentWidget parentIPPW; IPopupParentWidget childIPPW; IChildWidget popup; - bool mAIPPW; + MenuPosition mAIPPW; } diff -r e785e98d3b78 -r c67d074a7111 mde/gui/widget/Ifaces.d --- a/mde/gui/widget/Ifaces.d Sat Apr 04 17:32:18 2009 +0200 +++ b/mde/gui/widget/Ifaces.d Fri Apr 10 15:19:46 2009 +0200 @@ -107,6 +107,14 @@ *****************************************************************************/ interface IPopupParentWidget : IParentWidget { + /// menuActive's type + enum MenuPosition { + INACTIVE = 0, + ACTIVE = 1, + LEFT = 3, + RIGHT = 5 + } + /** Add caller ippw as current child IPopupParentWidget of called IPPW. * * ippw is added as called IPPW's child IPPW, and its functions are @@ -128,18 +136,22 @@ /** Notify the called IPPW that it has been removed. */ void removedIPPW (); - /** Set/get menuActive state. + /** Set/get menuActive state, which includes position information. * * This is set on the parent IPPW when a popup menu is opened and unset * when the menu is closed. * If set on the parent IPPW, popup menus can be opened with just a mouse- - * over and buttons activated with an up-click. */ - void menuActive (bool); - bool menuActive (); - /** Returns the IPPW's parent's menuActive (WM returns false). If true, - * popup widgets may assume they are sub-menu popups not top-level menu - * popups. */ - bool parentMenuActive (); + * over and buttons activated with an up-click. + * + * It is also used by positionPopup to signal if the popup was left or + * right of the previous popup, to enable a further popup to be placed by + * positionPopup without overlapping previous popups. */ + void menuActive (MenuPosition); + MenuPosition menuActive (); + /** Returns the IPPW's parent's menuActive (WM returns false). If + * (menuActive & MenuPosition.ACTIVE) popup widgets may assume they are + * sub-menu popups not top-level menu popups. */ + MenuPosition parentMenuActive (); /** Called by descendant widgets such as buttons when an action occurred, * which should close a menu. (But also called when not in a menu.) */ @@ -153,7 +165,7 @@ * * If closePopup is true and a widget isn't returned from the childIPPW, * the childIPPW should be removed (to close popups when a click is not on - * the popup or its parent) and menuActive set false. */ + * the popup or its parent) and menuActive set to INACTIVE. */ IChildWidget getPopupWidget (wdabs cx, wdabs cy, bool closePopup); /** Draw. @@ -199,9 +211,18 @@ wdims dimData (widgetID id); /// ditto void dimData (widgetID id, wdims d); /// ditto - /** Position popup below or above parent, or right or left of parent - * (flags & 1 == 1). */ - void positionPopup (IChildWidget parent, IChildWidget popup, int flags = 0); + /** Position popup adjacent to parent. + * + * If position is 0, place popup below parent, or above if there isn't + * space below, and expand popup's width to at least that of parent. + * + * If (position & MenuPosition.ACTIVE), place popup to the side of parent, + * using the side indicated by LEFT or RIGHT, if any. + * + * Returns: + * MenuPosition.ACTIVE if popup placed above or below, and LEFT or RIGHT + * if placed left or right of parent. */ + MenuPosition positionPopup (IChildWidget parent, IChildWidget popup, MenuPosition position = MenuPosition.INACTIVE); // Rendering: /** For when a widget needs redrawing. diff -r e785e98d3b78 -r c67d074a7111 mde/gui/widget/ParentContent.d --- a/mde/gui/widget/ParentContent.d Sat Apr 04 17:32:18 2009 +0200 +++ b/mde/gui/widget/ParentContent.d Fri Apr 10 15:19:46 2009 +0200 @@ -76,10 +76,7 @@ if (b == 1 && state == true) { if (!pushed) { parentIPPW.addChildIPPW (this); - parentIPPW.menuActive = true; - if (popup.width != w && popup.minWidth <= w) - popup.setWidth (w, -1); // neatness - mgr.positionPopup (this, popup); + parentIPPW.menuActive = mgr.positionPopup (this, popup); pushed = true; } else if (!parentIPPW.parentMenuActive) { // if not a submenu parentIPPW.removeChildIPPW (this); @@ -96,14 +93,7 @@ override void underMouse (bool state) { if (state && !pushed && parentIPPW.menuActive) { parentIPPW.addChildIPPW (this); - menuActive = true; - if (parentIPPW.parentMenuActive) - mgr.positionPopup (this, popup, 1); - else { - if (popup.width != w && popup.minWidth <= w) - popup.setWidth (w, -1); // neatness - mgr.positionPopup (this, popup); - } + menuActive = mgr.positionPopup (this, popup, parentIPPW.parentMenuActive); pushed = true; } }