Mercurial > projects > mde
comparison mde/gui/widget/layout.d @ 124:a2ef6b549101
Dynamic minimal size changing is now fully supported.
Support for reducing minimal size in layouts.
Editing numbers as text now always converts new number back to string at end of edit.
Floating point number display format changed.
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Mon, 05 Jan 2009 12:43:27 +0000 |
parents | d3b2cefd46c9 |
children | c9843fbaac88 |
comparison
equal
deleted
inserted
replaced
123:d3b2cefd46c9 | 124:a2ef6b549101 |
---|---|
249 } | 249 } |
250 debug logger.error ("minSizeChange: widget is not my child (code error)"); | 250 debug logger.error ("minSizeChange: widget is not my child (code error)"); |
251 return; | 251 return; |
252 | 252 |
253 gotCell: | 253 gotCell: |
254 if (col.newMinWidth (c % cols, nmw) || | 254 size_t r = c / cols; |
255 row.newMinWidth (c / cols, nmh)) { | 255 c = c % cols; |
256 parent.minSizeChange (this, col.mw, row.mw); | 256 bool sizeChange = col.newMinWidth (c, r+colR, nmw); |
257 sizeChange = row.newMinWidth (r, c+rowR, nmh) || sizeChange; | |
258 if (sizeChange) { | |
257 w = col.w; | 259 w = col.w; |
258 h = row.w; | 260 h = row.w; |
261 parent.minSizeChange (this, col.mw, row.mw); | |
259 } | 262 } |
260 mgr.requestRedraw; | 263 mgr.requestRedraw; |
261 } | 264 } |
262 //END Size & position | 265 //END Size & position |
263 | 266 |
267 debug scope (failure) | 270 debug scope (failure) |
268 logger.warn ("getWidget: failure; values: click; pos; width: {},{}; {},{}; {},{}", cx, cy, x, y, w, h); | 271 logger.warn ("getWidget: failure; values: click; pos; width: {},{}; {},{}; {},{}", cx, cy, x, y, w, h); |
269 debug assert (cx >= x && cx < x + w && cy >= y && cy < y + h, "getWidget: not on widget (code error)"); | 272 debug assert (cx >= x && cx < x + w && cy >= y && cy < y + h, "getWidget: not on widget (code error)"); |
270 | 273 |
271 // Find row/column: | 274 // Find row/column: |
272 myDiff i = col.getCell (cx - x); | 275 ptrdiff_t i = col.getCell (cx - x); |
273 myDiff j = row.getCell (cy - y); | 276 ptrdiff_t j = row.getCell (cy - y); |
274 if (i < 0 || j < 0) // on a space between widgets | 277 if (i < 0 || j < 0) // on a space between widgets |
275 return this; | 278 return this; |
276 | 279 |
277 // On a subwidget; recurse call: | 280 // On a subwidget; recurse call: |
278 return subWidgets[i + j*cols].getWidget (cx, cy); | 281 return subWidgets[i + j*cols].getWidget (cx, cy); |
321 if (sADD_n == n) return; // cached data is current | 324 if (sADD_n == n) return; // cached data is current |
322 sADD_n = n; | 325 sADD_n = n; |
323 | 326 |
324 debug (mdeWidgets) logger.trace ("GridWidget: setup on subWidgets..."); | 327 debug (mdeWidgets) logger.trace ("GridWidget: setup on subWidgets..."); |
325 foreach (widg; subWidgets) { // make sure all subwidgets have been set up | 328 foreach (widg; subWidgets) { // make sure all subwidgets have been set up |
326 debug assert (widg); | 329 debug assert (widg, "null widg"); |
327 widg.setup (n,flags); | 330 widg.setup (n,flags); |
328 } | 331 } |
329 debug (mdeWidgets) logger.trace ("GridWidget: setup on subWidgets...done"); | 332 debug (mdeWidgets) logger.trace ("GridWidget: setup on subWidgets...done"); |
330 // make sure both AlignColumns are set up (since first call to setup(n) calls reset): | 333 // make sure both AlignColumns are set up (since first call to setup(n) calls reset): |
331 col.setup (n, flags); | 334 col.setup (n, flags); |
333 | 336 |
334 // Note: shared AlignColumns get this set by all sharing GridWidgets | 337 // Note: shared AlignColumns get this set by all sharing GridWidgets |
335 col.spacing = row.spacing = useSpacing ? mgr.renderer.layoutSpacing : 0; | 338 col.spacing = row.spacing = useSpacing ? mgr.renderer.layoutSpacing : 0; |
336 | 339 |
337 // Calculate the minimal column and row sizes: | 340 // Calculate the minimal column and row sizes: |
341 if (colR == size_t.max) | |
342 colR = col.addRows (rows); | |
343 if (rowR == size_t.max) | |
344 rowR = row.addRows (cols); | |
338 // AlignColumns (row, col) takes care of initializing minWidth. | 345 // AlignColumns (row, col) takes care of initializing minWidth. |
339 foreach (i,widget; subWidgets) { | 346 for (size_t r = 0; r < rows; ++r) { |
340 // Increase dimensions if current minimal size is larger: | 347 for (size_t c = 0; c < cols; ++c) { |
341 myIt j = i % cols; // column | 348 size_t i = r*cols + c; |
342 wdim md = widget.minWidth; | 349 col.minCellWidths[i+colR*cols] = subWidgets[i].minWidth; |
343 if (col.minWidth[j] < md) col.minWidth[j] = md; | 350 row.minCellWidths[(c+rowR)*rows+r] = subWidgets[i].minHeight; |
344 j = i / cols; // row | 351 } |
345 md = widget.minHeight; | |
346 if (row.minWidth[j] < md) row.minWidth[j] = md; | |
347 } | 352 } |
348 | 353 |
349 // Find which cols/rows are resizable: | 354 // Find which cols/rows are resizable: |
350 // AlignColumns initializes sizable, and sets first and last sizables. | 355 // AlignColumns initializes sizable, and sets first and last sizables. |
351 forCols: | 356 forCols: |
352 for (myIt i = 0; i < cols; ++i) { // for each column | 357 for (size_t i = 0; i < cols; ++i) { // for each column |
353 for (myIt j = 0; j < subWidgets.length; j += cols) // for each row | 358 for (size_t j = 0; j < subWidgets.length; j += cols) // for each row |
354 if (!subWidgets[i+j].isWSizable) // column not resizable | 359 if (!subWidgets[i+j].isWSizable) // column not resizable |
355 continue forCols; // continue the outer for loop | 360 continue forCols; // continue the outer for loop |
356 | 361 |
357 // column is resizable if we get to here | 362 // column is resizable if we get to here |
358 col.sizable[i] = true; | 363 col.sizable[i] = true; |
359 } | 364 } |
360 | 365 |
361 forRows: | 366 forRows: |
362 for (myIt i = 0; i < subWidgets.length; i += cols) { // for each row | 367 for (size_t i = 0; i < subWidgets.length; i += cols) { // for each row |
363 for (myIt j = 0; j < cols; ++j) // for each column | 368 for (size_t j = 0; j < cols; ++j) // for each column |
364 if (!subWidgets[i+j].isHSizable) | 369 if (!subWidgets[i+j].isHSizable) |
365 continue forRows; | 370 continue forRows; |
366 | 371 |
367 row.sizable[i / cols] = true; | 372 row.sizable[i / cols] = true; |
368 } | 373 } |
369 } | 374 } |
370 | 375 |
371 private: | 376 private: |
372 override void setColWidth (myIt i, wdim w, int dir) { | 377 override void setColWidth (size_t i, wdim w, int dir) { |
373 for (myIt j = 0; j < rows; ++j) { | 378 for (size_t j = 0; j < rows; ++j) { |
374 subWidgets[i + cols*j].setWidth (w, dir); | 379 subWidgets[i + cols*j].setWidth (w, dir); |
375 } | 380 } |
376 } | 381 } |
377 override void setRowHeight (myIt j, wdim h, int dir) { | 382 override void setRowHeight (size_t j, wdim h, int dir) { |
378 for (myIt i = 0; i < cols; ++i) { | 383 for (size_t i = 0; i < cols; ++i) { |
379 subWidgets[i + cols*j].setHeight (h, dir); | 384 subWidgets[i + cols*j].setHeight (h, dir); |
380 } | 385 } |
381 } | 386 } |
382 | 387 |
383 | 388 |
406 protected: | 411 protected: |
407 // Data for resizing cols/rows: | 412 // Data for resizing cols/rows: |
408 wdim dragX, dragY; // coords where drag starts | 413 wdim dragX, dragY; // coords where drag starts |
409 //END Col/row resizing callback | 414 //END Col/row resizing callback |
410 | 415 |
411 myIt cols, rows; // number of cells in grid | 416 size_t cols, rows; // number of cells in grid |
412 wdim[] initWidths; // see this / setInitialSize | 417 wdim[] initWidths; // see this / setInitialSize |
413 uint sADD_n = uint.max; // param n of last setup call after setupAlignDimData has run | 418 uint sADD_n = uint.max; // param n of last setup call after setupAlignDimData has run |
414 bool useSpacing; // add inter-row/col spacing? | 419 bool useSpacing; // add inter-row/col spacing? |
415 | 420 |
416 /* All widgets in the grid, by row. Order: [ 0 1 ] | 421 /* All widgets in the grid, by row. Order: [ 0 1 ] |
417 * [ 2 3 ] */ | 422 * [ 2 3 ] */ |
418 //IChildWidget[] subWidgets; | 423 //IChildWidget[] subWidgets; (inherited from AParentWidget) |
419 | 424 |
420 AlignColumns col, row; | 425 AlignColumns col, row; // aligners for cols and rows |
426 // "rows" allocated in col and row; return value of *.addRows(): | |
427 size_t colR = size_t.max, rowR = size_t.max; | |
421 } | 428 } |
422 | 429 |
423 | 430 |
424 /************************************************************************************************** | 431 /************************************************************************************************** |
425 * Alignment device | 432 * Alignment device |
436 package class AlignColumns | 443 package class AlignColumns |
437 { | 444 { |
438 /** Instance returned will be shared with any other widgets of same widgetID. | 445 /** Instance returned will be shared with any other widgets of same widgetID. |
439 * | 446 * |
440 * Also ensures each widget sharing an instance expects the same number of columns. */ | 447 * Also ensures each widget sharing an instance expects the same number of columns. */ |
441 static AlignColumns getInstance (widgetID id, myIt columns) { | 448 static AlignColumns getInstance (widgetID id, size_t columns) { |
442 AlignColumns* p = id in instances; | 449 AlignColumns* p = id in instances; |
443 if (p) { | 450 if (p) { |
444 if (p.minWidth.length != columns) | 451 if (p.cols != columns) |
445 throw new GuiException ("AlignColumns: no. of columns varies between sharing widgets (code error)"); | 452 throw new GuiException ("AlignColumns: no. of columns varies between sharing widgets (code error)"); |
446 //logger.trace ("Shared alignment for: "~id); | 453 //logger.trace ("Shared alignment for: "~id); |
447 return *p; | 454 return *p; |
448 } else { | 455 } else { |
449 auto a = new AlignColumns (columns); | 456 auto a = new AlignColumns (columns); |
455 /** Create an instance. After creation, the number of columns can only be changed by calling | 462 /** Create an instance. After creation, the number of columns can only be changed by calling |
456 * reset. | 463 * reset. |
457 * | 464 * |
458 * After creation, minimal widths should be set for all columns (minWidth) and | 465 * After creation, minimal widths should be set for all columns (minWidth) and |
459 * setWidths must be called before other functions are used. */ | 466 * setWidths must be called before other functions are used. */ |
460 this (myIt columns) { | 467 this (size_t columns) { |
461 if (columns < 1) | 468 if (columns < 1) |
462 throw new GuiException("AlignColumns: created with <1 column (code error)"); | 469 throw new GuiException("AlignColumns: created with <1 column (code error)"); |
463 minWidth.length = columns; | 470 minWidth.length = columns; |
464 sizable.length = columns; | 471 sizable.length = columns; |
472 cols = columns; | |
465 } | 473 } |
466 | 474 |
467 /** Like IChildWidget's setup; calls sADD delegates. */ | 475 /** Like IChildWidget's setup; calls sADD delegates. */ |
468 void setup (uint n, uint flags) { | 476 void setup (uint n, uint flags) { |
469 if (n != setup_n) { | 477 if (n != setup_n) { |
470 setup_n = n; | 478 setup_n = n; |
471 setupWidths = false; | 479 setupWidths = false; |
472 reset (minWidth.length); | 480 reset (cols); |
473 | 481 |
474 foreach (dg; sADD) | 482 foreach (dg; sADD) |
475 dg (n, flags); // set flag 1 | 483 dg (n, flags); // set flag 1 |
476 } | 484 } |
477 } | 485 } |
478 | 486 |
479 /** Reset all column information (only keep set callbacks). | 487 /** Reset all column information (only keep set callbacks). |
480 * | 488 * |
481 * Widths should be set after calling, as on creation. */ | 489 * Widths should be set after calling, as on creation. */ |
482 void reset (myIt columns) { | 490 void reset (size_t columns) { |
483 minWidth[] = 0; | 491 minWidth[] = 0; |
484 sizable[] = false; | 492 sizable[] = false; |
485 firstSizable = -1; | 493 firstSizable = -1; |
486 lastSizable = -1; | 494 lastSizable = -1; |
495 } | |
496 | |
497 /** Add num "rows" to the aligner. They start at the returned index r, thus the values in | |
498 * minCellWidths to set are minCellWidths[cols*r..cols*(r+num)]. | |
499 * | |
500 * Calling this function is necessary to allocate room in minCellWidths. */ | |
501 size_t addRows (size_t num) { | |
502 size_t r = rows; | |
503 rows += num; | |
504 minCellWidths.length = cols*rows; | |
505 return r; | |
487 } | 506 } |
488 | 507 |
489 /** Initialize widths, either from minWidths or from supplied list, checking validity. | 508 /** Initialize widths, either from minWidths or from supplied list, checking validity. |
490 * | 509 * |
491 * Also calculates first/lastSizable from sizable, overall minimal width and column positions. | 510 * Also calculates first/lastSizable from sizable, overall minimal width and column positions. |
492 */ | 511 */ |
493 void setWidths (wdim[] data = null) { | 512 void setWidths (wdim[] data = null) { |
494 if (!setupWidths) { | 513 if (!setupWidths) { |
495 setupWidths = true; | 514 setupWidths = true; |
515 | |
516 // Set minWidth | |
517 assert (minCellWidths.length == rows * cols, "minCellWidths: bad length"); | |
518 for (size_t c = 0; c < cols; ++c) | |
519 for (size_t r = 0; r < rows; ++r) { | |
520 wdim mcw = minCellWidths[c+r*cols]; | |
521 if (minWidth[c] < mcw) | |
522 minWidth[c] = mcw; | |
523 } | |
524 | |
525 /* Calculate the minimal width of all columns plus spacing. */ | |
526 mw = spacing * cast(wdim)(cols - 1); | |
527 foreach (imw; minWidth) | |
528 mw += imw; | |
529 | |
530 // set width | |
496 if (data || width) { // use existing/external data: need to check validity | 531 if (data || width) { // use existing/external data: need to check validity |
497 if (data) { | 532 if (data) { |
498 assert (data.length == minWidth.length, "setWidths called with bad data length (code error)"); | 533 assert (data.length == cols, "setWidths called with bad data length (code error)"); |
499 width = data.dup; // data is shared by other widgets with same id so must be .dup'ed | 534 width = data.dup; // data is shared by other widgets with same id so must be .dup'ed |
500 } | 535 } |
501 foreach (i, m; minWidth) { | 536 foreach (i, m; minWidth) { |
502 if (!sizable[i] || width[i] < m) // if width is fixed or less than minimum | 537 if (!sizable[i] || width[i] < m) // if width is fixed or less than minimum |
503 width[i] = m; | 538 width[i] = m; |
504 } | 539 } |
505 } else | 540 } else |
506 width = minWidth.dup; | 541 width = minWidth.dup; |
507 | 542 |
508 /* Calculate the minimal width of all columns plus spacing. */ | |
509 mw = spacing * cast(wdim)(minWidth.length - 1); | |
510 foreach (imw; minWidth) | |
511 mw += imw; | |
512 | |
513 genPositions; | 543 genPositions; |
514 | 544 |
515 foreach (i,s; sizable) { | 545 foreach (i,s; sizable) { |
516 if (s) { | 546 if (s) { |
517 firstSizable = i; | 547 firstSizable = i; |
529 } | 559 } |
530 } | 560 } |
531 | 561 |
532 /** Add a callback to be called to notify changes in a column's width, and the sADD callback. | 562 /** Add a callback to be called to notify changes in a column's width, and the sADD callback. |
533 */ | 563 */ |
534 typeof(this) addCallbacks (void delegate (myIt,wdim,int) setCW, void delegate (uint,uint) sDg) { | 564 typeof(this) addCallbacks (void delegate (size_t,wdim,int) setCW, void delegate (uint,uint) sDg) { |
535 assert (setCW && sDg, "AlignColumns.addCallbacks: null callback (code error)"); | 565 assert (setCW && sDg, "AlignColumns.addCallbacks: null callback (code error)"); |
536 setWidthCb ~= setCW; | 566 setWidthCb ~= setCW; |
537 sADD ~= sDg; | 567 sADD ~= sDg; |
538 return this; | 568 return this; |
539 } | 569 } |
540 | 570 |
541 /** Get the row/column of relative position l. | 571 /** Get the row/column of relative position l. |
542 * | 572 * |
543 * returns: | 573 * returns: |
544 * -i if in space to left of col i, or i if on col i. */ | 574 * -i if in space to left of col i, or i if on col i. */ |
545 myDiff getCell (wdim l) { | 575 ptrdiff_t getCell (wdim l) { |
546 debug assert (width, "AlignColumns not initialized when getCell called (code error)"); | 576 debug assert (width, "AlignColumns not initialized when getCell called (code error)"); |
547 myDiff i = minWidth.length - 1; // starting from right... | 577 ptrdiff_t i = cols - 1; // starting from right... |
548 while (l < pos[i]) { // decrement while left of this column | 578 while (l < pos[i]) { // decrement while left of this column |
549 debug assert (i > 0, "getCell: l < pos[0] (code error)"); | 579 debug assert (i > 0, "getCell: l < pos[0] (code error)"); |
550 --i; | 580 --i; |
551 } // now (l >= pos[i]) | 581 } // now (l >= pos[i]) |
552 if (l >= pos[i] + width[i]) { // between columns | 582 if (l >= pos[i] + width[i]) { // between columns |
553 debug assert (i+1 < minWidth.length, "getCell: l >= total width (code error)"); | 583 debug assert (i+1 < cols, "getCell: l >= total width (code error)"); |
554 return -i - 1; // note: i might be 0 so cannot just return -i | 584 return -i - 1; // note: i might be 0 so cannot just return -i |
555 } | 585 } |
556 return i; | 586 return i; |
557 } | 587 } |
558 | 588 |
567 } | 597 } |
568 if (nw == w) return w; | 598 if (nw == w) return w; |
569 | 599 |
570 wdim diff = nw - w; | 600 wdim diff = nw - w; |
571 if (firstSizable == -1) | 601 if (firstSizable == -1) |
572 diff = adjustCellSizes (diff, minWidth.length-1, -1); | 602 diff = adjustCellSizes (diff, cols-1, -1); |
573 else | 603 else |
574 diff = adjustCellSizes (diff, (dir == -1 ? lastSizable : firstSizable), dir); | 604 diff = adjustCellSizes (diff, (dir == -1 ? lastSizable : firstSizable), dir); |
575 genPositions; | 605 genPositions; |
576 | 606 |
577 debug if (nw != w) { | 607 debug if (nw != w) { |
578 logger.trace ("resizeWidth on {} to {} failed, new width: {}, diff {}, firstSizable {}, columns {}",cast(void*)this, nw,w, diff, firstSizable, minWidth.length); | 608 logger.trace ("resizeWidth on {} to {} failed, new width: {}, diff {}, firstSizable {}, columns {}",cast(void*)this, nw,w, diff, firstSizable, cols); |
579 /+ Also print column widths & positions: | 609 /+ Also print column widths & positions: |
580 logger.trace ("resizeWidth to {} failed! Column dimensions and positions:",nw); | 610 logger.trace ("resizeWidth to {} failed! Column dimensions and positions:",nw); |
581 foreach (i,w; width) | 611 foreach (i,w; width) |
582 logger.trace ("\t{}\t{}", w,pos[i]);+/ | 612 logger.trace ("\t{}\t{}", w,pos[i]);+/ |
583 } | 613 } |
588 * | 618 * |
589 * This and resizeCols are for moving dividers between cells. */ | 619 * This and resizeCols are for moving dividers between cells. */ |
590 bool findResizeCols (wdim l) { | 620 bool findResizeCols (wdim l) { |
591 resizeU = -getCell (l); // potential start for upward-resizes | 621 resizeU = -getCell (l); // potential start for upward-resizes |
592 if (resizeU <= 0) | 622 if (resizeU <= 0) |
593 return true; // not on a space between cells | 623 return true; // not on a space between cells |
594 resizeD = resizeU - 1; // potential start for downward-resizes | 624 resizeD = resizeU - 1; // potential start for downward-resizes |
595 | 625 |
596 while (!sizable[resizeU]) { // find first actually resizable column (upwards) | 626 while (!sizable[resizeU]) { // find first actually resizable column (upwards) |
597 ++resizeU; | 627 ++resizeU; |
598 if (resizeU >= minWidth.length) { // cannot resize | 628 if (resizeU >= cols) { // cannot resize |
599 resizeU = -1; | 629 resizeU = -1; |
600 return true; | 630 return true; |
601 } | 631 } |
602 } | 632 } |
603 | 633 |
604 while (!sizable[resizeD]) { // find first actually resizable column (downwards) | 634 while (!sizable[resizeD]) { // find first actually resizable column (downwards) |
605 --resizeD; | 635 --resizeD; |
606 if (resizeD < 0) { // cannot resize | 636 if (resizeD < 0) { // cannot resize |
607 resizeU = -1; // resizeU is tested to check whether resizes are possible | 637 resizeU = -1; // resizeU is tested to check whether resizes are possible |
608 return true; | 638 return true; |
609 } | 639 } |
610 } | 640 } |
611 | 641 |
612 return false; // can resize | 642 return false; // can resize |
629 | 659 |
630 /** Called when one of the cells in column col now has minimal width nmw. | 660 /** Called when one of the cells in column col now has minimal width nmw. |
631 * | 661 * |
632 * Enlarges column minimal width if necessary; tries to keep total width the same but returns | 662 * Enlarges column minimal width if necessary; tries to keep total width the same but returns |
633 * true if it cannot. */ | 663 * true if it cannot. */ |
634 bool newMinWidth (myDiff col, wdim nmw) { | 664 bool newMinWidth (size_t col, size_t row, wdim nmw) { |
635 bool r = false; | 665 minCellWidths[col + row*cols] = nmw; |
636 if (minWidth[col] < nmw) { | 666 wdim nd = 0; // negative diff to keep overall size constant if possible |
667 if (minWidth[col] < nmw) { // increase minimal | |
637 minWidth[col] = nmw; | 668 minWidth[col] = nmw; |
638 wdim d = nmw - width[col]; | 669 nd = width[col] - nmw; // negative diff |
639 if (d > 0 || (d < 0 && !sizable[col])) { | 670 } else if (minWidth[col] > nmw) { // potentially decrease minimal |
640 d = -adjustCellSizes (d, col, -1); | 671 nmw = 0; |
641 if (d != adjustCellSizes (d, minWidth.length-1, -1)) | 672 for (size_t r = 0; r < rows; ++r) { |
642 r = true; // if unable to keep overall size the same | 673 wdim mcw = minCellWidths[col+r*cols]; |
643 genPositions; | 674 if (nmw < mcw) |
644 } | 675 nmw = mcw; |
645 mw = spacing * cast(wdim)(minWidth.length - 1); | 676 } |
646 foreach (imw; minWidth) | 677 minWidth[col] = nmw; |
647 mw += imw; | 678 if (!sizable[col]) |
648 } | 679 nd = width[col] - nmw; |
649 return r; | 680 } else |
681 return false; | |
682 | |
683 mw = spacing * cast(wdim)(cols - 1); | |
684 foreach (imw; minWidth) | |
685 mw += imw; | |
686 | |
687 if (nd != 0) { // needs enlarging | |
688 width[col] = nmw; | |
689 foreach (dg; setWidthCb) | |
690 dg(col, nmw, -1); | |
691 if (lastSizable >= 0) | |
692 adjustCellSizes (nd, lastSizable, -1); // doesn't necessarily resize exactly | |
693 genPositions; | |
694 } | |
695 | |
696 return true; | |
650 } | 697 } |
651 | 698 |
652 /* Generate position infomation for each column and set w. */ | 699 /* Generate position infomation for each column and set w. */ |
653 private void genPositions () { | 700 private void genPositions () { |
654 pos.length = minWidth.length; | 701 pos.length = cols; |
655 | 702 |
656 w = 0; | 703 w = 0; |
657 foreach (i, cw; width) { | 704 foreach (i, cw; width) { |
658 pos[i] = w; | 705 pos[i] = w; |
659 w += cw + spacing; | 706 w += cw + spacing; |
663 | 710 |
664 /* Adjust the total size of rows/columns (including spacing) by diff. | 711 /* Adjust the total size of rows/columns (including spacing) by diff. |
665 * | 712 * |
666 * Params: | 713 * Params: |
667 * diff = amount to increase/decrease the total size | 714 * diff = amount to increase/decrease the total size |
668 * start= index for col/row to start resizing on | 715 * start= index for col/row to start resizing on; assumed to be sizable |
669 * incr = direction to resize in (added to index each step). Must be either -1 or +1. | 716 * incr = direction to resize in (added to index each step). Must be either -1 or +1. |
670 * | 717 * |
671 * Returns: | 718 * Returns: |
672 * The amount adjusted. This may be larger than diff, since cellD is clamped by cellDMin. | 719 * The amount adjusted. This may be larger than diff, since cellD is clamped by cellDMin. |
673 * | 720 * |
721 * Doesn't touch non-sizable columns (except start which is only assumed sizable). | |
722 * | |
674 * Note: Check variable used for start is valid before calling! If a non-sizable column's | 723 * Note: Check variable used for start is valid before calling! If a non-sizable column's |
675 * index is passed, this should get increased (if diff > 0) but not decreased. | 724 * index is passed, this should get increased (if diff > 0) but not decreased. |
676 */ | 725 */ |
677 private wdim adjustCellSizes (wdim diff, myDiff start, int incr) | 726 private wdim adjustCellSizes (wdim diff, ptrdiff_t start, int incr) |
678 in { | 727 in { |
679 assert (width.length == minWidth.length, "CellAlign.adjustCellSizes: width is null (code error)"); | 728 assert (width.length == cols, "CellAlign.adjustCellSizes: width is invalid (code error)"); |
680 // Most likely if passed negative when sizing is disabled: | 729 // Most likely if passed negative when sizing is disabled: |
681 assert (start >= 0 && start < minWidth.length, "adjustCellSizes: invalid start"); | 730 assert (start >= 0 && start < cols, "adjustCellSizes: invalid start"); |
682 debug assert (incr == 1 || incr == -1, "adjustCellSizes: invalid incr"); | 731 debug assert (incr == 1 || incr == -1, "adjustCellSizes: invalid incr"); |
683 } body { | 732 } body { |
684 debug scope(failure) logger.trace ("adjustCellSizes: failure"); | 733 debug scope(failure) logger.trace ("adjustCellSizes: failure"); |
685 myDiff i = start; | 734 ptrdiff_t i = start; |
686 if (diff > 0) { // increase size of first resizable cell | 735 if (diff > 0) { // increase size of first resizable cell |
687 width[i] += diff; | 736 width[i] += diff; |
688 foreach (dg; setWidthCb) | 737 foreach (dg; setWidthCb) |
689 dg(i, width[i], incr); | 738 dg(i, width[i], incr); |
690 } | 739 } |
706 dg(i, width[i], incr); | 755 dg(i, width[i], incr); |
707 // rd is remainder to decrease by | 756 // rd is remainder to decrease by |
708 | 757 |
709 do { | 758 do { |
710 i += incr; | 759 i += incr; |
711 if (i < 0 || i >= minWidth.length) { // run out of next cells | 760 if (i < 0 || i >= cols) { // run out of next cells |
712 diff -= rd; // still had rd left to decrease | 761 diff -= rd; // still had rd left to decrease |
713 break aCSwhile; // exception: Array index out of bounds | 762 break aCSwhile; // exception: Array index out of bounds |
714 } | 763 } |
715 } while (!sizable[i]) // iterate again if row/col isn't resizable | 764 } while (!sizable[i]) // iterate again if row/col isn't resizable |
716 } | 765 } |
718 // else no adjustment needed (diff == 0) | 767 // else no adjustment needed (diff == 0) |
719 | 768 |
720 return diff; | 769 return diff; |
721 } | 770 } |
722 | 771 |
723 /** Minimal width for each column. | 772 |
724 * | 773 /** Minimal widths per cell. |
725 * Initialized to zero. Each class using this AlignColumns should, for each column, increase | 774 * |
726 * this value to the maximum of the minimal widths (in other words, set | 775 * Array of all cells, organised like GridLayoutWidget.subWidgets when representing columns, |
727 * minWidth[i] = max(minWidth[i], cell.minWidth) for each cell in column i). */ | 776 * with rows and columns swapped when representing rows. |
728 wdim[] minWidth; // minimal widths (set by genCachedConstructionData) | 777 * |
778 * Then minWidth[i] = min(minCellWidths[i]) (where min acts on an array). */ | |
779 wdim[] minCellWidths; | |
729 | 780 |
730 /** For each column i, sizable[i] is true if that column is resizable. | 781 /** For each column i, sizable[i] is true if that column is resizable. |
731 * | 782 * |
732 * Set along with minWidth before calling setWidths. */ | 783 * Set along with minWidth before calling setWidths. */ |
733 bool[] sizable; // set by genCachedConstructionData | 784 bool[] sizable; // set by genCachedConstructionData |
738 wdim[] width; // only adjusted within the class | 789 wdim[] width; // only adjusted within the class |
739 wdim[] pos; /// ditto | 790 wdim[] pos; /// ditto |
740 wdim spacing; // used by genPositions (which cannot access the layout class's data) | 791 wdim spacing; // used by genPositions (which cannot access the layout class's data) |
741 wdim w,mw; // current & minimal widths | 792 wdim w,mw; // current & minimal widths |
742 protected: | 793 protected: |
743 myDiff resizeD, // resizeCols works down from this index (<0 if not resizing) | 794 /* Minimal width for each column. |
795 * | |
796 * Set by setWidths. */ | |
797 wdim[] minWidth; | |
798 size_t cols, rows; // number of columns and rows (wrong way round when AlignColumns | |
799 // represents rows) | |
800 | |
801 ptrdiff_t resizeD, // resizeCols works down from this index (<0 if not resizing) | |
744 resizeU; // and up from this index | 802 resizeU; // and up from this index |
745 /* indicies of the first/last resizable column (negative if none are resizable). */ | 803 /* indicies of the first/last resizable column (negative if none are resizable). */ |
746 myDiff firstSizable = -1, lastSizable = -1; // set by calcFLSbl | 804 ptrdiff_t firstSizable = -1, lastSizable = -1; // set by calcFLSbl |
747 // Callbacks used to actually adjust a column's width: | 805 // Callbacks used to actually adjust a column's width: |
748 void delegate (myIt,wdim,int) setWidthCb[]; // set width of a column, with resize direction | 806 void delegate (size_t,wdim,int) setWidthCb[]; // set width of a column, with resize direction |
749 void delegate (uint,uint) sADD[]; // setupAlignDimData dlgs | 807 void delegate (uint,uint) sADD[]; // setupAlignDimData dlgs |
750 | 808 |
751 uint setup_n = uint.max; // param n of last setup call | 809 uint setup_n = uint.max; // param n of last setup call |
752 bool setupWidths; // setWidths has been run | 810 bool setupWidths; // setWidths has been run |
753 | 811 |
757 } | 815 } |
758 | 816 |
759 debug invariant() | 817 debug invariant() |
760 { | 818 { |
761 if (setupWidths) { | 819 if (setupWidths) { |
762 assert (width.length == minWidth.length); | 820 assert (width.length == cols, "invariant: bad width length"); |
763 wdim x = 0; | 821 wdim x = 0; |
764 foreach (i,w; width) { | 822 foreach (i,w; width) { |
765 assert (minWidth[i] <= w); // even when "not sizable", cols may get enlarged | 823 assert (minWidth[i] <= w, "invariant: min size not reached"); // even when "not sizable", cols may get enlarged |
766 assert (x == pos[i]); | 824 assert (x == pos[i], "invariant: position wrong"); |
767 x += w + spacing; | 825 x += w + spacing; |
768 } | 826 } |
769 assert (x - spacing == w); | 827 assert (x - spacing == w, "invariant: w is wrong"); |
770 x = spacing * cast(wdim)(minWidth.length - 1); | 828 x = spacing * cast(wdim)(cols - 1); |
771 foreach (mw; minWidth) | 829 foreach (mw; minWidth) |
772 x += mw; | 830 x += mw; |
773 assert (x == mw); | 831 assert (x == mw, "invariant: mw is wrong"); |
774 } | 832 } |
775 } | 833 } |
776 | 834 |
777 debug (mdeUnitTest) unittest { | 835 debug (mdeUnitTest) unittest { |
778 bool throws (void delegate() dg) { | 836 bool throws (void delegate() dg) { |
813 assert (b.width[3] == 12); | 871 assert (b.width[3] == 12); |
814 | 872 |
815 logger.info ("Unittest complete."); | 873 logger.info ("Unittest complete."); |
816 } | 874 } |
817 } | 875 } |
818 | |
819 // Index types. Note that in some cases they need to hold negative values. | |
820 // int is used for resizing direction (although ptrdiff_t would be more appropriate), | |
821 // since the value must always be -1 or +1. | |
822 alias size_t myIt; | |
823 alias ptrdiff_t myDiff; |