Mercurial > projects > mde
diff mde/gui/widget/layout.d @ 111:1655693702fc
Resolved ticket #4, allowing widgets to reload strings and recalculate sizes mid-run.
Removed prefinalize and finalize and added setup as the new second initialization phase, which can be re-run.
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Sat, 06 Dec 2008 17:41:42 +0000 |
parents | 2a1428ec5344 |
children | fe061009029d |
line wrap: on
line diff
--- a/mde/gui/widget/layout.d Fri Dec 05 11:29:39 2008 +0000 +++ b/mde/gui/widget/layout.d Sat Dec 06 17:41:42 2008 +0000 @@ -152,57 +152,58 @@ * the call to genCachedConstructionData can be moved to the derived this() methods.) * * Derived constructors may also set initWidths to the array of column widths followed by - * row heights used to initially set the row/column dimensions. - * - * Sub-widgets are finalized here, so no methods should be called on sub-widgets before calling - * this super. */ + * row heights used to initially set the row/column dimensions. */ protected this (IWidgetManager mgr, widgetID id, WidgetData data) { super (mgr, id, data); // Create cell aligners with appropriate col/row adjustment function if (data.ints[1] & 1) - col = AlignColumns.getInstance (id, cols); - else - col = (new AlignColumns (cols)); - col.addSetCallback (&setColWidth); - if (data.ints[1] & 2) - row = AlignColumns.getInstance (id~"R", rows); // id must be unique to that for cols! + col = AlignColumns.getInstance (id, cols); else - row = (new AlignColumns (rows)); - row.addSetCallback (&setRowHeight); + col = (new AlignColumns (cols)); + col.addCallbacks (&setColWidth, &setupAlignDimData); + if (data.ints[1] & 2) + row = AlignColumns.getInstance (id~"R", rows); // id must be unique to that for cols! + else + row = (new AlignColumns (rows)); + row.addCallbacks (&setRowHeight, &setupAlignDimData); useSpacing = (data.ints[1] & 4) != 0; } - /** Prior to finalizing but after sub-widgets are finalized, some information needs to be - * passed to the AlignColumns. */ - void prefinalize () { - genCachedConstructionData; // min widths, sizableness - } - /** Responsible for calculating the minimal size and initializing some stuff. * * As such, this must be the first function called after this(). */ - void finalize () { - if (initWidths.length == cols + rows) { - col.setWidths (initWidths[0..cols]); - row.setWidths (initWidths[cols..$]); - } else { - col.setWidths; - row.setWidths; - } - initWidths = null; // free - - mw = col.mw; - mh = row.mw; - w = col.w; - h = row.w; - - // Tell subwidgets their new sizes. Positions are given by a later call to setPosition. - 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); - } + bool setup (uint n, uint flags) { + // Run all internal calculations regardless of changes, then check dimensions for changes. + // Don't try shortcutting internal calculations when there are no changes - I've tried, and + // doing so adds enough overhead to make doing so almost(?) worthless (or at least large + // increases in complexity). + wdim ow = w, oh = h; + + col.setup (n, flags); + row.setup (n, flags); + + if (initWidths.length == cols + rows) { + col.setWidths (initWidths[0..cols]); + row.setWidths (initWidths[cols..$]); + } else { + col.setWidths; + row.setWidths; + } + initWidths = null; // free + + mw = col.mw; + mh = row.mw; + w = col.w; + h = row.w; + + // Tell subwidgets their new sizes. Positions are given by a later call to setPosition. + 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 (ow != w || oh != h); } //END Creation & saving @@ -284,26 +285,34 @@ package: /* Calculations which need to be run whenever a new sub-widget structure is set - * (i.e. to produce cached data calculated from construction data). - * Also need to be re-run if the renderer changes. + * or other changes affecting widget sizes. Most of these need to happen regardless of whether + * changes have occurred, since AlignColumns have been reset. * * rows, cols and subWidgets must be set before calling. Part of the set-up for AlignColumns * (col and row). subWidgets need to know their minimal size and resizability. */ - void genCachedConstructionData () { - // Will only change if renderer changes: - // NOTE shared AlignColumns get this set by all sharing GridWidgets + void setupAlignDimData (uint n, uint flags) { + if (sADD_n == n) return; // cached data is current + sADD_n = n; + + foreach (widg; subWidgets) // make sure all subwidgets have been set up + widg.setup (n,flags); + // make sure both AlignColumns are set up (since first call to setup(n) calls reset): + col.setup (n, flags); + row.setup (n, flags); + + // Note: shared AlignColumns get this set by all sharing GridWidgets col.spacing = row.spacing = useSpacing ? mgr.renderer.layoutSpacing : 0; // Calculate the minimal column and row sizes: // AlignColumns (row, col) takes care of initializing minWidth. foreach (i,widget; subWidgets) { // Increase dimensions if current minimal size is larger: - myIt n = i % cols; // column + myIt j = i % cols; // column wdim md = widget.minWidth; - if (col.minWidth[n] < md) col.minWidth[n] = md; - n = i / cols; // row + if (col.minWidth[j] < md) col.minWidth[j] = md; + j = i / cols; // row md = widget.minHeight; - if (row.minWidth[n] < md) row.minWidth[n] = md; + if (row.minWidth[j] < md) row.minWidth[j] = md; } // Find which cols/rows are resizable: @@ -370,7 +379,8 @@ myIt cols, rows; // number of cells in grid wdim[] initWidths; // see this / setInitialSize - bool useSpacing; // true if spacing should be applied + uint sADD_n = uint.max; // param n of last setup call after setupAlignDimData has run + bool useSpacing; // add inter-row/col spacing? /* All widgets in the grid, by row. Order: [ 0 1 ] * [ 2 3 ] */ @@ -417,18 +427,31 @@ * After creation, minimal widths should be set for all columns (minWidth) and * setWidths must be called before other functions are used. */ this (myIt columns) { - reset (columns); + if (columns < 1) + throw new GuiException("AlignColumns: created with <1 column (code error)"); + minWidth.length = columns; + sizable.length = columns; + } + + /** Like IChildWidget's setup; calls sADD delegates. */ + void setup (uint n, uint flags) { + if (n != setup_n) { + logger.trace ("AlignColumns.setup ({}): {}", n, cast(void*)this); + setup_n = n; + setupWidths = false; + reset (minWidth.length); + + foreach (dg; sADD) + dg (n, flags); // set flag 1 + } } /** Reset all column information (only keep set callbacks). * * Widths should be set after calling, as on creation. */ void reset (myIt columns) { - if (columns < 1) - throw new GuiException("AlignColumns: created with <1 column (code error)"); - minWidth = new wdim[columns]; - sizable = new bool[columns]; - width = null; // enforce calling setWidths after this + minWidth[] = 0; + sizable[] = false; firstSizable = -1; lastSizable = -1; } @@ -438,11 +461,14 @@ * Also calculates first/lastSizable from sizable, overall minimal width and column positions. */ void setWidths (wdim[] data = null) { - if (!width) { - if (data) { - debug assert (data.length == minWidth.length, "setWidths called with bad data length (code error)"); - width = data.dup; // data is shared by other widgets with same id so must be .dup'ed - // And check sizes are valid: + if (!setupWidths) { + logger.trace ("setWidths"); + setupWidths = true; + if (data || width) { // use existing/external data: need to check validity + if (data) { + assert (data.length == minWidth.length, "setWidths called with bad data length (code error)"); + width = data.dup; // data is shared by other widgets with same id so must be .dup'ed + } foreach (i, m; minWidth) { if (!sizable[i] || width[i] < m) // if width is fixed or less than minimum width[i] = m; @@ -474,13 +500,12 @@ } } - /** Add a callback to be called to notify changes in a column's width. - * - * All callbacks added are called on a width change so that multiple objects may share a - * CellAlign object. */ - typeof(this) addSetCallback (void delegate (myIt,wdim,int) setCW) { - assert (setCW, "CellAlign.this: setCW is null (code error)"); + /** Add a callback to be called to notify changes in a column's width, and the sADD callback. + */ + typeof(this) addCallbacks (void delegate (myIt,wdim,int) setCW, void delegate (uint,uint) sDg) { + assert (setCW && sDg, "AlignColumns.addCallbacks: null callback (code error)"); setWidthCb ~= setCW; + sADD ~= sDg; return this; } @@ -669,6 +694,10 @@ myDiff firstSizable = -1, lastSizable = -1; // set by calcFLSbl // Callbacks used to actually adjust a column's width: void delegate (myIt,wdim,int) setWidthCb[]; // set width of a column, with resize direction + void delegate (uint,uint) sADD[]; // setupAlignDimData dlgs + + uint setup_n = uint.max; // param n of last setup call + bool setupWidths; // setWidths has been run static HashMap!(widgetID,AlignColumns) instances; static this () {