comparison mde/gui/widget/layout.d @ 77:3dfd934100f7

Continuing widget data changes started in last commit: all previous widgets work again now (but lacking saving).
author Diggory Hardy <diggory.hardy@gmail.com>
date Tue, 29 Jul 2008 17:11:22 +0100
parents 159775502bb4
children 79a1809421aa
comparison
equal deleted inserted replaced
76:65780e0e48e6 77:3dfd934100f7
46 * 46 *
47 * Widget uses the initialisation data: 47 * Widget uses the initialisation data:
48 * [widgetID, r, c, w11, w12, ..., w1c, ..., wr1, ..., wrc] 48 * [widgetID, r, c, w11, w12, ..., w1c, ..., wr1, ..., wrc]
49 * where r and c are the number of rows and columns, and wij is the ID (from parent Window's 49 * where r and c are the number of rows and columns, and wij is the ID (from parent Window's
50 * list) for the widget in row i and column j. The number of parameters must be r*c + 3. */ 50 * list) for the widget in row i and column j. The number of parameters must be r*c + 3. */
51 this (IWindow wind, int[] data) { 51 this (IWidgetManager mgr, WidgetData data) {
52 // Get grid size and check data 52 // Get grid size and check data
53 // Check sufficient data for rows, cols, and at least one widget: 53 // Check sufficient data for rows, cols, and possibly row/col widths.
54 if (data.length < 4) throw new WidgetDataException; 54 if (data.ints.length < 3) throw new WidgetDataException;
55 55
56 rows = data[1]; 56 rows = data.ints[1];
57 cols = data[2]; 57 cols = data.ints[2];
58 if (data.length != 3 + rows * cols) throw new WidgetDataException; 58 // Check: at least one sub-widget, ints length == 3 or also contains row & col widths,
59 /* data.length >= 4 so besides checking the length is correct, this tells us: 59 // strings' length is correct:
60 * rows * cols >= 4 - 3 = 1 a free check! 60 if (rows < 1 || cols < 1 ||
61 * The only thing not checked is whether both rows and cols are negative, which would 61 (data.ints.length != 3 && data.ints.length != 3 + rows + cols) ||
62 * cause an exception when dynamic arrays are allocated by genCachedConstructionData, which 62 data.strings.length != rows * cols)
63 * is an acceptible method of failure (and is unlikely anyway). */ 63 throw new WidgetDataException;
64 64
65 // Get all sub-widgets 65 // Get all sub-widgets
66 subWidgets.length = rows*cols; 66 subWidgets.length = rows*cols;
67 foreach (i, ref subWidget; subWidgets) { 67 foreach (i, ref subWidget; subWidgets) {
68 subWidget = wind.makeWidget (data[i+3]); 68 subWidget = mgr.makeWidget (data.strings[i]);
69 } 69 }
70 super (wind, data); 70
71 } 71 super (mgr, data);
72
73 if (data.ints.length == 3 + rows + cols) {
74 col.setCheck (cast(wdim[]) data.ints[3..cols+3]);
75 row.setCheck (cast(wdim[]) data.ints[cols+3..$]);
76 } else {
77 col.dupMin;
78 row.dupMin;
79 }
80 adjustCache;
81 }
82 /+FIXME
72 /** Return construction data to recreate this GridLayoutWidget. */ 83 /** Return construction data to recreate this GridLayoutWidget. */
73 int[] getCreationData () { 84 int[] getCreationData () {
74 int[] ret; 85 int[] ret;
75 ret.length = 3 + subWidgets.length; 86 ret.length = 3 + subWidgets.length;
76 87
78 89
79 foreach (i,widget; subWidgets) // sub widgets 90 foreach (i,widget; subWidgets) // sub widgets
80 ret[i+3] = window.addCreationData (widget); 91 ret[i+3] = window.addCreationData (widget);
81 92
82 return ret; 93 return ret;
83 } 94 }+/
84 } 95 }
85 96
86 97
87 /************************************************************************************************* 98 /*************************************************************************************************
88 * Trial layout of sub-widgets of one type only. 99 * Trial layout of sub-widgets of one type only.
89 *************************************************************************************************/ 100 *************************************************************************************************/
90 class TrialContentLayoutWidget : GridWidget 101 class TrialContentLayoutWidget : GridWidget
91 { 102 {
92 this (IWindow wind, int[] data) { 103 this (IWidgetManager mgr, WidgetData data) {
93 debug scope (failure) 104 debug scope (failure)
94 logger.warn ("TrialContentLayoutWidget: failure"); 105 logger.warn ("TrialContentLayoutWidget: failure");
95 if (data.length != 3) throw new WidgetDataException; 106 WDCheck (data, 2);
96 107
97 OptionList optsList = OptionList.trial(); 108 OptionList optsList = OptionList.trial();
98 rows = optsList.list.length; 109 rows = optsList.list.length;
99 cols = 1; 110 cols = 1;
100 111
101 // Get all sub-widgets 112 // Get all sub-widgets
102 subWidgets.length = rows*cols; 113 subWidgets.length = rows*cols;
114 WidgetData COWData;
115 COWData.ints = [0, data.ints[1]];
103 foreach (i, c; optsList.list) { 116 foreach (i, c; optsList.list) {
104 subWidgets[i] = new ContentOptionWidget (wind, data[1..3], c); 117 subWidgets[i] = new ContentOptionWidget (mgr, COWData, c);
105 } 118 }
106 super (wind, data); 119 super (mgr, data);
107 } 120
108 121 // Set col/row widths to minimals.
122 col.dupMin;
123 row.dupMin;
124 adjustCache;
125 }
126
127 /+FIXME
109 int[] getCreationData () { 128 int[] getCreationData () {
110 return [widgetType]; 129 return [widgetType];
111 } 130 }+/
112 131
113 private: 132 private:
114 OptionList optsList; 133 OptionList optsList;
115 } 134 }
116 135
128 abstract class GridWidget : Widget 147 abstract class GridWidget : Widget
129 { 148 {
130 //BEGIN Creation & saving 149 //BEGIN Creation & saving
131 /** Partial constructor for a grid layout widget. 150 /** Partial constructor for a grid layout widget.
132 * 151 *
133 * Deriving classes should check data length, and set rows, cols, and the subWidgets array, 152 * Deriving classes should check data lengths, and set rows, cols, and the subWidgets array,
134 * before calling this super constructor. (If it's necessary to call super(...) first, 153 * before calling this super constructor. (If it's necessary to call super(...) first,
135 * the call to genCachedConstructionData can be moved to the derived this() methods.) */ 154 * the call to genCachedConstructionData can be moved to the derived this() methods.)
136 protected this (IWindow wind, int[] data) { 155 *
137 super (wind, data); 156 * Derived constructors should call either dupMin or setCheck on col and row, and then call
157 * adjustCache, after calling this. */
158 protected this (IWidgetManager mgr, WidgetData data) {
159 super (mgr, data);
138 160
139 // Needn't be set before genCachedConstructionData is called: 161 // Needn't be set before genCachedConstructionData is called:
140 col.setColWidth = &setColWidth; 162 col.setColWidth = &setColWidth;
141 row.setColWidth = &setRowHeight; 163 row.setColWidth = &setRowHeight;
142 164
143 // Calculate cached construction data 165 // Calculate cached construction data
144 genCachedConstructionData; 166 genCachedConstructionData;
145 } 167 }
146 168
147 /** This implementation of adjust() does two things:
148 * 1. Pass adjust data on to sub-widgets
149 * 2. Set the size, from the adjust data if possible
150 *
151 * Can be overridden (probably along with getMutableData()) if a different implementation is
152 * wanted. adjustCache() may still be useful. */
153 int[] adjust (int[] data) {
154 // Give all sub-widgets their data:
155 foreach (widget; subWidgets)
156 data = widget.adjust (data);
157
158 /** We basically short-cut setSize by loading previous col/row sizes and doing the final
159 * calculations.
160 * Note: if setSize gets called afterwards, it should have same dimensions and so not do
161 * anything. */
162 int lenUsed = 0;
163 if (data.length < rows + cols) { // data error; use defaults
164 col.dupMin;
165 row.dupMin;
166 } else { // sufficient data
167 lenUsed = rows+cols;
168 col.setCheck (cast(wdim[])data[0..cols]);
169 row.setCheck (cast(wdim[])data[cols..lenUsed]);
170 }
171
172 adjustCache();
173 return data[lenUsed..$];
174 }
175 /** Generates cached mutable data. 169 /** Generates cached mutable data.
176 * 170 *
177 * Should be called by adjust() after setting col and row widths (currently via dupMin or 171 * Should be called by adjust() after setting col and row widths (currently via dupMin or
178 * setCheck). */ 172 * setCheck). */
179 void adjustCache () { 173 void adjustCache () {
187 // Resizing direction is arbitrarily set to negative: 181 // Resizing direction is arbitrarily set to negative:
188 widget.setWidth (col.width[i % cols], -1); 182 widget.setWidth (col.width[i % cols], -1);
189 widget.setHeight (row.width[i / cols], -1); 183 widget.setHeight (row.width[i / cols], -1);
190 } 184 }
191 } 185 }
186 /+ FIXME - saving
192 /** Returns sub-widget mutable data along with column widths and row heights, as used by 187 /** Returns sub-widget mutable data along with column widths and row heights, as used by
193 * adjust(). */ 188 * adjust(). */
194 int[] getMutableData () { 189 int[] getMutableData () {
195 int[] ret; 190 int[] ret;
196 foreach (widget; subWidgets) 191 foreach (widget; subWidgets)
197 ret ~= widget.getMutableData; 192 ret ~= widget.getMutableData;
198 193
199 return ret ~ cast(int[])col.width ~ cast(int[])row.width; 194 return ret ~ cast(int[])col.width ~ cast(int[])row.width;
200 } 195 }+/
201 //END Creation & saving 196 //END Creation & saving
202 197
203 //BEGIN Size & position 198 //BEGIN Size & position
204 bool isWSizable () { 199 bool isWSizable () {
205 return col.firstSizable >= 0; 200 return col.firstSizable >= 0;
232 } 227 }
233 //END Size & position 228 //END Size & position
234 229
235 230
236 // Find the relevant widget. 231 // Find the relevant widget.
237 IWidget getWidget (wdim cx, wdim cy) { 232 IChildWidget getWidget (wdim cx, wdim cy) {
238 debug scope (failure) 233 debug scope (failure)
239 logger.warn ("getWidget: failure"); 234 logger.warn ("getWidget: failure");
240 // Find row/column: 235 // Find row/column:
241 myDiff i = col.getCell (cx - x); 236 myDiff i = col.getCell (cx - x);
242 myDiff j = row.getCell (cy - y); 237 myDiff j = row.getCell (cy - y);
261 return; // unable to resize 256 return; // unable to resize
262 257
263 dragX = cx; 258 dragX = cx;
264 dragY = cy; 259 dragY = cy;
265 260
266 window.gui.addClickCallback (&endCallback); 261 mgr.addClickCallback (&endCallback);
267 window.gui.addMotionCallback (&resizeCallback); 262 mgr.addMotionCallback (&resizeCallback);
268 } 263 }
269 } 264 }
270 265
271 void draw () { 266 void draw () {
272 super.draw (); 267 super.draw ();
282 * Also need to be re-run if the renderer changes. 277 * Also need to be re-run if the renderer changes.
283 * 278 *
284 * rows, cols and subWidgets must be set before calling. */ 279 * rows, cols and subWidgets must be set before calling. */
285 void genCachedConstructionData () { 280 void genCachedConstructionData () {
286 // Will only change if renderer changes: 281 // Will only change if renderer changes:
287 col.spacing = row.spacing = window.renderer.layoutSpacing; 282 col.spacing = row.spacing = mgr.renderer.layoutSpacing;
288 283
289 // Calculate the minimal column and row sizes: 284 // Calculate the minimal column and row sizes:
290 // set length, making sure the arrays are initialised to zero: 285 // set length, making sure the arrays are initialised to zero:
291 col.minWidth = new wdim[cols]; 286 col.minWidth = new wdim[cols];
292 row.minWidth = new wdim[rows]; 287 row.minWidth = new wdim[rows];
300 if (row.minWidth[n] < md) row.minWidth[n] = md; 295 if (row.minWidth[n] < md) row.minWidth[n] = md;
301 } 296 }
302 297
303 298
304 // Calculate the overall minimal size, starting with the spacing: 299 // Calculate the overall minimal size, starting with the spacing:
305 mh = window.renderer.layoutSpacing; // use mh temporarily 300 mh = mgr.renderer.layoutSpacing; // use mh temporarily
306 mw = mh * cast(wdim)(cols - 1); 301 mw = mh * cast(wdim)(cols - 1);
307 mh *= cast(wdim)(rows - 1); 302 mh *= cast(wdim)(rows - 1);
308 303
309 foreach (x; col.minWidth) // add the column/row's dimensions 304 foreach (x; col.minWidth) // add the column/row's dimensions
310 mw += x; 305 mw += x;
368 dragY = cy; 363 dragY = cy;
369 364
370 foreach (i,widget; subWidgets) 365 foreach (i,widget; subWidgets)
371 widget.setPosition (x + col.pos[i % cols], 366 widget.setPosition (x + col.pos[i % cols],
372 y + row.pos[i / cols]); 367 y + row.pos[i / cols]);
373 window.requestRedraw; 368 mgr.requestRedraw;
374 } 369 }
375 bool endCallback (wdabs cx, wdabs cy, ubyte b, bool state) { 370 bool endCallback (wdabs cx, wdabs cy, ubyte b, bool state) {
376 if (b == 1 && state == false) { 371 if (b == 1 && state == false) {
377 window.gui.removeCallbacks (cast(void*) this); 372 mgr.removeCallbacks (cast(void*) this);
378 return true; // we've handled the up-click 373 return true; // we've handled the up-click
379 } 374 }
380 return false; // we haven't handled it 375 return false; // we haven't handled it
381 } 376 }
382 377
388 383
389 myIt cols, rows; // number of cells in grid 384 myIt cols, rows; // number of cells in grid
390 385
391 /* All widgets in the grid, by row. Order: [ 0 1 ] 386 /* All widgets in the grid, by row. Order: [ 0 1 ]
392 * [ 2 3 ] */ 387 * [ 2 3 ] */
393 IWidget[] subWidgets; 388 IChildWidget[] subWidgets;
394 389
395 /* Widths, positions, etc., either of columns or of rows 390 /* Widths, positions, etc., either of columns or of rows
396 * 391 *
397 * The purpose of this struct is mostly to unify functionality which must work the same on both 392 * The purpose of this struct is mostly to unify functionality which must work the same on both
398 * horizontal and vertical cell placement. 393 * horizontal and vertical cell placement.
489 * Note: Check variable used for start is valid before calling! If a non-sizable column's 484 * Note: Check variable used for start is valid before calling! If a non-sizable column's
490 * index is passed, this should get increased (if diff > 0) but not decreased. 485 * index is passed, this should get increased (if diff > 0) but not decreased.
491 */ 486 */
492 wdim adjustCellSizes (wdim diff, myDiff start, int incr) 487 wdim adjustCellSizes (wdim diff, myDiff start, int incr)
493 in { 488 in {
494 // Could occur if adjust isn't called first, but this would be a code error: 489 // Could occur if constructor doesn't call dupMin/setCheck (code error):
495 assert (width !is null, "adjustCellSizes: width is null"); 490 assert (width !is null, "adjustCellSizes: width is null");
496 // Most likely if passed negative when sizing is disabled: 491 // Most likely if passed negative when sizing is disabled:
497 assert (start >= 0 && start < minWidth.length, "adjustCellSizes: invalid start"); 492 assert (start >= 0 && start < minWidth.length, "adjustCellSizes: invalid start");
498 assert (incr == 1 || incr == -1, "adjustCellSizes: invalid incr"); 493 assert (incr == 1 || incr == -1, "adjustCellSizes: invalid incr");
499 assert (setColWidth !is null, "adjustCellSizes: setColWidth is null"); 494 assert (setColWidth !is null, "adjustCellSizes: setColWidth is null");