diff mde/gui/widget/layout.d @ 46:03fa79a48c48

Fixed resizing bugs in previous commit and made code cleaner and more efficient. setSize replaced by setWidth & setHeight. setPosition must be called after setWidth/Height. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Thu, 22 May 2008 12:51:47 +0100
parents 0fd51d2c6c8a
children d43523ed4b62
line wrap: on
line diff
--- a/mde/gui/widget/layout.d	Thu May 22 11:34:09 2008 +0100
+++ b/mde/gui/widget/layout.d	Thu May 22 12:51:47 2008 +0100
@@ -37,6 +37,7 @@
 * The grid has no border but has spacing between widgets. */
 class GridLayoutWidget : Widget
 {
+    //BEGIN Creation & saving
     this (IWindow wind, int[] data) {
         // Get grid size and check data
         // Check sufficient data for rows, cols, and at least one widget:
@@ -62,6 +63,10 @@
         genCachedConstructionData;
     }
     
+    /* This does two things:
+     * 1. Pass adjust data on to sub-widgets
+     * 2. Set the size, from the adjust data if possible
+     */
     int[] adjust (int[] data) {
         // Give all sub-widgets their data:
         foreach (widget; subWidgets)
@@ -89,9 +94,11 @@
         h = row.genPositions;
         
         // Tell subwidgets their new sizes. Positions are given by a later call to setPosition.
-        foreach (i,widget; subWidgets)
-            // Resizing direction is arbitrarily set to "high direction":
-            widget.setSize (col.width[i % cols], row.width[i / cols], true, true);
+        foreach (i,widget; subWidgets) {
+            // Resizing direction is arbitrarily set to negative:
+            widget.setWidth  (col.width[i % cols], -1);
+            widget.setHeight (row.width[i / cols], -1);
+        }
         
         return data[lenUsed..$];
     }
@@ -115,7 +122,9 @@
         ret ~= col.width ~ row.width;
         return ret;
     }
+    //END Creation & saving
     
+    //BEGIN Size & position
     bool isWSizable () {
         return col.firstSizable >= 0;
     }
@@ -129,28 +138,19 @@
         mh = this.mh;
     }
     
-    void setSize (int nw, int nh, bool wHigh, bool hHigh) {
-        debug scope (failure) {
-            char[128] tmp;
-                logger.trace ("setSize failed: hHigh = " ~ (hHigh ? "true" : "false"));
-                logger.trace (logger.format (tmp, "rows to resize: {}, {}", row.firstSizable, row.lastSizable));
-        }
-        // Optimisation (could easily be called with same sizes if a parent layout widget is
-        // resized, since many columns/rows may not be resized).
-        if (nw == w && nh == h) return;
+    void setWidth (int nw, int dir) {
+        if (nw == w) return;
+        
+        w += col.adjustCellSizes (nw - w, (dir == -1 ? col.lastSizable : col.firstSizable), dir);
         
-        // calculate the row/column sizes (and new positions)
-        if (wHigh)
-            w += col.adjustCellSizes (nw - w, col.lastSizable, -1);
-        else
-            w += col.adjustCellSizes (nw - w, col.firstSizable, 1);
-        if (hHigh)
-            h += row.adjustCellSizes (nh - h, row.lastSizable, -1);
-        else
-            h += row.adjustCellSizes (nh - h, row.firstSizable, 1);
+        // Note: setPosition must be called after!
+    }
+    void setHeight (int nh, int dir) {
+        if (nh == h) return;
         
-        // set the sub-widget's sizes & positions
-        setSubWidgetSP (wHigh, hHigh);
+        h += row.adjustCellSizes (nh - h, (dir == -1 ? row.lastSizable : row.firstSizable), dir);
+        
+        // Note: setPosition must be called after!
     }
     
     void setPosition (int x, int y) {
@@ -160,6 +160,7 @@
         foreach (i,widget; subWidgets)
             widget.setPosition (x + col.pos[i % cols], y + row.pos[i / cols]);
     }
+    //END Size & position
     
     
     // Find the relevant widget.
@@ -210,6 +211,8 @@
      * (i.e. to produce cached data calculated from construction data). */
     void genCachedConstructionData () {
         col.spacing = row.spacing = window.renderer.layoutSpacing;
+        col.setColWidth = &setColWidth;
+        row.setColWidth = &setRowHeight;
         
         // Calculate the minimal column and row sizes:
         // set length, making sure the arrays are initialised to zero:
@@ -269,21 +272,22 @@
                 row.firstSizable = row.lastSizable;
         }
     }
-    
-    // set sub-widgets size & position (done after resizing widget or rows/columns)
-    void setSubWidgetSP (bool wH, bool hH) {
-        for (myIt i = 0; i < cols; ++i)
-            for (myIt j = 0; j < rows; ++j)
-        {
-            IWidget widget = subWidgets[i + cols*j];
-            widget.setSize (col.width[i], row.width[j], wH, hH);
-            widget.setPosition (x + col.pos[i], y + row.pos[j]);
-        }
-    }
     //END Cache calculation functions
     
     
-    //BEGIN Col/row resizing
+    void setColWidth (myIt i, int w, int dir) {
+        for (myIt j = 0; j < rows; ++j) {
+            subWidgets[i + cols*j].setWidth (w, dir);
+        }
+    }
+    void setRowHeight (myIt j, int h, int dir) {
+        for (myIt i = 0; i < cols; ++i) {
+            subWidgets[i + cols*j].setHeight (h, dir);
+        }
+    }
+    
+    
+    //BEGIN Col/row resizing callback
     void resizeCallback (ushort cx, ushort cy) {
         col.resize (cx - dragX);
         row.resize (cy - dragY);
@@ -292,10 +296,9 @@
         dragX = cx;
         dragY = cy;
         
-        // NOTE: Resizing direction is set to "high direction" which isn't always going to be
-        // correct. A more accurate but more complex approach might be to get
-        // adjustCellSizes to do the work.
-        setSubWidgetSP (true, true);
+        foreach (i,widget; subWidgets)
+            widget.setPosition (x + col.pos[i % cols],
+                                y + row.pos[i / cols]);
         window.requestRedraw;
     }
     bool endCallback (ushort cx, ushort cy, ubyte b, bool state) {
@@ -309,7 +312,7 @@
 protected:
     // Data for resizing cols/rows:
     int dragX, dragY;	// coords where drag starts
-    //END Col/row resizing
+    //END Col/row resizing callback
     
     
     myIt cols, rows;	// number of cells in grid
@@ -334,6 +337,10 @@
         myDiff resizeD,	// resize down from this index (<0 if not resizing)
                resizeU;	// and up from this index
         int spacing;	// used by genPositions (which cannot access the layout class's data)
+        /* This is a delegate to a enclosing class's function, since:
+         * a different implementation is needed for cols or rows
+         * we're unable to access enclosing class members directly */
+        void delegate (myIt,int,int) setColWidth;	// set width of a column, with resize direction
         
         void dupMin () {
             width = minWidth.dup;
@@ -407,20 +414,25 @@
         *
         * Returns:
         *  The amount adjusted. This may be larger than diff, since cellD is clamped by cellDMin.
+        *
+        * Note: Check variable used for start is valid before calling! If a non-sizable column's
+        *  index is passed, this should get increased (if diff > 0) but not decreased.
         */
-        int adjustCellSizes (int diff, myDiff start, myDiff incr)
-        in {// Could occur if adjust isn't called first, but this would be a code error:
-            char[128] tmp;
-            logger.trace (logger.format (tmp, "start is {}", start));
+        int adjustCellSizes (int diff, myDiff start, int incr)
+        in {
+            // Could occur if adjust isn't called first, but this would be a code error:
             assert (width !is null, "adjustCellSizes: width is null");
+            // Most likely if passed negative when sizing is disabled:
             assert (start >= 0 && start < minWidth.length, "adjustCellSizes: invalid start");
             assert (incr == 1 || incr == -1, "adjustCellSizes: invalid incr");
+            assert (setColWidth !is null, "adjustCellSizes: setColWidth is null");
         } body {
             debug scope(failure)
                     logger.trace ("adjustCellSizes: failure");
             myDiff i = start;
             if (diff > 0) {		// increase size of first resizable cell
                 width[i] += diff;
+                setColWidth (i, width[i], incr);
             }
             else if (diff < 0) {	// decrease
                 int rd = diff;		// running diff
@@ -428,13 +440,17 @@
                 while (true) {
                     width[i] += rd;	// decrease this cell's size (but may be too much)
                     rd = width[i] - minWidth[i];
-                    if (rd >= 0)	// OK; we're done
+                    if (rd >= 0) {	// OK; we're done
+                        setColWidth (i, width[i], incr);	// set new width
                         break;		// we hit the mark exactly: diff is correct
+                    }
                     
                     // else we decreased it too much!
                     width[i] = minWidth[i];
+                    setColWidth (i, width[i], incr);
                     // rd is remainder to decrease by
                     
+                    
                     bool it = true;	// iterate (force first time)
                     while (it) {
                         i += incr;
@@ -468,6 +484,8 @@
     CellDimensions col, row;
     
     // Index types. Note that in some cases they need to hold negative values.
+    // Int is used for resizing direction (although ptrdiff_t would be more appropriate),
+    // since the value must always be -1 or +1 and int is smaller on X86_64.
     alias size_t myIt;
     alias ptrdiff_t myDiff;
 }