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;