Mercurial > projects > mde
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"); |