# HG changeset patch # User Diggory Hardy # Date 1211457107 -3600 # Node ID 03fa79a48c4874ab257f69e93ece4132592de0de # Parent 0fd51d2c6c8a82a6d0ffc1a3e75241a45009db85 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 diff -r 0fd51d2c6c8a -r 03fa79a48c48 codeDoc/jobs.txt --- a/codeDoc/jobs.txt Thu May 22 11:34:09 2008 +0100 +++ b/codeDoc/jobs.txt Thu May 22 12:51:47 2008 +0100 @@ -56,6 +56,3 @@ Done (for git log message): -Moved the implementable widgets from mde.gui.widget.Widget to miscWidgets, leaving base widgets in Widget. -Rewrote some of GridLayoutWidget's implementation. Made many operations general to work for either columns or rows. Some optimisations were intended but ended up being removed due to problems. -Allowed layout's to resize from either direction (only with window resizes). diff -r 0fd51d2c6c8a -r 03fa79a48c48 data/conf/gui.mtt --- a/data/conf/gui.mtt Thu May 22 11:34:09 2008 +0100 +++ b/data/conf/gui.mtt Thu May 22 12:51:47 2008 +0100 @@ -11,4 +11,4 @@ {WEmbedded} - + diff -r 0fd51d2c6c8a -r 03fa79a48c48 mde/gui/widget/Ifaces.d --- a/mde/gui/widget/Ifaces.d Thu May 22 11:34:09 2008 +0100 +++ b/mde/gui/widget/Ifaces.d Thu May 22 12:51:47 2008 +0100 @@ -21,7 +21,12 @@ /** Interface for Window, allowing widgets to call some of Window's methods. * - * Contains the methods in Window available for widgets to call on their root. */ + * Contains the methods in Window available for widgets to call on their root. + * + * Notation: + * Positive/negative direction: along the x/y axis in this direction. + * Layout widget: a widget containing multiple sub-widges (which hence controls how they are laid + * out). */ interface IWindow : IWidget { /** Widget ID type. Each ID is unique under this window. @@ -119,9 +124,12 @@ /** Used to adjust the size. * - * w,h is the new size. The boolean parameters describe which direction to resize from and is - * only really relevent to layout widgets (see GridLayoutWidget's implementation). When - * calling, just past true,true if it doesn't matter. + * Params: + * nw/nh = The new width/height + * dir = Direction to resize from. This is only really applicable to layout widgets. + * It must be either -1 (start resizing from highest row/col index, decreasing the + * index as necessary), or +1 (resize from the lowest index, i.e. 0). + * Most widgets can simply ignore it. * * Implementation: * The size should be clamped to the widget's minimal size, i.e. the size set may be larger @@ -130,8 +138,10 @@ * This should be true for both resizable and fixed widgets; fixed widgets may still be scaled * to fill a whole row/column in a layout widget. * - * If the actual size is needed, call getCurrentSize afterwards. */ - void setSize (int w, int h, bool, bool); + * If the actual size is needed, call getCurrentSize afterwards. setPosition must be called + * afterwards if the widget might be a layout widget. */ + void setWidth (int nw, int dir); + void setHeight (int nh, int dir); /// ditto /** Set the current position (i.e. called on init and move). */ void setPosition (int x, int y); diff -r 0fd51d2c6c8a -r 03fa79a48c48 mde/gui/widget/Widget.d --- a/mde/gui/widget/Widget.d Thu May 22 11:34:09 2008 +0100 +++ b/mde/gui/widget/Widget.d Thu May 22 12:51:47 2008 +0100 @@ -40,7 +40,8 @@ // Most widgets don't need to do adjustments based on mutable data, however they usually do // still need to set their size. int[] adjust (int[] data) { - setSize (0,0,true,true); + setWidth (0,-1); + setHeight (0,-1); return data; } @@ -72,8 +73,10 @@ /* Set size: minimal size is (mw,mh). Note that both resizable and fixed widgets should allow * enlarging, so in both cases this is a correct implementation. */ - void setSize (int nw, int nh, bool, bool) { + void setWidth (int nw, int) { w = (nw >= mw ? nw : mw); + } + void setHeight (int nh, int) { h = (nh >= mh ? nh : mh); } diff -r 0fd51d2c6c8a -r 03fa79a48c48 mde/gui/widget/Window.d --- a/mde/gui/widget/Window.d Thu May 22 11:34:09 2008 +0100 +++ b/mde/gui/widget/Window.d Thu May 22 12:51:47 2008 +0100 @@ -86,6 +86,11 @@ widgetY = y + border.t; // must be updated if the window is moved widget.setPosition (widgetX, widgetY); + // Calculate mw/mh and xw/yh (cached data): + widget.getMinimalSize (mw, mh); + mw += border.l + border.r; + mh += border.t + border.b; + xw = x+w; yh = y+h; } @@ -206,11 +211,7 @@ } void getMinimalSize (out int wM, out int hM) { - if (mh < 0) { // calculate if necessary - widget.getMinimalSize (mw, mh); - mw += border.l + border.r; - mh += border.t + border.b; - } + // mw/mh are calculated by finalise(); wM = mw; hM = mh; } @@ -219,17 +220,17 @@ ch = h; } - void setSize (int nw, int nh, bool wB, bool hB) { - getMinimalSize (w,h); - if (nw > w) w = nw; // expand if new size is larger, but don't go smaller - if (nh > h) h = nh; - - xw = x+w; - yh = y+h; - - widget.setSize (w - border.l - border.r, h - border.t - border.b, wB, hB); - - gui_.requestRedraw (); // obviously necessary whenever the window's size is changed + void setWidth (int nw, int dir) { + if (nw < mw) w = mw; // clamp + else w = nw; + xw = x + w; + widget.setWidth (w - border.l - border.r, dir); + } + void setHeight (int nh, int dir) { + if (nh < mh) h = mh; // clamp + else h = nh; + yh = y + h; + widget.setHeight (h - border.t - border.b, dir); } void setPosition (int nx, int ny) { @@ -244,7 +245,7 @@ widget.setPosition (widgetX, widgetY); - gui_.requestRedraw (); // obviously necessary whenever the window is moved + gui_.requestRedraw (); // necessary whenever the window is moved; setPosition is called after resizes and moves } IWidget getWidget (int cx, int cy) { @@ -307,35 +308,31 @@ logger.trace ("resizeCallback: failure"); // This function is only called if some resize is going to happen. - // To improve efficiency, store parameters to resize to. - int xSize = w, ySize = h; // new size - int xDiff, yDiff; // difference to new position - bool xHigh, yHigh; // resize from positive side + // x,y are used as parameters to setPosition as well as being affected by it; somewhat + // pointless but fairly effective. if (resizeType & RESIZE_TYPE.L) { - getMinimalSize (xDiff, xSize); // (only want xDiff, temporarily used as mw) - xSize = xDrag - cx; - if (xSize < xDiff) xSize = xDiff; // clamp - xDiff = w - xSize; // now used as amount to move + int xSize = xDrag - cx; + if (xSize < mw) xSize = mw; // clamp + x += w - xSize; + setWidth (xSize, 1); } else if (resizeType & RESIZE_TYPE.R) { - xSize = xDrag + cx; - xHigh = true; + setWidth (xDrag + cx, -1); } if (resizeType & RESIZE_TYPE.T) { - getMinimalSize (ySize, yDiff); - ySize = yDrag - cy; - if (ySize < yDiff) ySize = yDiff; - yDiff = h - ySize; + int ySize = yDrag - cy; + if (ySize < mh) ySize = mh; + y += h - ySize; + setHeight (ySize, 1); } else if (resizeType & RESIZE_TYPE.B) { - ySize = yDrag + cy; - yHigh = true; + setHeight (yDrag + cy, -1); } - setSize (xSize, ySize, xHigh, yHigh); - if (xDiff != 0 || yDiff != 0) - setPosition (x + xDiff, y + yDiff); + // Moves lower (x,y) coordinate if necessary and repositions any sub-widgets moved by the + // resizing: + setPosition (x, y); } bool endCallback (ushort cx, ushort cy, ubyte b, bool state) { if (b == 1 && state == false) { diff -r 0fd51d2c6c8a -r 03fa79a48c48 mde/gui/widget/layout.d --- 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; }