changeset 116:5ee69b3ed9c9

Partial implementation of infinite widget recursion protection; some cleanup. Implemented recursion protection which only allowed unsafe widgets to be instantiated once; realised this was far too restrictive (multiple sibling instances are needed) and a check against parent widgets would be needed. Could be implemented by passing widgets a reference to parents. Removed ButtonWidget aka First interactible widget.
author Diggory Hardy <diggory.hardy@gmail.com>
date Sun, 21 Dec 2008 12:03:50 +0000
parents 1b1e2297e2fc
children aba2dd815a1f
files codeDoc/debugCodes.txt data/conf/gui.mtt mde/gui/WidgetManager.d mde/gui/widget/Ifaces.d mde/gui/widget/createWidget.d mde/gui/widget/miscContent.d mde/gui/widget/miscWidgets.d mde/setup/Screen.d
diffstat 8 files changed, 73 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- a/codeDoc/debugCodes.txt	Sat Dec 20 17:57:05 2008 +0000
+++ b/codeDoc/debugCodes.txt	Sun Dec 21 12:03:50 2008 +0000
@@ -13,3 +13,4 @@
 mdeUnitTest             Compile in unittest code (including extra imports, and a few other bits outside the unittest itself).
 drawGlyphCache          Draw the font texture in the upper-left corner of the screen, with a pretty background.
 mdeWidgets              Log trace messages for the creation of all widgets.
+SDLCalls		Log a message before some SDL calls.
--- a/data/conf/gui.mtt	Sat Dec 20 17:57:05 2008 +0000
+++ b/data/conf/gui.mtt	Sun Dec 21 12:03:50 2008 +0000
@@ -2,20 +2,24 @@
 <char[]|Renderer="Simple">
 <char[]|Design="Working">
 {Working}
-<WidgetData|root={0:[0xC100,0,3,1],1:["bar","opts","bar"]}>
-<WidgetData|bar={0:[0xC100,0,1,3],1:["menu","blank","menu"]}>
-<WidgetData|menu={0:[0x2031,0xC011,0],1:["imde.menu"]}>
+<WidgetData|root={0:[0x4100,0,3,1],1:["bar","opts","bar"]}>
+<WidgetData|bar={0:[0x4100,0,1,3],1:["menu","blank","menu"]}>
+<WidgetData|menu={0:[0x2031,0x4011,0],1:["imde.menu"]}>
 <WidgetData|blank={0:[0x2]}>
-<WidgetData|opts={0:[0x2031,0xC100,4,2,1],1:["Options","optName","optSecs"]}>
-<WidgetData|optSecs={0:[0x6030,4],1:["optSec"]}>
-<WidgetData|optSec={0:[0xC100,0,2,1],1:["optName","optVars"]}>
-<WidgetData|optVars={0:[0x6030,0],1:["optDBox"]}>
-<WidgetData|optDBox={0:[0xC100,1,2,1],1:["optBox","optDesc"]}>
-<WidgetData|optBox={0:[0xC100,1,1,3],1:["optName","optSep","optVal"]}>
+<WidgetData|opts={0:[0x2031,0x4100,4,2,1],1:["Options","optName","optSecs"]}>
+<WidgetData|optSecs={0:[0xE030,4],1:["optSec"]}>
+<WidgetData|optSec={0:[0x4100,0,2,1],1:["optName","optVars"]}>
+<WidgetData|optVars={0:[0xE030,0],1:["optDBox"]}>
+<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, 0xfe8c00]}>
 <WidgetData|optDesc={0:[0x4020, 2, 0xaf6000]}>
-<WidgetData|optVal={0:[0x6030,12],1:["optEnum"]}>
-<WidgetData|optEnum={0:[0xC100,0,1,2],1:["optVal","optName"]}>
+<WidgetData|optVal={0:[0xE030,12],1:["optEnum"]}>
+<WidgetData|optEnum={0:[0x4100,0,1,2],1:["optVal","optName"]}>
 <WidgetData|optSep={0:[0x21, 0xff],1:[" = "]}>
 {Basic}
-<WidgetData|root={0:[0x21,0x90D970],1:["A string!"]}>
+<WidgetData|root={0:[0x4100,0,2,1],1:["bar","msg"]}>
+<WidgetData|bar={0:[0x4100,0,1,2],1:["menu","blank"]}>
+<WidgetData|menu={0:[0x2031,0x4011,0],1:["imde.menu"]}>
+<WidgetData|msg={0:[0x21,0x90D970],1:["A string!"]}>
+<WidgetData|blank={0:[0x2]}>
--- a/mde/gui/WidgetManager.d	Sat Dec 20 17:57:05 2008 +0000
+++ b/mde/gui/WidgetManager.d	Sun Dec 21 12:03:50 2008 +0000
@@ -523,10 +523,6 @@
         debug (mdeWidgets) logger.trace ("Creating widget \""~id~'"');
         return createWidget (this, id, curData[id], content);
     }
-    override IChildWidget makeWidget (widgetID id, WidgetData data, IContent content = null) {
-	debug (mdeWidgets) logger.trace ("Creating widget \""~id~'"');
-	return createWidget (this, id, data, content);
-    }
     
     override wdims dimData (widgetID id) {
         return curData.dims (id);
--- a/mde/gui/widget/Ifaces.d	Sat Dec 20 17:57:05 2008 +0000
+++ b/mde/gui/widget/Ifaces.d	Sun Dec 21 12:03:50 2008 +0000
@@ -58,12 +58,8 @@
      *  content = An IContent may be passed to some widgets on creation.
      *
      * Creates a widget, using the widget data with index id. Widget data is loaded from files,
-     * and per design (multiple gui layouts, called designs, may exist; data is per design).
-     * 
-     * The function taking a WidgetData is intended for modifier functions and only exists to
-     * avoid circular dependencies between the modifier function's module and createWidget. */
+     * and per design (multiple gui layouts, called designs, may exist; data is per design). */
     IChildWidget makeWidget (widgetID id, IContent content = null);
-    IChildWidget makeWidget (widgetID id, WidgetData data, IContent content = null);
     
     /** Get dimension data for a widget. */
     wdims dimData (widgetID id);
--- a/mde/gui/widget/createWidget.d	Sat Dec 20 17:57:05 2008 +0000
+++ b/mde/gui/widget/createWidget.d	Sun Dec 21 12:03:50 2008 +0000
@@ -20,8 +20,9 @@
 module mde.gui.widget.createWidget;
 
 import mde.gui.widget.Ifaces;
-import mde.gui.exception : WidgetDataException;
+import mde.gui.exception;
 import mde.content.Content;
+import Items = mde.content.Items;
 
 // Widgets to create:
 import mde.gui.widget.layout;
@@ -31,6 +32,7 @@
 import mde.gui.widget.textContent;
 import mde.gui.widget.Floating;
 import mde.gui.widget.PopupMenu;
+
 import tango.util.log.Log : Log, Logger;
 
 private Logger logger;
@@ -71,22 +73,29 @@
     return new DebugWidget (mgr, id, data);
 }
 
-/+ for converting to a char[] name (unused)
-static this() {
-    WIDGET_NAMES = [
-            FixedBlank : "FixedBlank",
-            SizableBlank : "SizableBlank",
-            Button : "Button",
-            GridLayout : "GridLayout"
-                    ];
-}+/
+/*************************************************************************************************
+ * A function which uses Items.get (data.strings[0]) to get a content and creates a widget from
+ * data.ints[1]. The first item in each ints and strings is removed before passing data to the new
+ * widget.
+ * 
+ * The function only takes an IContent parameter to satisfy createWidget; it's value is ignored.
+ * 
+ * Circularly depends on createWidget, so should be in this module.
+ *************************************************************************************************/
+IChildWidget addContent (IWidgetManager mgr, widgetID id, WidgetData data, IContent) {
+    if (data.ints.length < 2 || data.strings.length < 1) throw new WidgetDataException;
+    char[] cItem = data.strings[0];
+    data.strings = data.strings[1..$];
+    data.ints    = data.ints   [1..$];
+    return createWidget (mgr, id, data, Items.get (cItem));
+}
 
 private:
 /// Widget types.
 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.
-    PARENT		= 0x8000,   // widget can have children; not used by code (except in data files)
+    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
@@ -97,15 +106,14 @@
     Debug		= 0xF,
     
     // buttons: 0x10
-    Button		= 0x10,
-    PopupMenu		= TAKES_CONTENT | PARENT | 0x11,
+    PopupMenu		= TAKES_CONTENT | 0x11,
     
     // labels: 0x20
     ContentLabel	= TAKES_CONTENT | 0x20,
     TextLabel		= 0x21,
     
     // content functions: 0x30
-    editContent		= FUNCTION | TAKES_CONTENT | 0x30,
+    editContent		= FUNCTION | TAKES_CONTENT | SAFE_RECURSION | 0x30,
     addContent		= FUNCTION | 0x31,
     
     // content widgets: 0x40
@@ -113,12 +121,11 @@
     BoolContent		= TAKES_CONTENT | 0x41,
     AStringContent	= TAKES_CONTENT | 0x42,
     ButtonContent	= TAKES_CONTENT | 0x43,
-    //EnumContent	= TAKES_CONTENT | 0x44,
     
-    GridLayout		= TAKES_CONTENT | PARENT | 0x100,
-    ContentList		= TAKES_CONTENT | PARENT | 0x110,
+    GridLayout		= TAKES_CONTENT | 0x100,
+    ContentList		= TAKES_CONTENT | SAFE_RECURSION | 0x110,
     
-    FloatingArea	= PARENT | 0x200,
+    FloatingArea	= 0x200,
 }
 
 //const char[][int] WIDGET_NAMES;
@@ -128,20 +135,18 @@
         "FixedBlank",
         "SizableBlank",
         "Debug",
-        "Button",
 	"TextLabel",
+	"FloatingArea",
 	"addContent",
+	"PopupMenu",
 	"ContentLabel",
         "DisplayContent",
         "BoolContent",
 	"AStringContent",
 	"ButtonContent",
-	//"EnumContent",
-        "editContent",
-        "FloatingArea",
-	"PopupMenu",
-        "GridLayout",
-	"ContentList"];
+	"GridLayout",
+	"ContentList",
+	"editContent"];
 
 /* Generates a binary search algorithm. */
 char[] binarySearch (char[] var, char[][] consts) {
@@ -154,15 +159,20 @@
     } else {
         char[] ret;
         foreach (c; consts) {
-            ret ~=  "if (" ~ var ~ " == WIDGET_TYPE." ~ c ~ ") {\n" ~
-                    "   debug (mdeWidgets) logger.trace (\"Creating new "~c~"Widget.\");\n" ~
-                    "   static if (WIDGET_TYPE."~c~" & WIDGET_TYPE.FUNCTION)\n" ~
-                    "       return " ~ c ~ " (mgr, id, data, content);\n" ~
-                    "   else static if (WIDGET_TYPE."~c~" & WIDGET_TYPE.TAKES_CONTENT)\n" ~
-                    "       return new " ~ c ~ "Widget (mgr, id, data, content);\n" ~
-                    "   else\n" ~
-                    "       return new " ~ c ~ "Widget (mgr, id, data);\n" ~
-                    "} else ";
+            ret ~= "if (" ~ var ~ " == WIDGET_TYPE." ~ c ~ ") {\n"~
+                      /+if ((WIDGET_TYPE."~c~" & WIDGET_TYPE.SAFE_RECURSION) ||
+			  "not being recursed (no parent with same id)") {\n
+                    	For recursion detection; would probably work with above check and some modification to widgets. +/
+                       "debug (mdeWidgets) logger.trace (\"Creating new "~c~"Widget.\");\n
+                        static if (WIDGET_TYPE."~c~" & WIDGET_TYPE.FUNCTION)\n
+                          return " ~ c ~ " (mgr, id, data, content);\n
+                        else static if (WIDGET_TYPE."~c~" & WIDGET_TYPE.TAKES_CONTENT)\n
+                          return new " ~ c ~ "Widget (mgr, id, data, content);\n
+                        else\n
+                          return new " ~ c ~ "Widget (mgr, id, data);\n"~
+                      /+} else
+                    	throw new GuiException (\"Widget not safe to be recursed: "~c~"\");+/
+                   "} else ";
         }
         ret = ret[0..$-6] ~ '\n';  // remove last else
         return ret;
--- a/mde/gui/widget/miscContent.d	Sat Dec 20 17:57:05 2008 +0000
+++ b/mde/gui/widget/miscContent.d	Sun Dec 21 12:03:50 2008 +0000
@@ -27,7 +27,6 @@
 import mde.gui.renderer.IRenderer;
 import mde.content.AStringContent;
 import mde.content.miscContent;
-import Items = mde.content.Items;
 
 debug {
     import tango.util.log.Log : Log, Logger;
@@ -38,27 +37,13 @@
 }
 
 /*************************************************************************************************
- * A function which uses Items.get (data.strings[0]) to get a content and creates a widget from
- * data.ints[1]. The first item in each ints and strings is removed before passing data to the new
- * widget.
- * 
- * The function only takes an IContent parameter to satisfy createWidget; it's value is ignored.
- *************************************************************************************************/
-IChildWidget addContent (IWidgetManager mgr, widgetID id, WidgetData data, IContent) {
-    if (data.ints.length < 2 || data.strings.length < 1) throw new WidgetDataException;
-    char[] cItem = data.strings[0];
-    data.strings = data.strings[1..$];
-    data.ints    = data.ints   [1..$];
-    return mgr.makeWidget (id, data, Items.get (cItem));
-}
-
-/*************************************************************************************************
  * A function which returns the most appropriate content editing widget.
  *
  * Widgets which can be returned: BoolContentWidget (toggle button), ValueContentWidget (generic
  * text-box editor), DisplayContentWidget (generic text label).
  *************************************************************************************************/
 IChildWidget editContent (IWidgetManager mgr, widgetID id, WidgetData data, IContent c) {
+    // Note: SAFE_RECURSION enabled
     if (c is null) throw new ContentException;
     else if (cast(AStringContent) c) {
         if (cast(EnumContent) c)	// can be PopupMenuWidget or ContentListWidget
--- a/mde/gui/widget/miscWidgets.d	Sat Dec 20 17:57:05 2008 +0000
+++ b/mde/gui/widget/miscWidgets.d	Sun Dec 21 12:03:50 2008 +0000
@@ -20,7 +20,12 @@
 import mde.gui.exception;
 import mde.gui.renderer.IRenderer;
 
-import tango.io.Stdout;
+import tango.util.log.Log : Log, Logger;
+
+private Logger logger;
+static this () {
+    logger = Log.getLogger ("mde.gui.widget.miscWidgets");
+}
 
 
 /// A fixed-size blank widget.
@@ -58,14 +63,7 @@
 {
     this (IWidgetManager mgr, widgetID id, WidgetData data) {
         super (mgr, id, data);
-        
-        Stdout ("Debug widget - parameters: int: [");
-        foreach (x; data.ints)
-            Stdout (" ")(x);
-        Stdout (" ], char[]: [");
-        foreach (x; data.strings)
-            Stdout (" \"")(x)('"');
-        Stdout (" ]").newline;
+        logger.warn ("Debug widget - parameters: ints = {}, strings = {}", data.ints, data.strings);
     }
     
     override void draw () {
@@ -74,18 +72,3 @@
         mgr.renderer.drawBlank (x,y, w,h);
     }
 }
-
-/// First interactible widget
-class ButtonWidget : AButtonWidget
-{
-    this (IWidgetManager mgr, widgetID id, WidgetData data) {
-        WDCheck (data, 3);
-        w = mw = cast(wdim) data.ints[1];
-        h = mh = cast(wdim) data.ints[2];
-        super (mgr, id, data);
-    }
-    
-    override void activated () {
-        Stdout ("Button clicked!").newline;
-    }
-}
--- a/mde/setup/Screen.d	Sat Dec 20 17:57:05 2008 +0000
+++ b/mde/setup/Screen.d	Sun Dec 21 12:03:50 2008 +0000
@@ -56,7 +56,7 @@
     /** Init function to initialize SDL. */
     StageState init () {      // init func
         // Initialise SDL
-        debug logger.trace ("Calling SDL_Init (SDL_INIT_VIDEO | SDL_INIT_JOYSTICK)");
+        debug (SDLCalls) logger.trace ("Calling SDL_Init (SDL_INIT_VIDEO | SDL_INIT_JOYSTICK)");
         if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_JOYSTICK /+| SDL_INIT_EVENTTHREAD+/)) {
             logger.fatal ("SDL initialisation failed:");
             char* msg = SDL_GetError ();
@@ -68,7 +68,7 @@
     }
     /** SDL shutdown */
     StageState cleanup () {
-        debug logger.trace ("Calling SDL_Quit ()");
+        debug (SDLCalls) logger.trace ("Calling SDL_Quit ()");
         SDL_Quit();
         return StageState.INACTIVE;
     }
@@ -214,7 +214,7 @@
         }
         
         //debug logger.trace ("Setting video mode {}x{}, 32-bit, flags: {}", w,h,flags);
-        debug logger.trace ("Calling SDL_SetVideoMode ({}, {}, 32, 0x{:x})", w,h, flags);
+        debug (SDLCalls) logger.trace ("Calling SDL_SetVideoMode ({}, {}, 32, 0x{:x})", w,h, flags);
         if (SDL_SetVideoMode (w, h, 32, flags) is null) {
             logger.fatal ("Unable to set video mode:");
             char* msg = SDL_GetError ();