Mercurial > projects > mde
changeset 133:9fd705793568
Fixed menu popup bug, improved recursion detection.
Menu popups can now determine whether or not they are sub-menus.
Recursion detection can now also check content (if not the same, there's not a risk of infinite recursion).
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Fri, 23 Jan 2009 16:05:05 +0000 |
parents | 264028f4115a |
children | 7ababdf97748 |
files | data/conf/guiDemo.mtt mde/gui/WidgetManager.d mde/gui/exception.d mde/gui/widget/AParentWidget.d mde/gui/widget/Ifaces.d mde/gui/widget/PopupMenu.d mde/gui/widget/layout.d mde/menus.d |
diffstat | 8 files changed, 59 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/data/conf/guiDemo.mtt Fri Jan 23 14:59:05 2009 +0000 +++ b/data/conf/guiDemo.mtt Fri Jan 23 16:05:05 2009 +0000 @@ -8,12 +8,9 @@ <WidgetData|blank={0:[0x2]}> <WidgetData|menuContent={0:[0x2031],1:["imde.menus","menus"]}> -<WidgetData|menus={0:[0xC110,8] ,1:["menuPopup"]}> +<WidgetData|menus={0:[0x4110,12] ,1:["menuPopup"]}> <WidgetData|menuPopup={0:[0x6033,0],1:["menuList"]}> -!{Could recurse to menuPopup if it wasn't for recursion protection:} -<WidgetData|menuList={0:[0xE030,0] ,1:["menu1Popup"]}> -<WidgetData|menu1Popup={0:[0x6033] ,1:["menu1List"]}> -<WidgetData|menu1List={0:[0xE030,0],1:["blank"]}> +<WidgetData|menuList={0:[0x6030,0] ,1:["menuPopup"]}> <EnumContent|switch={0:["misc","video","font"],1:0}> <WidgetData|options={0:[0x2031],1:["dynamic.switch","switchL"]}> @@ -26,12 +23,12 @@ <WidgetData|optFont={0:[0x2031],1:["Options.FontOptions","optSec"]}> !{use optBox for no description, optDBox for descriptions under entries} -<WidgetData|optSec={0:[0xC110,0],1:["optBox"]}> +<WidgetData|optSec={0:[0x4110,0],1:["optBox"]}> <WidgetData|optDBox={0:[0x4100,1,2,1],1:["optBox","optDesc"]}> <WidgetData|optBox={0:[0x4100,1,1,3],1:["optName","optSep","optVal"]}> <WidgetData|optName={0:[0x4020, 1, 0xffffff]}> <WidgetData|optDesc={0:[0x4020, 2, 0x999999]}> -<WidgetData|optVal={0:[0xE030,12],1:["optEnum"]}> +<WidgetData|optVal={0:[0x6030,12],1:["optEnum"]}> <WidgetData|optEnum={0:[0x4100,0,1,2],1:["optVal","optName"]}> <WidgetData|optSep={0:[0x21, 0xff],1:[" = "]}> {Basic}
--- a/mde/gui/WidgetManager.d Fri Jan 23 14:59:05 2009 +0000 +++ b/mde/gui/WidgetManager.d Fri Jan 23 16:05:05 2009 +0000 @@ -268,7 +268,7 @@ //BEGIN IParentWidget methods // If call reaches the widget manager there isn't any recursion. //NOTE: should be override - final void recursionCheck (widgetID) {} + final void recursionCheck (widgetID, IContent) {} override void minWChange (IChildWidget widget, wdim nmw) { debug assert (widget is child, "WM.mSC (code error)"); @@ -320,6 +320,9 @@ override bool menuActive () { return mAIPPW; } + override bool parentMenuActive () { + return false; + } // Don't do anything. E.g. can get called by non-popup buttons. override void menuDone () {} @@ -473,7 +476,6 @@ enum WIDGET_TYPE : int { FUNCTION = 0x2000, // Function called instead of widget created (no "Widget" appended to fct name) TAKES_CONTENT = 0x4000, // Flag indicates widget's this should be passed an IContent reference. - SAFE_RECURSION = 0x8000, // Safe to instantiate recursively without infinite looping. // Use widget names rather than usual capitals convention Unnamed = 0x0, // Only for use by widgets not created with createWidget @@ -491,7 +493,7 @@ TextLabel = 0x21, // content functions: 0x30 - editContent = FUNCTION | TAKES_CONTENT | SAFE_RECURSION | 0x30, + editContent = FUNCTION | TAKES_CONTENT | 0x30, addContent = FUNCTION | 0x31, popupListContent = FUNCTION | TAKES_CONTENT | 0x33, @@ -502,7 +504,7 @@ ButtonContent = TAKES_CONTENT | 0x43, GridLayout = TAKES_CONTENT | 0x100, - ContentList = TAKES_CONTENT | SAFE_RECURSION | 0x110, + ContentList = TAKES_CONTENT | 0x110, FloatingArea = TAKES_CONTENT | 0x200, Switch = TAKES_CONTENT | 0x210, @@ -522,11 +524,11 @@ "AStringContent", "ButtonContent", "GridLayout", + "ContentList", "FloatingArea", "Switch", - "popupListContent", - "ContentList", - "editContent"]; + "editContent", + "popupListContent"]; /* Generates a binary search algorithm for makeWidget. */ char[] binarySearch (char[] var, char[][] consts) { @@ -541,8 +543,7 @@ foreach (c; consts) { ret ~= `if (` ~ var ~ ` == WIDGET_TYPE.` ~ c ~ `) { debug (mdeWidgets) logger.trace ("Creating new `~c~`."); - if (!(WIDGET_TYPE.`~c~` & WIDGET_TYPE.SAFE_RECURSION)) - parent.recursionCheck (id); + parent.recursionCheck (id, content); static if (WIDGET_TYPE.`~c~` & WIDGET_TYPE.FUNCTION) return `~c~` (this, parent, id, data, content); else static if (WIDGET_TYPE.`~c~` & WIDGET_TYPE.TAKES_CONTENT)
--- a/mde/gui/exception.d Fri Jan 23 14:59:05 2009 +0000 +++ b/mde/gui/exception.d Fri Jan 23 16:05:05 2009 +0000 @@ -40,6 +40,14 @@ } } +/// Thrown when a widget is (potentially) being recursed infinitely. +class WidgetRecursionException : GuiException +{ + this (char[] id) { // Pass id of widget being recursed + super ("Infinite recursion of "~id); + } +} + class ContentException : GuiException { char[] getSymbol () {
--- a/mde/gui/widget/AParentWidget.d Fri Jan 23 14:59:05 2009 +0000 +++ b/mde/gui/widget/AParentWidget.d Fri Jan 23 16:05:05 2009 +0000 @@ -23,6 +23,7 @@ public import mde.gui.widget.AChildWidget; import mde.gui.exception; +import mde.content.Content; debug { import tango.util.log.Log : Log, Logger; @@ -72,13 +73,13 @@ throw new GuiException ("getWidgetIndex: widget not found (code error)"); } - // Don't override; use the WIDGET_TYPE.SAFE_RECURSION flag for safe widgets. - //NOTE: should be override (compiler bug) - final void recursionCheck (widgetID a) { + // Parents taking a content should override, only throwing if both the + // widget id and the content are the same (as its it and content). + override void recursionCheck (widgetID wID, IContent c) { debug assert (id !is null && parent !is null, "recursionCheck called before parent and id set"); - if (a is id) - throw new GuiException ("Infite recursion of "~a); - parent.recursionCheck (a); + if (wID is id) + throw new WidgetRecursionException (wID); + parent.recursionCheck (wID, c); } IPopupParentWidget getParentIPPW () { @@ -151,7 +152,10 @@ override bool menuActive () { return mAIPPW; } - + override bool parentMenuActive () { + return parentIPPW.menuActive; + } + override void menuDone () { // default actions, for popup menus: parentIPPW.removeChildIPPW (this); // remove self parentIPPW.menuDone; // and propegate
--- a/mde/gui/widget/Ifaces.d Fri Jan 23 14:59:05 2009 +0000 +++ b/mde/gui/widget/Ifaces.d Fri Jan 23 16:05:05 2009 +0000 @@ -47,7 +47,7 @@ interface IParentWidget { /** Checks for recursion of unsafe widgets to prevent infinite recursion. */ - void recursionCheck (widgetID); + void recursionCheck (widgetID, IContent); /** IPPWs return self, other widgets recurse call on parent. */ IPopupParentWidget getParentIPPW (); @@ -132,6 +132,10 @@ * 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 (); /** Called by descendant widgets such as buttons when an action occurred, * which should close a menu. (But also called when not in a menu.) */
--- a/mde/gui/widget/PopupMenu.d Fri Jan 23 14:59:05 2009 +0000 +++ b/mde/gui/widget/PopupMenu.d Fri Jan 23 16:05:05 2009 +0000 @@ -51,6 +51,12 @@ h = mh; } + override void recursionCheck (widgetID wID, IContent c) { + if (wID is id && c is content) + throw new WidgetRecursionException (wID); + parent.recursionCheck (wID, c); + } + override int clickEvent (wdabs, wdabs, ubyte b, bool state) { if (b == 1 && state == true) { if (!pushed) { @@ -58,10 +64,7 @@ parentIPPW.menuActive = true; mgr.positionPopup (this, popup); pushed = true; - } else { - // NOTE: perhaps shouldn't do anything when - // parentIPPW.parentIPPW.menuActive - // (this causes funny behaviour when clicking a submenu): + } else if (!parentIPPW.parentMenuActive) { // if not a submenu parentIPPW.removeChildIPPW (this); } } @@ -77,7 +80,8 @@ if (state && !pushed && parentIPPW.menuActive) { parentIPPW.addChildIPPW (this); menuActive = true; - mgr.positionPopup (this, popup, 1); // causes redraw + mgr.positionPopup (this, popup, + parentIPPW.parentMenuActive ? 1 : 0); pushed = true; } }
--- a/mde/gui/widget/layout.d Fri Jan 23 14:59:05 2009 +0000 +++ b/mde/gui/widget/layout.d Fri Jan 23 16:05:05 2009 +0000 @@ -116,6 +116,12 @@ } } + override void recursionCheck (widgetID wID, IContent c) { + if (wID is id && c is cList) + throw new WidgetRecursionException (wID); + parent.recursionCheck (wID, c); + } + override bool saveChanges () { // Since all sub-widgets have the same id, it only makes sense to call on one if (subWidgets is null)
--- a/mde/menus.d Fri Jan 23 14:59:05 2009 +0000 +++ b/mde/menus.d Fri Jan 23 16:05:05 2009 +0000 @@ -36,5 +36,10 @@ debug logger.trace ("Quit (from menu)"); run = false; }); - menus.append (new ContentList ("main", [cast(Content)quit])); + auto main = new ContentList ("main", [cast(Content)quit]); + debug { + main.append (new ContentList ("sm1", [cast(Content) new EventContent ("a"), new EventContent ("b")])); + main.append (new ContentList ("sm2", [cast(Content) new EventContent ("c"), new EventContent ("d")])); + } + menus.append (main); }