changeset 152:c67d074a7111

Menu placement now takes into account left/right placement of parent menus.
author Diggory Hardy <diggory.hardy@gmail.com>
date Fri, 10 Apr 2009 15:19:46 +0200
parents e785e98d3b78
children 2934fcacbb97
files mde/gui/WMScreen.d mde/gui/WidgetManager.d mde/gui/widget/AParentWidget.d mde/gui/widget/Ifaces.d mde/gui/widget/ParentContent.d
diffstat 5 files changed, 76 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- 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) {
--- 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:
--- 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;
 }
--- 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.
--- 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;
         }
     }