changeset 93:08a4ae11454b

Widgets now save dimensions without preventing structural changes in the base config file from applying. Widget dimensional data separated from other data in files, hence above change. Moved TextAdapter from TextWidget to IRenderer.
author Diggory Hardy <diggory.hardy@gmail.com>
date Tue, 21 Oct 2008 11:35:15 +0100
parents 085f2ca31914
children 9520cc0448e5
files data/conf/gui.mtt mde/gui/WidgetDataSet.d mde/gui/WidgetManager.d mde/gui/renderer/IRenderer.d mde/gui/renderer/SimpleRenderer.d mde/gui/types.d mde/gui/widget/Ifaces.d mde/gui/widget/TextWidget.d mde/gui/widget/Widget.d mde/gui/widget/layout.d
diffstat 10 files changed, 116 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/data/conf/gui.mtt	Tue Oct 21 09:57:19 2008 +0100
+++ b/data/conf/gui.mtt	Tue Oct 21 11:35:15 2008 +0100
@@ -4,7 +4,7 @@
 {Working}
 <WidgetData|root={0:[0xC100,0,3,3],1:["square","blank","square","blank","content","blank","square","blank","square"]}>
 <WidgetData|square={0:[0x1,6,6]}>
-<WidgetData|content={0:[0xC100,0,4,2],1:["floating","button","blank","blank","blank","opts","blank","blank"]}>
+<WidgetData|content={0:[0xC100,0,4,2],1:["floating","button","blank","blank","f2","opts","blank","blank"]}>
 <WidgetData|button={0:[0x10,50,50]}>
 <WidgetData|blank={0:[0x2]}>
 <WidgetData|opts={0:[0x8110,0],1:["optDBox"]}>
@@ -15,6 +15,7 @@
 <WidgetData|optVal={0:[0x4020, 0, 0xBF00]}>
 <WidgetData|optSep={0:[0x21, 0xff],1:["="]}>
 <WidgetData|floating={0:[0x8200,20,20],1:["text"]}>
+<WidgetData|f2={0:[0x8200,50,20],1:["button"]}>
 <WidgetData|text={0:[0x21,0xFF0000],1:["Floating text"]}>
 {Basic}
 <WidgetData|root={0:[0x21,0x90D970],1:["A string!"]}>
--- a/mde/gui/WidgetDataSet.d	Tue Oct 21 09:57:19 2008 +0100
+++ b/mde/gui/WidgetDataSet.d	Tue Oct 21 11:35:15 2008 +0100
@@ -50,6 +50,8 @@
         // Priority is HIGH_LOW. Only load tag if it doesn't already exist.
         if (tp == "WidgetData" && (id in widgetData) is null) {
             widgetData[id] = deserialize!(WidgetData) (dt);
+        } else if (tp == "WDims" && (id in dimData) is null) {
+            dimData[id] = cast(wdims) deserialize!(int[]) (dt);
         }
     }
     // Only WidgetDataChanges is used for writing.
@@ -66,8 +68,15 @@
         return *p;
     }
     
+    /** Get the widget dimensions for widget i (null if none). */
+    wdims dims (widgetID id) {
+        auto p = id in dimData;
+        return p ? *p : null;
+    }
+    
 protected:
-    WidgetData[widgetID] widgetData;    // Per-widget data:
+    WidgetData[widgetID] widgetData;    // Per-widget data
+    wdims[widgetID] dimData;            // Per-widget sizes
 }
 
 /*************************************************************************************************
@@ -90,6 +99,8 @@
     void writeAll (ItemDelg dlg) {
         foreach (id,data; widgetData)
             dlg ("WidgetData", id, serialize!(WidgetData) (data));
+        foreach (id,dim; dimData)
+            dlg ("WDims", id, serialize!(int[]) (cast(int[]) dim));
     }
     //END Mergetag code
     
@@ -100,6 +111,12 @@
         base.widgetData[i] = d;
     }
     
+    /** Set the widget dimensions for widget i. */
+    void setDims (widgetID id, wdims d) {
+        dimData[id] = d;
+        base.dimData[id] = d;
+    }
+    
     /** Do any changes exist? True if no changes have been stored. */
     bool none () {
         return widgetData.length == 0;
--- a/mde/gui/WidgetManager.d	Tue Oct 21 09:57:19 2008 +0100
+++ b/mde/gui/WidgetManager.d	Tue Oct 21 11:35:15 2008 +0100
@@ -333,7 +333,7 @@
         scope(exit) mutex.unlock;
         
         // Make all widgets save any changed data; return if no changes:
-        if (!child.saveChanges ("root"))
+        if (!child.saveChanges)
             return;
         
         if (loadUserFile) { // merge entries from user file into current changes
@@ -425,11 +425,21 @@
         }
     }
     
-    /** For making changes. */
+    /** Get dimension data for a widget. */
+    wdims dimData (widgetID id) {
+        return curData.dims (id);
+    }
+    
+    /** For making changes to widget structure. */
     void setData (widgetID id, WidgetData d) {
         changes[id] = d;        // also updates WidgetDataSet in data.
     }
     
+    /** For making changes to widget dimensions. */
+    void setDimData (widgetID id, wdims d) {
+        changes.setDims(id, d);    // also updates WidgetDataSet in data.
+    }
+    
     /** Second stage of loading the widgets.
     * 
     * loadDesign handles the data; this method needs to:
--- a/mde/gui/renderer/IRenderer.d	Tue Oct 21 09:57:19 2008 +0100
+++ b/mde/gui/renderer/IRenderer.d	Tue Oct 21 11:35:15 2008 +0100
@@ -17,6 +17,7 @@
 module mde.gui.renderer.IRenderer;
 
 public import mde.gui.types;
+import mde.font.font;
 
 /** Interface for renderers.
 *
@@ -90,5 +91,34 @@
     
     /** Draws a button frame, in if pushed == true. */
     void drawButton (wdim x, wdim y, wdim w, wdim h, bool pushed);
+    
+    /** Get a TextAdapter to draw some text. */
+    TextAdapter getAdapter (char[] text, int colour);
+    
+    /** For drawing text - one instance per string.
+     *
+     * NOTE: currently inflexible. Could use (function) pointers, class interfaces or struct
+     * interfaces when available to allow flexibility. */
+    struct TextAdapter {
+        void set (char[] c, int col) {
+            content = c;
+            colour = Colour (col);
+        }
+        
+        void getDimensions (out wdsize w, out wdsize h) {
+            font.updateBlock (content, textCache);
+            w = cast(wdim) textCache.w;
+            h = cast(wdim) textCache.h;
+        }
+        
+        void draw (wdabs x, wdabs y) {
+            font.textBlock (x,y, content, textCache, colour);
+        }
+        
+        char[] content;
+        TextBlock textCache;
+        Colour colour;
+        FontStyle font;
+    }
     //END draw routines
 }
--- a/mde/gui/renderer/SimpleRenderer.d	Tue Oct 21 09:57:19 2008 +0100
+++ b/mde/gui/renderer/SimpleRenderer.d	Tue Oct 21 11:35:15 2008 +0100
@@ -19,6 +19,7 @@
 import mde.gui.renderer.IRenderer;
 
 import gl = mde.gl.basic;
+import mde.font.font;
 
 /** Interface for renderers.
 *
@@ -29,6 +30,10 @@
 * The renderer is intended to be per-GUI. */
 class SimpleRenderer : IRenderer
 {
+    this () {
+        defaultFont = FontStyle.get("default");
+    }
+    
     BorderDimensions setSizable (bool wS, bool hS) {
         wSizable = wS;
         hSizable = hS;
@@ -114,8 +119,16 @@
         gl.drawBox (x,y, w,h);
     }
     
+    TextAdapter getAdapter (char[] text, int col) {
+        TextAdapter a;
+        a.font = defaultFont;
+        a.set (text, col);
+        return a;
+    }
+    
 protected:
     bool wSizable, hSizable;
     BorderDimensions border;
     BorderDimensions resize;
+    FontStyle defaultFont;
 }
--- a/mde/gui/types.d	Tue Oct 21 09:57:19 2008 +0100
+++ b/mde/gui/types.d	Tue Oct 21 11:35:15 2008 +0100
@@ -47,6 +47,9 @@
     wdim x, y;  /// data
 }
 
+/// Used to save column sizes, etc.
+alias wdim[] wdims;
+
 
 /*************************************************************************************************
 * The data type all widgets creatable by the widget manager receive on creation.
--- a/mde/gui/widget/Ifaces.d	Tue Oct 21 09:57:19 2008 +0100
+++ b/mde/gui/widget/Ifaces.d	Tue Oct 21 11:35:15 2008 +0100
@@ -61,9 +61,15 @@
      */
     IChildWidget makeWidget (widgetID id, IContent content = null);
     
+    /// Get dimensional data.
+    wdims dimData (widgetID id);
+    
     /** Record some changes, for saving. Should only be called from IWidget.saveChanges() to avoid
-     * multiple calls for instanced widgets of same id. */
+     * multiple calls for instanced widgets of same id.
+     * 
+     * WidgetData is for most data, dimensional data (wdims) is for dimensions. */
     void setData (widgetID id, WidgetData);
+    void setDimData (widgetID id, wdims d);     /// ditto
     
     // Rendering:
     /** For when a widget needs redrawing.
@@ -159,8 +165,7 @@
      * 
      * If the widget has subwidgets, it should also be recursively called on these (passing their 
      * ids). */
-    // FIXME - no longer necessary to pass id!
-    bool saveChanges (widgetID id);
+    bool saveChanges ();
     
     /** Called when the renderer is changed (at least when the changes affect dimensions).
      * Also called after widget creation, before any other methods are called.
--- a/mde/gui/widget/TextWidget.d	Tue Oct 21 09:57:19 2008 +0100
+++ b/mde/gui/widget/TextWidget.d	Tue Oct 21 11:35:15 2008 +0100
@@ -24,34 +24,6 @@
 import mde.gui.renderer.IRenderer;
 import mde.gui.content.Content;
 
-import mde.font.font;
-
-/// Adapter to ease use of ContentLabelWidget
-struct TextAdapter {
-    void set (char[] c, int col) {
-        //FIXME tie font to renderer or so
-        if (font is null) font = FontStyle.get("default");
-        
-        content = c;
-        colour = Colour (col);
-    }
-    
-    void getDimensions (out wdsize w, out wdsize h) {
-        font.updateBlock (content, textCache);
-        w = cast(wdim) textCache.w;
-        h = cast(wdim) textCache.h;
-    }
-    
-    void draw (wdabs x, wdabs y) {
-        font.textBlock (x,y, content, textCache, colour);
-    }
-    
-    char[] content;
-    TextBlock textCache;
-    Colour colour;
-    static FontStyle font;
-}
-
 /// Basic text widget
 class TextLabelWidget : Widget
 {
@@ -63,7 +35,7 @@
      * and colour is an 8-bit-per-channel RGB colour of the form 0xRRGGBB. */
     this (IWidgetManager mgr, widgetID id, WidgetData data) {
         WDCheck (data, 2, 1);
-        adapter.set (data.strings[0], data.ints[1]);
+        adapter = mgr.renderer.getAdapter (data.strings[0], data.ints[1]);
         adapter.getDimensions (mw, mh);
         super (mgr, id, data);
     }
@@ -74,7 +46,7 @@
     }
     
 protected:
-    TextAdapter adapter;
+    IRenderer.TextAdapter adapter;
 }
 
 /// Basic widget displaying a label from a content.
@@ -84,7 +56,7 @@
         WDCheck (data, 3, 0);
         content = c;
         index = data.ints[1];
-        adapter.set (content.toString(index), data.ints[2]);
+        adapter = mgr.renderer.getAdapter (content.toString(index), data.ints[2]);
         adapter.getDimensions (mw, mh);
         super (mgr, id,data);
     }
@@ -95,7 +67,7 @@
     }
     
 protected:
-    TextAdapter adapter;
+    IRenderer.TextAdapter adapter;
     IContent content;
     int index;
 }
--- a/mde/gui/widget/Widget.d	Tue Oct 21 09:57:19 2008 +0100
+++ b/mde/gui/widget/Widget.d	Tue Oct 21 11:35:15 2008 +0100
@@ -45,8 +45,9 @@
 {
 //BEGIN Load and save
     // Base this() for child Widgets.
-    this (IWidgetManager mgr, widgetID, WidgetData) {
+    this (IWidgetManager mgr, widgetID id, WidgetData) {
         this.mgr = mgr;
+        this.id = id;
     }
     
     // Most widgets don't need this; all initialization os usually done in this()
@@ -59,8 +60,7 @@
     }
     
     // Don't save any data: fine for many widgets.
-    // FIXME: implementation could be added to ParentWidget
-    bool saveChanges (widgetID) {
+    bool saveChanges () {
         return false;
     }
     
@@ -144,6 +144,7 @@
         throw new WidgetDataException (this);
     }
     
+    widgetID id;                // The widget's ID, used for saving data
     IWidgetManager mgr;		// the enclosing window
     wdim x, y;			// position
     wdim w, h;			// size
@@ -164,6 +165,13 @@
         return subWidgets;
     }
     
+    bool saveChanges () {
+        bool c = false;
+        foreach (w; subWidgets)
+            c |= w.saveChanges;
+        return c;
+    }
+    
 protected:
     IChildWidget[] subWidgets;
 }
--- a/mde/gui/widget/layout.d	Tue Oct 21 09:57:19 2008 +0100
+++ b/mde/gui/widget/layout.d	Tue Oct 21 11:35:15 2008 +0100
@@ -61,17 +61,13 @@
     this (IWidgetManager mgr, widgetID id, WidgetData data, IContent content) {
         // Get grid size and check data
         // Check sufficient data for type, align-flags, rows, cols, and possibly row/col widths.
-        if (data.ints.length < 4) throw new WidgetDataException (this);
+        if (data.ints.length != 4) throw new WidgetDataException (this);
         
         rows = data.ints[2];
         cols = data.ints[3];
-        // Check: at least one sub-widget, ints length == 3 or also contains row & col widths,
-        // strings' length is correct:
-        if (rows < 1 || cols < 1 ||
-            (data.ints.length != 4 && data.ints.length != 4 + rows + cols) ||
-            data.strings.length != rows * cols)
+        // Check: at least one sub-widget, ints length == 3, strings' length is correct:
+        if (rows < 1 || cols < 1 || data.ints.length != 4 || data.strings.length != rows * cols)
             throw new WidgetDataException (this);
-        this.data = data;
         
         // Get all sub-widgets
         subWidgets.length = rows*cols;
@@ -79,25 +75,20 @@
             subWidget = mgr.makeWidget (data.strings[i], content);
         }
         
-        if (data.ints.length == 4 + rows + cols)
-            initWidths = cast(wdim[]) data.ints[4..$];
+        initWidths = mgr.dimData (id);  // may be null, tested later
         
         super (mgr, id, data);
     }
     
     // Save column/row sizes. Currently always do so.
-    bool saveChanges (widgetID id) {
-        with (data) {
-            foreach (i, widget; subWidgets) // recurse on subwidgets
-                widget.saveChanges (strings[i]);
-            
-            ints = ints[0..4] ~ cast(int[])col.width ~ cast(int[])row.width;
-        }
-        mgr.setData (id, data);
+    bool saveChanges () {
+        foreach (widget; subWidgets) // recurse on subwidgets
+            widget.saveChanges ();
+        
+        mgr.setDimData (id, col.width ~ row.width);
         return true;
     }
 protected:
-    WidgetData data;
 }
 
 
@@ -114,26 +105,24 @@
         OptionList optsList = OptionList.trial();
         rows = optsList.list.length;
         cols = 1;
-        sWId = data.strings[0];
         
         // Get all sub-widgets
         subWidgets.length = rows*cols;
         foreach (i, c; optsList.list) {
-            subWidgets[i] = mgr.makeWidget (sWId, c);
+            subWidgets[i] = mgr.makeWidget (data.strings[0], c);
         }
         super (mgr, id, data);
     }
     
-    bool saveChanges (widgetID id) {
+    bool saveChanges () {
         // Since all sub-widgets have the same id, it only makes sense to call on one
         if (subWidgets is null)
             return false;
-        return subWidgets[0].saveChanges (sWId);
+        return subWidgets[0].saveChanges;
     }
     
 private:
     OptionList optsList;
-    widgetID sWId;      // sub-widget's ID, for calling saveChanges FIXME no longer pass?
 }
 
 
@@ -187,15 +176,15 @@
      *
      * As such, this must be the first function called after this(). */
     void finalize () {
-        if (initWidths) {
-            debug assert (initWidths.length == cols + rows, "initWidths provided but has bad length");
+        logger.trace ("initWidths.length: {}", initWidths.length);
+        if (initWidths.length == cols + rows) {
             col.setWidths (initWidths[0..cols]);
             row.setWidths (initWidths[cols..$]);
-            initWidths = null;  // free
         } else {
             col.setWidths;
             row.setWidths;
         }
+        initWidths = null;  // free
         
         mw = col.mw;
         mh = row.mw;