Mercurial > projects > mde
comparison 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 |
comparison
equal
deleted
inserted
replaced
110:6acd96f8685f | 111:1655693702fc |
---|---|
150 * Deriving classes should check data lengths, and set rows, cols, and the subWidgets array, | 150 * Deriving classes should check data lengths, and set rows, cols, and the subWidgets array, |
151 * before calling this super constructor. (If it's necessary to call super(...) first, | 151 * before calling this super constructor. (If it's necessary to call super(...) first, |
152 * the call to genCachedConstructionData can be moved to the derived this() methods.) | 152 * the call to genCachedConstructionData can be moved to the derived this() methods.) |
153 * | 153 * |
154 * Derived constructors may also set initWidths to the array of column widths followed by | 154 * Derived constructors may also set initWidths to the array of column widths followed by |
155 * row heights used to initially set the row/column dimensions. | 155 * row heights used to initially set the row/column dimensions. */ |
156 * | |
157 * Sub-widgets are finalized here, so no methods should be called on sub-widgets before calling | |
158 * this super. */ | |
159 protected this (IWidgetManager mgr, widgetID id, WidgetData data) { | 156 protected this (IWidgetManager mgr, widgetID id, WidgetData data) { |
160 super (mgr, id, data); | 157 super (mgr, id, data); |
161 | 158 |
162 // Create cell aligners with appropriate col/row adjustment function | 159 // Create cell aligners with appropriate col/row adjustment function |
163 if (data.ints[1] & 1) | 160 if (data.ints[1] & 1) |
164 col = AlignColumns.getInstance (id, cols); | 161 col = AlignColumns.getInstance (id, cols); |
165 else | 162 else |
166 col = (new AlignColumns (cols)); | 163 col = (new AlignColumns (cols)); |
167 col.addSetCallback (&setColWidth); | 164 col.addCallbacks (&setColWidth, &setupAlignDimData); |
168 if (data.ints[1] & 2) | 165 if (data.ints[1] & 2) |
169 row = AlignColumns.getInstance (id~"R", rows); // id must be unique to that for cols! | 166 row = AlignColumns.getInstance (id~"R", rows); // id must be unique to that for cols! |
170 else | 167 else |
171 row = (new AlignColumns (rows)); | 168 row = (new AlignColumns (rows)); |
172 row.addSetCallback (&setRowHeight); | 169 row.addCallbacks (&setRowHeight, &setupAlignDimData); |
173 useSpacing = (data.ints[1] & 4) != 0; | 170 useSpacing = (data.ints[1] & 4) != 0; |
174 } | 171 } |
175 | 172 |
176 /** Prior to finalizing but after sub-widgets are finalized, some information needs to be | |
177 * passed to the AlignColumns. */ | |
178 void prefinalize () { | |
179 genCachedConstructionData; // min widths, sizableness | |
180 } | |
181 | |
182 /** Responsible for calculating the minimal size and initializing some stuff. | 173 /** Responsible for calculating the minimal size and initializing some stuff. |
183 * | 174 * |
184 * As such, this must be the first function called after this(). */ | 175 * As such, this must be the first function called after this(). */ |
185 void finalize () { | 176 bool setup (uint n, uint flags) { |
186 if (initWidths.length == cols + rows) { | 177 // Run all internal calculations regardless of changes, then check dimensions for changes. |
187 col.setWidths (initWidths[0..cols]); | 178 // Don't try shortcutting internal calculations when there are no changes - I've tried, and |
188 row.setWidths (initWidths[cols..$]); | 179 // doing so adds enough overhead to make doing so almost(?) worthless (or at least large |
189 } else { | 180 // increases in complexity). |
190 col.setWidths; | 181 wdim ow = w, oh = h; |
191 row.setWidths; | 182 |
192 } | 183 col.setup (n, flags); |
193 initWidths = null; // free | 184 row.setup (n, flags); |
194 | 185 |
195 mw = col.mw; | 186 if (initWidths.length == cols + rows) { |
196 mh = row.mw; | 187 col.setWidths (initWidths[0..cols]); |
197 w = col.w; | 188 row.setWidths (initWidths[cols..$]); |
198 h = row.w; | 189 } else { |
199 | 190 col.setWidths; |
200 // Tell subwidgets their new sizes. Positions are given by a later call to setPosition. | 191 row.setWidths; |
201 foreach (i,widget; subWidgets) { | 192 } |
202 // Resizing direction is arbitrarily set to negative: | 193 initWidths = null; // free |
203 widget.setWidth (col.width[i % cols], -1); | 194 |
204 widget.setHeight (row.width[i / cols], -1); | 195 mw = col.mw; |
205 } | 196 mh = row.mw; |
197 w = col.w; | |
198 h = row.w; | |
199 | |
200 // Tell subwidgets their new sizes. Positions are given by a later call to setPosition. | |
201 foreach (i,widget; subWidgets) { | |
202 // Resizing direction is arbitrarily set to negative: | |
203 widget.setWidth (col.width[i % cols], -1); | |
204 widget.setHeight (row.width[i / cols], -1); | |
205 } | |
206 return (ow != w || oh != h); | |
206 } | 207 } |
207 //END Creation & saving | 208 //END Creation & saving |
208 | 209 |
209 //BEGIN Size & position | 210 //BEGIN Size & position |
210 bool isWSizable () { | 211 bool isWSizable () { |
282 mgr.renderer.drawSpacers (x,y, w,h, col.pos[1..$], row.pos[1..$]); | 283 mgr.renderer.drawSpacers (x,y, w,h, col.pos[1..$], row.pos[1..$]); |
283 } | 284 } |
284 | 285 |
285 package: | 286 package: |
286 /* Calculations which need to be run whenever a new sub-widget structure is set | 287 /* Calculations which need to be run whenever a new sub-widget structure is set |
287 * (i.e. to produce cached data calculated from construction data). | 288 * or other changes affecting widget sizes. Most of these need to happen regardless of whether |
288 * Also need to be re-run if the renderer changes. | 289 * changes have occurred, since AlignColumns have been reset. |
289 * | 290 * |
290 * rows, cols and subWidgets must be set before calling. Part of the set-up for AlignColumns | 291 * rows, cols and subWidgets must be set before calling. Part of the set-up for AlignColumns |
291 * (col and row). subWidgets need to know their minimal size and resizability. */ | 292 * (col and row). subWidgets need to know their minimal size and resizability. */ |
292 void genCachedConstructionData () { | 293 void setupAlignDimData (uint n, uint flags) { |
293 // Will only change if renderer changes: | 294 if (sADD_n == n) return; // cached data is current |
294 // NOTE shared AlignColumns get this set by all sharing GridWidgets | 295 sADD_n = n; |
296 | |
297 foreach (widg; subWidgets) // make sure all subwidgets have been set up | |
298 widg.setup (n,flags); | |
299 // make sure both AlignColumns are set up (since first call to setup(n) calls reset): | |
300 col.setup (n, flags); | |
301 row.setup (n, flags); | |
302 | |
303 // Note: shared AlignColumns get this set by all sharing GridWidgets | |
295 col.spacing = row.spacing = useSpacing ? mgr.renderer.layoutSpacing : 0; | 304 col.spacing = row.spacing = useSpacing ? mgr.renderer.layoutSpacing : 0; |
296 | 305 |
297 // Calculate the minimal column and row sizes: | 306 // Calculate the minimal column and row sizes: |
298 // AlignColumns (row, col) takes care of initializing minWidth. | 307 // AlignColumns (row, col) takes care of initializing minWidth. |
299 foreach (i,widget; subWidgets) { | 308 foreach (i,widget; subWidgets) { |
300 // Increase dimensions if current minimal size is larger: | 309 // Increase dimensions if current minimal size is larger: |
301 myIt n = i % cols; // column | 310 myIt j = i % cols; // column |
302 wdim md = widget.minWidth; | 311 wdim md = widget.minWidth; |
303 if (col.minWidth[n] < md) col.minWidth[n] = md; | 312 if (col.minWidth[j] < md) col.minWidth[j] = md; |
304 n = i / cols; // row | 313 j = i / cols; // row |
305 md = widget.minHeight; | 314 md = widget.minHeight; |
306 if (row.minWidth[n] < md) row.minWidth[n] = md; | 315 if (row.minWidth[j] < md) row.minWidth[j] = md; |
307 } | 316 } |
308 | 317 |
309 // Find which cols/rows are resizable: | 318 // Find which cols/rows are resizable: |
310 // AlignColumns initializes sizable, and sets first and last sizables. | 319 // AlignColumns initializes sizable, and sets first and last sizables. |
311 forCols: | 320 forCols: |
368 wdim dragX, dragY; // coords where drag starts | 377 wdim dragX, dragY; // coords where drag starts |
369 //END Col/row resizing callback | 378 //END Col/row resizing callback |
370 | 379 |
371 myIt cols, rows; // number of cells in grid | 380 myIt cols, rows; // number of cells in grid |
372 wdim[] initWidths; // see this / setInitialSize | 381 wdim[] initWidths; // see this / setInitialSize |
373 bool useSpacing; // true if spacing should be applied | 382 uint sADD_n = uint.max; // param n of last setup call after setupAlignDimData has run |
383 bool useSpacing; // add inter-row/col spacing? | |
374 | 384 |
375 /* All widgets in the grid, by row. Order: [ 0 1 ] | 385 /* All widgets in the grid, by row. Order: [ 0 1 ] |
376 * [ 2 3 ] */ | 386 * [ 2 3 ] */ |
377 //IChildWidget[] subWidgets; | 387 //IChildWidget[] subWidgets; |
378 | 388 |
415 * reset. | 425 * reset. |
416 * | 426 * |
417 * After creation, minimal widths should be set for all columns (minWidth) and | 427 * After creation, minimal widths should be set for all columns (minWidth) and |
418 * setWidths must be called before other functions are used. */ | 428 * setWidths must be called before other functions are used. */ |
419 this (myIt columns) { | 429 this (myIt columns) { |
420 reset (columns); | 430 if (columns < 1) |
431 throw new GuiException("AlignColumns: created with <1 column (code error)"); | |
432 minWidth.length = columns; | |
433 sizable.length = columns; | |
434 } | |
435 | |
436 /** Like IChildWidget's setup; calls sADD delegates. */ | |
437 void setup (uint n, uint flags) { | |
438 if (n != setup_n) { | |
439 logger.trace ("AlignColumns.setup ({}): {}", n, cast(void*)this); | |
440 setup_n = n; | |
441 setupWidths = false; | |
442 reset (minWidth.length); | |
443 | |
444 foreach (dg; sADD) | |
445 dg (n, flags); // set flag 1 | |
446 } | |
421 } | 447 } |
422 | 448 |
423 /** Reset all column information (only keep set callbacks). | 449 /** Reset all column information (only keep set callbacks). |
424 * | 450 * |
425 * Widths should be set after calling, as on creation. */ | 451 * Widths should be set after calling, as on creation. */ |
426 void reset (myIt columns) { | 452 void reset (myIt columns) { |
427 if (columns < 1) | 453 minWidth[] = 0; |
428 throw new GuiException("AlignColumns: created with <1 column (code error)"); | 454 sizable[] = false; |
429 minWidth = new wdim[columns]; | |
430 sizable = new bool[columns]; | |
431 width = null; // enforce calling setWidths after this | |
432 firstSizable = -1; | 455 firstSizable = -1; |
433 lastSizable = -1; | 456 lastSizable = -1; |
434 } | 457 } |
435 | 458 |
436 /** Initialize widths, either from minWidths or from supplied list, checking validity. | 459 /** Initialize widths, either from minWidths or from supplied list, checking validity. |
437 * | 460 * |
438 * Also calculates first/lastSizable from sizable, overall minimal width and column positions. | 461 * Also calculates first/lastSizable from sizable, overall minimal width and column positions. |
439 */ | 462 */ |
440 void setWidths (wdim[] data = null) { | 463 void setWidths (wdim[] data = null) { |
441 if (!width) { | 464 if (!setupWidths) { |
442 if (data) { | 465 logger.trace ("setWidths"); |
443 debug assert (data.length == minWidth.length, "setWidths called with bad data length (code error)"); | 466 setupWidths = true; |
444 width = data.dup; // data is shared by other widgets with same id so must be .dup'ed | 467 if (data || width) { // use existing/external data: need to check validity |
445 // And check sizes are valid: | 468 if (data) { |
469 assert (data.length == minWidth.length, "setWidths called with bad data length (code error)"); | |
470 width = data.dup; // data is shared by other widgets with same id so must be .dup'ed | |
471 } | |
446 foreach (i, m; minWidth) { | 472 foreach (i, m; minWidth) { |
447 if (!sizable[i] || width[i] < m) // if width is fixed or less than minimum | 473 if (!sizable[i] || width[i] < m) // if width is fixed or less than minimum |
448 width[i] = m; | 474 width[i] = m; |
449 } | 475 } |
450 } else | 476 } else |
472 } | 498 } |
473 } | 499 } |
474 } | 500 } |
475 } | 501 } |
476 | 502 |
477 /** Add a callback to be called to notify changes in a column's width. | 503 /** Add a callback to be called to notify changes in a column's width, and the sADD callback. |
478 * | 504 */ |
479 * All callbacks added are called on a width change so that multiple objects may share a | 505 typeof(this) addCallbacks (void delegate (myIt,wdim,int) setCW, void delegate (uint,uint) sDg) { |
480 * CellAlign object. */ | 506 assert (setCW && sDg, "AlignColumns.addCallbacks: null callback (code error)"); |
481 typeof(this) addSetCallback (void delegate (myIt,wdim,int) setCW) { | |
482 assert (setCW, "CellAlign.this: setCW is null (code error)"); | |
483 setWidthCb ~= setCW; | 507 setWidthCb ~= setCW; |
508 sADD ~= sDg; | |
484 return this; | 509 return this; |
485 } | 510 } |
486 | 511 |
487 /** Get the row/column of relative position l. | 512 /** Get the row/column of relative position l. |
488 * | 513 * |
667 wdim w,mw; // current & minimal widths | 692 wdim w,mw; // current & minimal widths |
668 /* indicies of the first/last resizable column (negative if none are resizable). */ | 693 /* indicies of the first/last resizable column (negative if none are resizable). */ |
669 myDiff firstSizable = -1, lastSizable = -1; // set by calcFLSbl | 694 myDiff firstSizable = -1, lastSizable = -1; // set by calcFLSbl |
670 // Callbacks used to actually adjust a column's width: | 695 // Callbacks used to actually adjust a column's width: |
671 void delegate (myIt,wdim,int) setWidthCb[]; // set width of a column, with resize direction | 696 void delegate (myIt,wdim,int) setWidthCb[]; // set width of a column, with resize direction |
697 void delegate (uint,uint) sADD[]; // setupAlignDimData dlgs | |
698 | |
699 uint setup_n = uint.max; // param n of last setup call | |
700 bool setupWidths; // setWidths has been run | |
672 | 701 |
673 static HashMap!(widgetID,AlignColumns) instances; | 702 static HashMap!(widgetID,AlignColumns) instances; |
674 static this () { | 703 static this () { |
675 instances = new HashMap!(widgetID,AlignColumns); | 704 instances = new HashMap!(widgetID,AlignColumns); |
676 } | 705 } |