Mercurial > projects > mde
comparison mde/gui/widget/layout.d @ 58:d43523ed4b62
Included a wdim typedef for all variables to do with window position or size instead of just using int.
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Sat, 14 Jun 2008 17:15:06 +0100 |
parents | 03fa79a48c48 |
children | 891211f034f2 |
comparison
equal
deleted
inserted
replaced
57:9e1f05fbbcef | 58:d43523ed4b62 |
---|---|
81 if (data.length < rows + cols) { // data error; use defaults | 81 if (data.length < rows + cols) { // data error; use defaults |
82 col.dupMin; | 82 col.dupMin; |
83 row.dupMin; | 83 row.dupMin; |
84 } else { // sufficient data | 84 } else { // sufficient data |
85 lenUsed = rows+cols; | 85 lenUsed = rows+cols; |
86 col.setCheck (data[0..cols]); | 86 col.setCheck (cast(wdim[])data[0..cols]); |
87 row.setCheck (data[cols..lenUsed]); | 87 row.setCheck (cast(wdim[])data[cols..lenUsed]); |
88 } | 88 } |
89 | 89 |
90 | 90 |
91 // Generate cached mutable data | 91 // Generate cached mutable data |
92 // Calculate column and row locations: | 92 // Calculate column and row locations: |
117 int[] getMutableData () { | 117 int[] getMutableData () { |
118 int[] ret; | 118 int[] ret; |
119 foreach (widget; subWidgets) | 119 foreach (widget; subWidgets) |
120 ret ~= widget.getMutableData; | 120 ret ~= widget.getMutableData; |
121 | 121 |
122 ret ~= col.width ~ row.width; | 122 return ret ~ cast(int[])col.width ~ cast(int[])row.width; |
123 return ret; | |
124 } | 123 } |
125 //END Creation & saving | 124 //END Creation & saving |
126 | 125 |
127 //BEGIN Size & position | 126 //BEGIN Size & position |
128 bool isWSizable () { | 127 bool isWSizable () { |
131 bool isHSizable () { | 130 bool isHSizable () { |
132 return row.firstSizable >= 0; | 131 return row.firstSizable >= 0; |
133 } | 132 } |
134 | 133 |
135 /* Calculates the minimal size from all rows and columns of widgets. */ | 134 /* Calculates the minimal size from all rows and columns of widgets. */ |
136 void getMinimalSize (out int mw, out int mh) { | 135 void getMinimalSize (out wdim mw, out wdim mh) { |
137 mw = this.mw; | 136 mw = this.mw; |
138 mh = this.mh; | 137 mh = this.mh; |
139 } | 138 } |
140 | 139 |
141 void setWidth (int nw, int dir) { | 140 void setWidth (wdim nw, int dir) { |
142 if (nw == w) return; | 141 if (nw == w) return; |
143 | 142 |
144 w += col.adjustCellSizes (nw - w, (dir == -1 ? col.lastSizable : col.firstSizable), dir); | 143 w += col.adjustCellSizes (nw - w, (dir == -1 ? col.lastSizable : col.firstSizable), dir); |
145 | 144 |
146 // Note: setPosition must be called after! | 145 // Note: setPosition must be called after! |
147 } | 146 } |
148 void setHeight (int nh, int dir) { | 147 void setHeight (wdim nh, int dir) { |
149 if (nh == h) return; | 148 if (nh == h) return; |
150 | 149 |
151 h += row.adjustCellSizes (nh - h, (dir == -1 ? row.lastSizable : row.firstSizable), dir); | 150 h += row.adjustCellSizes (nh - h, (dir == -1 ? row.lastSizable : row.firstSizable), dir); |
152 | 151 |
153 // Note: setPosition must be called after! | 152 // Note: setPosition must be called after! |
154 } | 153 } |
155 | 154 |
156 void setPosition (int x, int y) { | 155 void setPosition (wdim x, wdim y) { |
157 this.x = x; | 156 this.x = x; |
158 this.y = y; | 157 this.y = y; |
159 | 158 |
160 foreach (i,widget; subWidgets) | 159 foreach (i,widget; subWidgets) |
161 widget.setPosition (x + col.pos[i % cols], y + row.pos[i / cols]); | 160 widget.setPosition (x + col.pos[i % cols], y + row.pos[i / cols]); |
162 } | 161 } |
163 //END Size & position | 162 //END Size & position |
164 | 163 |
165 | 164 |
166 // Find the relevant widget. | 165 // Find the relevant widget. |
167 IWidget getWidget (int cx, int cy) { | 166 IWidget getWidget (wdim cx, wdim cy) { |
168 debug scope (failure) | 167 debug scope (failure) |
169 logger.warn ("getWidget: failure"); | 168 logger.warn ("getWidget: failure"); |
170 // Find row/column: | 169 // Find row/column: |
171 myDiff i = col.getCell (cx - x); | 170 myDiff i = col.getCell (cx - x); |
172 myDiff j = row.getCell (cy - y); | 171 myDiff j = row.getCell (cy - y); |
176 // On a subwidget; recurse call: | 175 // On a subwidget; recurse call: |
177 return subWidgets[i + j*cols].getWidget (cx, cy); | 176 return subWidgets[i + j*cols].getWidget (cx, cy); |
178 } | 177 } |
179 | 178 |
180 // Resizing columns & rows | 179 // Resizing columns & rows |
181 void clickEvent (ushort cx, ushort cy, ubyte b, bool state) { | 180 void clickEvent (wdabs cx, wdabs cy, ubyte b, bool state) { |
182 debug scope (failure) | 181 debug scope (failure) |
183 logger.warn ("clickEvent: failure"); | 182 logger.warn ("clickEvent: failure"); |
184 if (b == 1 && state == true) { | 183 if (b == 1 && state == true) { |
185 /* Note: Because of getWidget, this function is only called if the click is not on a | 184 /* Note: Because of getWidget, this function is only called if the click is not on a |
186 * sub-widget, so we know it's on some divisor (so at least one of resizeCol and | 185 * sub-widget, so we know it's on some divisor (so at least one of resizeCol and |
214 col.setColWidth = &setColWidth; | 213 col.setColWidth = &setColWidth; |
215 row.setColWidth = &setRowHeight; | 214 row.setColWidth = &setRowHeight; |
216 | 215 |
217 // Calculate the minimal column and row sizes: | 216 // Calculate the minimal column and row sizes: |
218 // set length, making sure the arrays are initialised to zero: | 217 // set length, making sure the arrays are initialised to zero: |
219 col.minWidth = new int[cols]; | 218 col.minWidth = new wdim[cols]; |
220 row.minWidth = new int[rows]; | 219 row.minWidth = new wdim[rows]; |
221 int ww, wh; // sub-widget minimal sizes | 220 wdim ww, wh; // sub-widget minimal sizes |
222 foreach (i,widget; subWidgets) { | 221 foreach (i,widget; subWidgets) { |
223 widget.getMinimalSize (ww, wh); | 222 widget.getMinimalSize (ww, wh); |
224 | 223 |
225 // Increase dimensions if current minimal size is larger: | 224 // Increase dimensions if current minimal size is larger: |
226 myIt n = i % cols; // column | 225 myIt n = i % cols; // column |
230 } | 229 } |
231 | 230 |
232 | 231 |
233 // Calculate the overall minimal size, starting with the spacing: | 232 // Calculate the overall minimal size, starting with the spacing: |
234 mh = window.renderer.layoutSpacing; // use mh temporarily | 233 mh = window.renderer.layoutSpacing; // use mh temporarily |
235 mw = mh * (cols - 1); | 234 mw = mh * cast(wdim)(cols - 1); |
236 mh *= (rows - 1); | 235 mh *= cast(wdim)(rows - 1); |
237 | 236 |
238 foreach (x; col.minWidth) // add the column/row's dimensions | 237 foreach (x; col.minWidth) // add the column/row's dimensions |
239 mw += x; | 238 mw += x; |
240 foreach (x; row.minWidth) | 239 foreach (x; row.minWidth) |
241 mh += x; | 240 mh += x; |
273 } | 272 } |
274 } | 273 } |
275 //END Cache calculation functions | 274 //END Cache calculation functions |
276 | 275 |
277 | 276 |
278 void setColWidth (myIt i, int w, int dir) { | 277 void setColWidth (myIt i, wdim w, int dir) { |
279 for (myIt j = 0; j < rows; ++j) { | 278 for (myIt j = 0; j < rows; ++j) { |
280 subWidgets[i + cols*j].setWidth (w, dir); | 279 subWidgets[i + cols*j].setWidth (w, dir); |
281 } | 280 } |
282 } | 281 } |
283 void setRowHeight (myIt j, int h, int dir) { | 282 void setRowHeight (myIt j, wdim h, int dir) { |
284 for (myIt i = 0; i < cols; ++i) { | 283 for (myIt i = 0; i < cols; ++i) { |
285 subWidgets[i + cols*j].setHeight (h, dir); | 284 subWidgets[i + cols*j].setHeight (h, dir); |
286 } | 285 } |
287 } | 286 } |
288 | 287 |
289 | 288 |
290 //BEGIN Col/row resizing callback | 289 //BEGIN Col/row resizing callback |
291 void resizeCallback (ushort cx, ushort cy) { | 290 void resizeCallback (wdim cx, wdim cy) { |
292 col.resize (cx - dragX); | 291 col.resize (cx - dragX); |
293 row.resize (cy - dragY); | 292 row.resize (cy - dragY); |
294 | 293 |
295 // NOTE: all adjustments are relative; might be better if they were absolute? | 294 // NOTE: all adjustments are relative; might be better if they were absolute? |
296 dragX = cx; | 295 dragX = cx; |
299 foreach (i,widget; subWidgets) | 298 foreach (i,widget; subWidgets) |
300 widget.setPosition (x + col.pos[i % cols], | 299 widget.setPosition (x + col.pos[i % cols], |
301 y + row.pos[i / cols]); | 300 y + row.pos[i / cols]); |
302 window.requestRedraw; | 301 window.requestRedraw; |
303 } | 302 } |
304 bool endCallback (ushort cx, ushort cy, ubyte b, bool state) { | 303 bool endCallback (wdabs cx, wdabs cy, ubyte b, bool state) { |
305 if (b == 1 && state == false) { | 304 if (b == 1 && state == false) { |
306 window.gui.removeCallbacks (cast(void*) this); | 305 window.gui.removeCallbacks (cast(void*) this); |
307 return true; // we've handled the up-click | 306 return true; // we've handled the up-click |
308 } | 307 } |
309 return false; // we haven't handled it | 308 return false; // we haven't handled it |
310 } | 309 } |
311 | 310 |
312 protected: | 311 protected: |
313 // Data for resizing cols/rows: | 312 // Data for resizing cols/rows: |
314 int dragX, dragY; // coords where drag starts | 313 wdim dragX, dragY; // coords where drag starts |
315 //END Col/row resizing callback | 314 //END Col/row resizing callback |
316 | 315 |
317 | 316 |
318 myIt cols, rows; // number of cells in grid | 317 myIt cols, rows; // number of cells in grid |
319 | 318 |
326 * The purpose of this struct is mostly to unify functionality which must work the same on both | 325 * The purpose of this struct is mostly to unify functionality which must work the same on both |
327 * horizontal and vertical cell placement. | 326 * horizontal and vertical cell placement. |
328 * | 327 * |
329 * Most notation corresponds to horizontal layout (columns), simply for easy of naming. */ | 328 * Most notation corresponds to horizontal layout (columns), simply for easy of naming. */ |
330 struct CellDimensions { | 329 struct CellDimensions { |
331 int[] pos, // relative position (cumulative width[i-1] plus spacing) | 330 wdim[] pos, // relative position (cumulative width[i-1] plus spacing) |
332 width, // current widths | 331 width, // current widths |
333 minWidth; // minimal widths (set by genCachedConstructionData) | 332 minWidth; // minimal widths (set by genCachedConstructionData) |
334 bool[] sizable; // true if col is resizable (set by genCachedConstructionData) | 333 bool[] sizable; // true if col is resizable (set by genCachedConstructionData) |
335 myDiff firstSizable, // first col which is resizable, negative if none | 334 myDiff firstSizable, // first col which is resizable, negative if none |
336 lastSizable; // as above, but last (set by genCachedConstructionData) | 335 lastSizable; // as above, but last (set by genCachedConstructionData) |
337 myDiff resizeD, // resize down from this index (<0 if not resizing) | 336 myDiff resizeD, // resize down from this index (<0 if not resizing) |
338 resizeU; // and up from this index | 337 resizeU; // and up from this index |
339 int spacing; // used by genPositions (which cannot access the layout class's data) | 338 wdim spacing; // used by genPositions (which cannot access the layout class's data) |
340 /* This is a delegate to a enclosing class's function, since: | 339 /* This is a delegate to a enclosing class's function, since: |
341 * a different implementation is needed for cols or rows | 340 * a different implementation is needed for cols or rows |
342 * we're unable to access enclosing class members directly */ | 341 * we're unable to access enclosing class members directly */ |
343 void delegate (myIt,int,int) setColWidth; // set width of a column, with resize direction | 342 void delegate (myIt,wdim,int) setColWidth; // set width of a column, with resize direction |
344 | 343 |
345 void dupMin () { | 344 void dupMin () { |
346 width = minWidth.dup; | 345 width = minWidth.dup; |
347 } | 346 } |
348 void setCheck (int[] data) { | 347 void setCheck (wdim[] data) { |
349 // Set to provided data: | 348 // Set to provided data: |
350 width = data; | 349 width = data; |
351 // And check sizes are valid: | 350 // And check sizes are valid: |
352 foreach (i, m; minWidth) | 351 foreach (i, m; minWidth) |
353 // if fixed width or width is less than minimum: | 352 // if fixed width or width is less than minimum: |
354 if (!sizable[i] || width[i] < m) | 353 if (!sizable[i] || width[i] < m) |
355 width[i] = m; | 354 width[i] = m; |
356 } | 355 } |
357 | 356 |
358 // Generate position infomation and return total width (i.e. widget width/height) | 357 // Generate position infomation and return total width (i.e. widget width/height) |
359 int genPositions () { | 358 wdim genPositions () { |
360 pos.length = minWidth.length; | 359 pos.length = minWidth.length; |
361 | 360 |
362 int x = 0; | 361 wdim x = 0; |
363 foreach (i, w; width) { | 362 foreach (i, w; width) { |
364 pos[i] = x; | 363 pos[i] = x; |
365 x += w + spacing; | 364 x += w + spacing; |
366 } | 365 } |
367 return x - spacing; | 366 return x - spacing; |
368 } | 367 } |
369 | 368 |
370 // Get the row/column a click occured in | 369 // Get the row/column a click occured in |
371 // Returns -i if in space to left of col i, or i if on col i | 370 // Returns -i if in space to left of col i, or i if on col i |
372 myDiff getCell (int l) { | 371 myDiff getCell (wdim l) { |
373 myDiff i = minWidth.length - 1; // starting from right... | 372 myDiff i = minWidth.length - 1; // starting from right... |
374 while (l < pos[i]) { // decrement while left of this column | 373 while (l < pos[i]) { // decrement while left of this column |
375 debug assert (i > 0, "getCell: l < pos[0] (code error)"); | 374 debug assert (i > 0, "getCell: l < pos[0] (code error)"); |
376 --i; | 375 --i; |
377 } // now (l >= pos[i]) | 376 } // now (l >= pos[i]) |
379 return -i - 1; // note: i might be 0 so cannot just return -i | 378 return -i - 1; // note: i might be 0 so cannot just return -i |
380 return i; | 379 return i; |
381 } | 380 } |
382 | 381 |
383 // Calculate resizeU/resizeD, and return true if unable to resize. | 382 // Calculate resizeU/resizeD, and return true if unable to resize. |
384 bool findResize (int l) { | 383 bool findResize (wdim l) { |
385 resizeU = -getCell (l); // potential start for upward-resizes | 384 resizeU = -getCell (l); // potential start for upward-resizes |
386 if (resizeU <= 0) return true; // not on a space between cells | 385 if (resizeU <= 0) return true; // not on a space between cells |
387 resizeD = resizeU - 1; // potential start for downward-resizes | 386 resizeD = resizeU - 1; // potential start for downward-resizes |
388 | 387 |
389 while (!sizable[resizeU]) { // find first actually resizable column (upwards) | 388 while (!sizable[resizeU]) { // find first actually resizable column (upwards) |
416 * The amount adjusted. This may be larger than diff, since cellD is clamped by cellDMin. | 415 * The amount adjusted. This may be larger than diff, since cellD is clamped by cellDMin. |
417 * | 416 * |
418 * Note: Check variable used for start is valid before calling! If a non-sizable column's | 417 * Note: Check variable used for start is valid before calling! If a non-sizable column's |
419 * index is passed, this should get increased (if diff > 0) but not decreased. | 418 * index is passed, this should get increased (if diff > 0) but not decreased. |
420 */ | 419 */ |
421 int adjustCellSizes (int diff, myDiff start, int incr) | 420 wdim adjustCellSizes (wdim diff, myDiff start, int incr) |
422 in { | 421 in { |
423 // Could occur if adjust isn't called first, but this would be a code error: | 422 // Could occur if adjust isn't called first, but this would be a code error: |
424 assert (width !is null, "adjustCellSizes: width is null"); | 423 assert (width !is null, "adjustCellSizes: width is null"); |
425 // Most likely if passed negative when sizing is disabled: | 424 // Most likely if passed negative when sizing is disabled: |
426 assert (start >= 0 && start < minWidth.length, "adjustCellSizes: invalid start"); | 425 assert (start >= 0 && start < minWidth.length, "adjustCellSizes: invalid start"); |
433 if (diff > 0) { // increase size of first resizable cell | 432 if (diff > 0) { // increase size of first resizable cell |
434 width[i] += diff; | 433 width[i] += diff; |
435 setColWidth (i, width[i], incr); | 434 setColWidth (i, width[i], incr); |
436 } | 435 } |
437 else if (diff < 0) { // decrease | 436 else if (diff < 0) { // decrease |
438 int rd = diff; // running diff | 437 wdim rd = diff; // running diff |
439 aCSwhile: | 438 aCSwhile: |
440 while (true) { | 439 while (true) { |
441 width[i] += rd; // decrease this cell's size (but may be too much) | 440 width[i] += rd; // decrease this cell's size (but may be too much) |
442 rd = width[i] - minWidth[i]; | 441 rd = width[i] - minWidth[i]; |
443 if (rd >= 0) { // OK; we're done | 442 if (rd >= 0) { // OK; we're done |
466 | 465 |
467 genPositions; | 466 genPositions; |
468 return diff; | 467 return diff; |
469 } | 468 } |
470 | 469 |
471 void resize (int diff) { | 470 void resize (wdim diff) { |
472 if (resizeU <= 0) return; | 471 if (resizeU <= 0) return; |
473 | 472 |
474 // do shrinking first (in case we hit the minimum) | 473 // do shrinking first (in case we hit the minimum) |
475 if (diff >= 0) { | 474 if (diff >= 0) { |
476 diff = -adjustCellSizes (-diff, resizeU, 1); | 475 diff = -adjustCellSizes (-diff, resizeU, 1); |
482 } | 481 } |
483 } | 482 } |
484 CellDimensions col, row; | 483 CellDimensions col, row; |
485 | 484 |
486 // Index types. Note that in some cases they need to hold negative values. | 485 // Index types. Note that in some cases they need to hold negative values. |
487 // Int is used for resizing direction (although ptrdiff_t would be more appropriate), | 486 // int is used for resizing direction (although ptrdiff_t would be more appropriate), |
488 // since the value must always be -1 or +1 and int is smaller on X86_64. | 487 // since the value must always be -1 or +1 and int is smaller on X86_64. |
489 alias size_t myIt; | 488 alias size_t myIt; |
490 alias ptrdiff_t myDiff; | 489 alias ptrdiff_t myDiff; |
491 } | 490 } |