summaryrefslogtreecommitdiff
path: root/src/ui/widget.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-03-30 15:03:04 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-03-30 15:03:04 +0300
commit8ab2c6c2a27f888602ea05afaf05a75ecca9bf02 (patch)
treef6160a88fa05ae2fc6b34c04d96f5cc637f40ba4 /src/ui/widget.c
parent23f70040368e8d5577f89b2bacf303b5dac8561f (diff)
Widget: Arrangement debugging; min size
There is a problem with repeated arrangements: the previous set sizes affect subsequent outcomes. This results in Preferences not being able to reduce in size, only to expand. It should be possible to reset sizes back to zero/minimum size before starting an arrangement, but LabelWidget needs to cooperate by using `minSize` to set its default size. `minSize` is preferable to fixedSize because then the widget can go through the usual arranging logic. To be continued at a later time...
Diffstat (limited to 'src/ui/widget.c')
-rw-r--r--src/ui/widget.c222
1 files changed, 176 insertions, 46 deletions
diff --git a/src/ui/widget.c b/src/ui/widget.c
index 91f6c12d..baabf673 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -86,6 +86,7 @@ void init_Widget(iWidget *d) {
86 init_String(&d->id); 86 init_String(&d->id);
87 d->flags = 0; 87 d->flags = 0;
88 d->rect = zero_Rect(); 88 d->rect = zero_Rect();
89 d->minSize = zero_I2();
89 d->bgColor = none_ColorId; 90 d->bgColor = none_ColorId;
90 d->frameColor = none_ColorId; 91 d->frameColor = none_ColorId;
91 init_Anim(&d->visualOffset, 0.0f); 92 init_Anim(&d->visualOffset, 0.0f);
@@ -188,20 +189,25 @@ void setPos_Widget(iWidget *d, iInt2 pos) {
188 setFlags_Widget(d, fixedPosition_WidgetFlag, iTrue); 189 setFlags_Widget(d, fixedPosition_WidgetFlag, iTrue);
189} 190}
190 191
191void setSize_Widget(iWidget *d, iInt2 size) { 192void setFixedSize_Widget(iWidget *d, iInt2 fixedSize) {
192 int flags = fixedSize_WidgetFlag; 193 int flags = fixedSize_WidgetFlag;
193 if (size.x < 0) { 194 if (fixedSize.x < 0) {
194 size.x = d->rect.size.x; 195 fixedSize.x = d->rect.size.x;
195 flags &= ~fixedWidth_WidgetFlag; 196 flags &= ~fixedWidth_WidgetFlag;
196 } 197 }
197 if (size.y < 0) { 198 if (fixedSize.y < 0) {
198 size.y = d->rect.size.y; 199 fixedSize.y = d->rect.size.y;
199 flags &= ~fixedHeight_WidgetFlag; 200 flags &= ~fixedHeight_WidgetFlag;
200 } 201 }
201 d->rect.size = size; 202 d->rect.size = fixedSize;
202 setFlags_Widget(d, flags, iTrue); 203 setFlags_Widget(d, flags, iTrue);
203} 204}
204 205
206void setMinSize_Widget(iWidget *d, iInt2 minSize) {
207 d->minSize = minSize;
208 /* rearranging needed to apply this */
209}
210
205void setPadding_Widget(iWidget *d, int left, int top, int right, int bottom) { 211void setPadding_Widget(iWidget *d, int left, int top, int right, int bottom) {
206 d->padding[0] = left; 212 d->padding[0] = left;
207 d->padding[1] = top; 213 d->padding[1] = top;
@@ -268,33 +274,79 @@ static int widestChild_Widget_(const iWidget *d) {
268 return width; 274 return width;
269} 275}
270 276
277static void arrange_Widget_(iWidget *);
278static const iBool tracing_ = iFalse;
279
280#define TRACE(d, ...) if (tracing_) { printf_Widget_(d, __VA_ARGS__); }
281
282static int depth_Widget_(const iWidget *d) {
283 int depth = 0;
284 for (const iWidget *w = d->parent; w; w = w->parent) {
285 depth++;
286 }
287 return depth;
288}
289
290static void printf_Widget_(const iWidget *d, const char *format, ...) {
291 va_list args;
292 va_start(args, format);
293 iString *msg = new_String();
294 for (size_t i = 0; i < depth_Widget_(d); ++i) {
295 appendCStr_String(msg, "| ");
296 }
297 appendFormat_String(msg, "[%p] %s(%s) ", d, class_Widget(d)->name, cstr_String(id_Widget(d)));
298 while (size_String(msg) < 44 + depth_Widget_(d) * 4) {
299 appendCStr_String(msg, " ");
300 }
301 iBlock *msg2 = new_Block(0);
302 vprintf_Block(msg2, format, args);
303 va_end(args);
304 printf("%s%s\n", cstr_String(msg), cstr_Block(msg2));
305 delete_Block(msg2);
306 delete_String(msg);
307}
308
271static void setWidth_Widget_(iWidget *d, int width) { 309static void setWidth_Widget_(iWidget *d, int width) {
272 iAssert(width >= 0); 310 iAssert(width >= 0);
311 TRACE(d, "attempt to set width to %d (current: %d, min width: %d)", width, d->rect.size.x, d->minSize.x);
312 width = iMax(width, d->minSize.x);
273 if (~d->flags & fixedWidth_WidgetFlag || d->flags & collapse_WidgetFlag) { 313 if (~d->flags & fixedWidth_WidgetFlag || d->flags & collapse_WidgetFlag) {
274 if (d->rect.size.x != width) { 314 if (d->rect.size.x != width) {
275 d->rect.size.x = width; 315 d->rect.size.x = width;
316 TRACE(d, "width has changed to %d", width);
276 if (class_Widget(d)->sizeChanged) { 317 if (class_Widget(d)->sizeChanged) {
277 const int oldHeight = d->rect.size.y; 318 const int oldHeight = d->rect.size.y;
278 class_Widget(d)->sizeChanged(d); 319 class_Widget(d)->sizeChanged(d);
279 if (d->rect.size.y != oldHeight) { 320 if (d->rect.size.y != oldHeight) {
321 TRACE(d, "sizeChanged() cuased height change to %d; redoing parent", d->rect.size.y);
280 /* Widget updated its height. */ 322 /* Widget updated its height. */
281 arrange_Widget(d->parent); 323 arrange_Widget_(d->parent);
324 TRACE(d, "parent layout redone");
282 } 325 }
283 } 326 }
284 } 327 }
285 } 328 }
329 else {
330 TRACE(d, "changing width not allowed; flags: %x", d->flags);
331 }
286} 332}
287 333
288static void setHeight_Widget_(iWidget *d, int height) { 334static void setHeight_Widget_(iWidget *d, int height) {
289 iAssert(height >= 0); 335 iAssert(height >= 0);
336 TRACE(d, "attempt to set height to %d (current: %d, min height: %d)", height, d->rect.size.y, d->minSize.y);
337 height = iMax(height, d->minSize.y);
290 if (~d->flags & fixedHeight_WidgetFlag || d->flags & collapse_WidgetFlag) { 338 if (~d->flags & fixedHeight_WidgetFlag || d->flags & collapse_WidgetFlag) {
291 if (d->rect.size.y != height) { 339 if (d->rect.size.y != height) {
292 d->rect.size.y = height; 340 d->rect.size.y = height;
341 TRACE(d, "height has changed to %d", height);
293 if (class_Widget(d)->sizeChanged) { 342 if (class_Widget(d)->sizeChanged) {
294 class_Widget(d)->sizeChanged(d); 343 class_Widget(d)->sizeChanged(d);
295 } 344 }
296 } 345 }
297 } 346 }
347 else {
348 TRACE(d, "changing height not allowed; flags: %x", d->flags);
349 }
298} 350}
299 351
300iLocalDef iBool isCollapsed_Widget_(const iWidget *d) { 352iLocalDef iBool isCollapsed_Widget_(const iWidget *d) {
@@ -336,29 +388,63 @@ static void centerHorizontal_Widget_(iWidget *d) {
336 : rootSize_Window(get_Window()).x) - 388 : rootSize_Window(get_Window()).x) -
337 width_Rect(d->rect)) / 389 width_Rect(d->rect)) /
338 2; 390 2;
391 TRACE(d, "center horizontally: %d", d->rect.pos.x);
339} 392}
340 393
341void arrange_Widget(iWidget *d) { 394static void boundsOfChildren_Widget_(const iWidget *d, iRect *bounds_out) {
395 *bounds_out = zero_Rect();
396 iConstForEach(ObjectList, i, d->children) {
397 const iWidget *child = constAs_Widget(i.object);
398 if (isCollapsed_Widget_(child)) {
399 continue;
400 }
401 iRect childRect = child->rect;
402 if (child->flags & ignoreForParentWidth_WidgetFlag) {
403 childRect.size.x = 0;
404 }
405 if (isEmpty_Rect(*bounds_out)) {
406 *bounds_out = childRect;
407 }
408 else {
409 *bounds_out = union_Rect(*bounds_out, childRect);
410 }
411 }
412}
413
414static void arrange_Widget_(iWidget *d) {
415 TRACE(d, "arranging...");
342 if (isCollapsed_Widget_(d)) { 416 if (isCollapsed_Widget_(d)) {
417 TRACE(d, "collapsed => END");
343 setFlags_Widget(d, wasCollapsed_WidgetFlag, iTrue); 418 setFlags_Widget(d, wasCollapsed_WidgetFlag, iTrue);
344 return; 419 return;
345 } 420 }
346 if (d->flags & moveToParentLeftEdge_WidgetFlag) { 421 if (d->flags & moveToParentLeftEdge_WidgetFlag) {
347 d->rect.pos.x = d->padding[0]; /* FIXME: Shouldn't this be d->parent->padding[0]? */ 422 d->rect.pos.x = d->padding[0]; /* FIXME: Shouldn't this be d->parent->padding[0]? */
423 TRACE(d, "move to parent left edge: %d", d->rect.pos.x);
348 } 424 }
349 else if (d->flags & moveToParentRightEdge_WidgetFlag) { 425 else if (d->flags & moveToParentRightEdge_WidgetFlag) {
350 d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect); 426 d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect);
427 TRACE(d, "move to parent right edge: %d", d->rect.pos.x);
351 } 428 }
352 else if (d->flags & moveToParentBottomEdge_WidgetFlag) { 429 else if (d->flags & moveToParentBottomEdge_WidgetFlag) {
353 d->rect.pos.y = height_Rect(innerRect_Widget_(d->parent)) - height_Rect(d->rect); 430 d->rect.pos.y = height_Rect(innerRect_Widget_(d->parent)) - height_Rect(d->rect);
431 TRACE(d, "move to parent bottom edge: %d", d->rect.pos.y);
354 } 432 }
355 else if (d->flags & centerHorizontal_WidgetFlag) { 433 else if (d->flags & centerHorizontal_WidgetFlag) {
356 centerHorizontal_Widget_(d); 434 centerHorizontal_Widget_(d);
357 } 435 }
358 if (d->flags & resizeToParentWidth_WidgetFlag) { 436 if (d->flags & resizeToParentWidth_WidgetFlag) {
359 setWidth_Widget_(d, width_Rect(innerRect_Widget_(d->parent))); 437 iRect childBounds = zero_Rect();
438 if (flags_Widget(d->parent) & arrangeWidth_WidgetFlag) {
439 /* Can't go narrower than what the children require, though. */
440 boundsOfChildren_Widget_(d, &childBounds);
441 }
442 TRACE(d, "resize to parent width; child bounds width %d", childBounds.size.x, childBounds.size.y);
443 setWidth_Widget_(d, iMaxi(width_Rect(innerRect_Widget_(d->parent)),
444 width_Rect(childBounds)));
360 } 445 }
361 if (d->flags & resizeToParentHeight_WidgetFlag) { 446 if (d->flags & resizeToParentHeight_WidgetFlag) {
447 TRACE(d, "resize to parent height");
362 setHeight_Widget_(d, height_Rect(innerRect_Widget_(d->parent))); 448 setHeight_Widget_(d, height_Rect(innerRect_Widget_(d->parent)));
363 } 449 }
364 if (d->flags & safePadding_WidgetFlag) { 450 if (d->flags & safePadding_WidgetFlag) {
@@ -370,46 +456,44 @@ void arrange_Widget(iWidget *d) {
370 } 456 }
371 /* The rest of the arrangement depends on child widgets. */ 457 /* The rest of the arrangement depends on child widgets. */
372 if (!d->children) { 458 if (!d->children) {
459 TRACE(d, "no children => END");
373 return; 460 return;
374 } 461 }
375 const size_t childCount = numArrangedChildren_Widget_(d); 462 const size_t childCount = numArrangedChildren_Widget_(d);
376 /* There may still be unarranged children that need arranging internally. */ 463 TRACE(d, "%d arranged children", childCount);
377 if (childCount == 0) {
378 iForEach(ObjectList, i, d->children) {
379 iWidget *child = as_Widget(i.object);
380 if (isArranged_Widget_(child)) {
381 arrange_Widget(child);
382 }
383 }
384 return;
385 }
386 /* Resize children to fill the parent widget. */ 464 /* Resize children to fill the parent widget. */
387 if (d->flags & resizeChildren_WidgetFlag) { 465 if (d->flags & resizeChildren_WidgetFlag) {
388 const iInt2 dirs = init_I2((d->flags & resizeWidthOfChildren_WidgetFlag) != 0, 466 const iInt2 dirs = init_I2((d->flags & resizeWidthOfChildren_WidgetFlag) != 0,
389 (d->flags & resizeHeightOfChildren_WidgetFlag) != 0); 467 (d->flags & resizeHeightOfChildren_WidgetFlag) != 0);
468 TRACE(d, "resize children, x:%d y:%d", dirs.x, dirs.y);
390 /* Collapse hidden children. */ 469 /* Collapse hidden children. */
391 iBool collapseChanged = iFalse; 470 iBool collapseChanged = iFalse;
392 iForEach(ObjectList, c, d->children) { 471 iForEach(ObjectList, c, d->children) {
393 iWidget *child = as_Widget(c.object); 472 iWidget *child = as_Widget(c.object);
394 if (!isCollapsed_Widget_(child) && child->flags & wasCollapsed_WidgetFlag) { 473 if (!isCollapsed_Widget_(child) && child->flags & wasCollapsed_WidgetFlag) {
395 setFlags_Widget(child, wasCollapsed_WidgetFlag, iFalse); 474 setFlags_Widget(child, wasCollapsed_WidgetFlag, iFalse);
475 TRACE(d, "child %p is uncollapsed", child);
396 /* Undo collapse and determine the normal size again. */ 476 /* Undo collapse and determine the normal size again. */
397 arrange_Widget(d); 477 arrange_Widget_(d);
398 collapseChanged = iTrue; 478 collapseChanged = iTrue;
399 } 479 }
400 else if (isCollapsed_Widget_(child) && ~child->flags & wasCollapsed_WidgetFlag) { 480 else if (isCollapsed_Widget_(child) && ~child->flags & wasCollapsed_WidgetFlag) {
401 setFlags_Widget(child, wasCollapsed_WidgetFlag, iTrue); 481 setFlags_Widget(child, wasCollapsed_WidgetFlag, iTrue);
402 collapseChanged = iTrue; 482 collapseChanged = iTrue;
483 TRACE(d, "child %p flagged as collapsed", child);
403 } 484 }
404 } 485 }
405 if (collapseChanged) { 486 if (collapseChanged) {
406 arrange_Widget(d); /* Redo with the new child sizes. */ 487 TRACE(d, "redoing arrangement due to changes in child collapse state");
488 arrange_Widget_(d); /* Redo with the new child sizes. */
407 return; 489 return;
408 } 490 }
409 const int expCount = numExpandingChildren_Widget_(d); 491 const int expCount = numExpandingChildren_Widget_(d);
492 TRACE(d, "%d expanding children", expCount);
410 /* Only resize the expanding children, not touching the others. */ 493 /* Only resize the expanding children, not touching the others. */
411 if (expCount > 0) { 494 if (expCount > 0) {
412 iInt2 avail = innerRect_Widget_(d).size; 495 iInt2 avail = innerRect_Widget_(d).size;
496 TRACE(d, "inner size: %dx%d", avail.x, avail.y);
413 iConstForEach(ObjectList, i, d->children) { 497 iConstForEach(ObjectList, i, d->children) {
414 const iWidget *child = constAs_Widget(i.object); 498 const iWidget *child = constAs_Widget(i.object);
415 if (!isArranged_Widget_(child)) { 499 if (!isArranged_Widget_(child)) {
@@ -420,9 +504,11 @@ void arrange_Widget(iWidget *d) {
420 } 504 }
421 } 505 }
422 avail = divi_I2(max_I2(zero_I2(), avail), expCount); 506 avail = divi_I2(max_I2(zero_I2(), avail), expCount);
507 TRACE(d, "changing child sizes (expand mode)...");
423 iForEach(ObjectList, j, d->children) { 508 iForEach(ObjectList, j, d->children) {
424 iWidget *child = as_Widget(j.object); 509 iWidget *child = as_Widget(j.object);
425 if (!isArranged_Widget_(child)) { 510 if (!isArranged_Widget_(child)) {
511 TRACE(d, "child %p is not arranged", child);
426 continue; 512 continue;
427 } 513 }
428 if (child->flags & expand_WidgetFlag) { 514 if (child->flags & expand_WidgetFlag) {
@@ -445,6 +531,7 @@ void arrange_Widget(iWidget *d) {
445 } 531 }
446 } 532 }
447 } 533 }
534 TRACE(d, "...done changing child sizes (expand mode)");
448 } 535 }
449 else { 536 else {
450 /* Evenly size all children. */ 537 /* Evenly size all children. */
@@ -458,6 +545,7 @@ void arrange_Widget(iWidget *d) {
458 childSize.y /= childCount; 545 childSize.y /= childCount;
459 unpaddedChildSize.y /= childCount; 546 unpaddedChildSize.y /= childCount;
460 } 547 }
548 TRACE(d, "begin changing child sizes (EVEN mode)...");
461 iForEach(ObjectList, i, d->children) { 549 iForEach(ObjectList, i, d->children) {
462 iWidget *child = as_Widget(i.object); 550 iWidget *child = as_Widget(i.object);
463 if (isArranged_Widget_(child) && ~child->flags & parentCannotResize_WidgetFlag) { 551 if (isArranged_Widget_(child) && ~child->flags & parentCannotResize_WidgetFlag) {
@@ -468,34 +556,52 @@ void arrange_Widget(iWidget *d) {
468 setHeight_Widget_(child, child->flags & unpadded_WidgetFlag ? unpaddedChildSize.y : childSize.y); 556 setHeight_Widget_(child, child->flags & unpadded_WidgetFlag ? unpaddedChildSize.y : childSize.y);
469 } 557 }
470 } 558 }
559 else {
560 TRACE(d, "child %p cannot be resized (parentCannotResize: %d)", child,
561 (child->flags & parentCannotResize_WidgetFlag) != 0);
562 }
471 } 563 }
564 TRACE(d, "...done changing child sizes (EVEN mode)");
472 } 565 }
473 } 566 }
474 if (d->flags & resizeChildrenToWidestChild_WidgetFlag) { 567 if (d->flags & resizeChildrenToWidestChild_WidgetFlag) {
475 const int widest = widestChild_Widget_(d); 568 const int widest = widestChild_Widget_(d);
569 TRACE(d, "resizing children to widest child (%d)...", widest);
476 iForEach(ObjectList, i, d->children) { 570 iForEach(ObjectList, i, d->children) {
477 iWidget *child = as_Widget(i.object); 571 iWidget *child = as_Widget(i.object);
478 if (isArranged_Widget_(child) && ~child->flags & parentCannotResize_WidgetFlag) { 572 if (isArranged_Widget_(child) && ~child->flags & parentCannotResize_WidgetFlag) {
479 setWidth_Widget_(child, widest); 573 setWidth_Widget_(child, widest);
480 } 574 }
575 else {
576 TRACE(d, "child %p cannot be resized (parentCannotResize: %d)", child,
577 (child->flags & parentCannotResize_WidgetFlag) != 0);
578 }
481 } 579 }
580 TRACE(d, "...done resizing children to widest child");
482 } 581 }
483 iInt2 pos = initv_I2(d->padding); 582 iInt2 pos = initv_I2(d->padding);
583 TRACE(d, "begin positioning children from %d,%d (flags:%s%s)...", pos.x, pos.y,
584 d->flags & arrangeHorizontal_WidgetFlag ? " horiz" : "",
585 d->flags & arrangeVertical_WidgetFlag ? " vert" : "");
484 iForEach(ObjectList, i, d->children) { 586 iForEach(ObjectList, i, d->children) {
485 iWidget *child = as_Widget(i.object); 587 iWidget *child = as_Widget(i.object);
486 arrange_Widget(child); 588 arrange_Widget_(child);
487 if (!isArranged_Widget_(child)) { 589 if (!isArranged_Widget_(child)) {
590 TRACE(d, "child %p arranging prohibited", child);
488 continue; 591 continue;
489 } 592 }
490 if (child->flags & centerHorizontal_WidgetFlag) { 593 if (child->flags & centerHorizontal_WidgetFlag) {
594 TRACE(d, "child %p is centered, skipping", child);
491 continue; 595 continue;
492 } 596 }
493 if (d->flags & (arrangeHorizontal_WidgetFlag | arrangeVertical_WidgetFlag)) { 597 if (d->flags & (arrangeHorizontal_WidgetFlag | arrangeVertical_WidgetFlag)) {
494 if (child->flags & 598 if (child->flags &
495 (moveToParentLeftEdge_WidgetFlag | moveToParentRightEdge_WidgetFlag)) { 599 (moveToParentLeftEdge_WidgetFlag | moveToParentRightEdge_WidgetFlag)) {
600 TRACE(d, "child %p is attached an edge, skipping", child);
496 continue; /* Not part of the sequential arrangement .*/ 601 continue; /* Not part of the sequential arrangement .*/
497 } 602 }
498 child->rect.pos = pos; 603 child->rect.pos = pos;
604 TRACE(d, "child %p set position to %d,%d", child, pos.x, pos.y);
499 if (d->flags & arrangeHorizontal_WidgetFlag) { 605 if (d->flags & arrangeHorizontal_WidgetFlag) {
500 pos.x += child->rect.size.x; 606 pos.x += child->rect.size.x;
501 } 607 }
@@ -506,30 +612,20 @@ void arrange_Widget(iWidget *d) {
506 else if ((d->flags & resizeChildren_WidgetFlag) == resizeChildren_WidgetFlag && 612 else if ((d->flags & resizeChildren_WidgetFlag) == resizeChildren_WidgetFlag &&
507 ~child->flags & moveToParentBottomEdge_WidgetFlag) { 613 ~child->flags & moveToParentBottomEdge_WidgetFlag) {
508 child->rect.pos = pos; 614 child->rect.pos = pos;
615 TRACE(d, "child %p set position to %d,%d (not sequential, children being resized)", child, pos.x, pos.y);
509 } 616 }
510 else if (d->flags & resizeWidthOfChildren_WidgetFlag) { 617 else if (d->flags & resizeWidthOfChildren_WidgetFlag) {
511 child->rect.pos.x = pos.x; 618 child->rect.pos.x = pos.x;
619 TRACE(d, "child %p set X to %d (not sequential, children being resized)", child, pos.x);
512 } 620 }
513 } 621 }
622 TRACE(d, "...done positioning children");
514 /* Update the size of the widget according to the arrangement. */ 623 /* Update the size of the widget according to the arrangement. */
515 if (d->flags & arrangeSize_WidgetFlag) { 624 if (d->flags & arrangeSize_WidgetFlag) {
516 iRect bounds = zero_Rect(); 625 iRect bounds;
517 iConstForEach(ObjectList, i, d->children) { 626 boundsOfChildren_Widget_(d, &bounds);
518 const iWidget *child = constAs_Widget(i.object); 627 TRACE(d, "begin arranging own size; bounds of children: %d,%d %dx%d",
519 if (isCollapsed_Widget_(child)) { 628 bounds.pos.x, bounds.pos.y, bounds.size.x, bounds.size.y);
520 continue;
521 }
522 iRect childRect = child->rect;
523 if (child->flags & ignoreForParentWidth_WidgetFlag) {
524 childRect.size.x = 0;
525 }
526 if (isEmpty_Rect(bounds)) {
527 bounds = childRect;
528 }
529 else {
530 bounds = union_Rect(bounds, childRect);
531 }
532 }
533 adjustEdges_Rect(&bounds, -d->padding[1], d->padding[2], d->padding[3], -d->padding[0]); 629 adjustEdges_Rect(&bounds, -d->padding[1], d->padding[2], d->padding[3], -d->padding[0]);
534 if (d->flags & arrangeWidth_WidgetFlag) { 630 if (d->flags & arrangeWidth_WidgetFlag) {
535 setWidth_Widget_(d, bounds.size.x); 631 setWidth_Widget_(d, bounds.size.x);
@@ -539,14 +635,15 @@ void arrange_Widget(iWidget *d) {
539 if (child->flags & 635 if (child->flags &
540 (resizeToParentWidth_WidgetFlag | 636 (resizeToParentWidth_WidgetFlag |
541 moveToParentLeftEdge_WidgetFlag | 637 moveToParentLeftEdge_WidgetFlag |
542 moveToParentBottomEdge_WidgetFlag |
543 moveToParentRightEdge_WidgetFlag)) { 638 moveToParentRightEdge_WidgetFlag)) {
544 arrange_Widget(child); 639 TRACE(d, "rearranging child %p because its size or position depends on parent width", child);
640 arrange_Widget_(child);
545 } 641 }
546 } 642 }
547 if (d->flags & moveToParentRightEdge_WidgetFlag) { 643 if (d->flags & moveToParentRightEdge_WidgetFlag) {
548 /* TODO: Fix this: not DRY. See beginning of method. */ 644 /* TODO: Fix this: not DRY. See beginning of method. */
549 d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect); 645 d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect);
646 TRACE(d, "after width change moving to right edge of parent, set X to %d", d, d->rect.pos.x);
550 } 647 }
551 } 648 }
552 if (d->flags & arrangeHeight_WidgetFlag) { 649 if (d->flags & arrangeHeight_WidgetFlag) {
@@ -554,8 +651,10 @@ void arrange_Widget(iWidget *d) {
554 /* Parent size changed, must update the children.*/ 651 /* Parent size changed, must update the children.*/
555 iForEach(ObjectList, j, d->children) { 652 iForEach(ObjectList, j, d->children) {
556 iWidget *child = as_Widget(j.object); 653 iWidget *child = as_Widget(j.object);
557 if (child->flags & resizeToParentHeight_WidgetFlag) { 654 if (child->flags & (resizeToParentHeight_WidgetFlag |
558 arrange_Widget(child); 655 moveToParentBottomEdge_WidgetFlag)) {
656 TRACE(d, "rearranging child %p because its size or position depends on parent height", child);
657 arrange_Widget_(child);
559 } 658 }
560 } 659 }
561 } 660 }
@@ -566,9 +665,31 @@ void arrange_Widget(iWidget *d) {
566 if (d->flags & centerHorizontal_WidgetFlag) { 665 if (d->flags & centerHorizontal_WidgetFlag) {
567 centerHorizontal_Widget_(d); 666 centerHorizontal_Widget_(d);
568 } 667 }
668 TRACE(d, "...done arranging own size");
669 }
670 TRACE(d, "END");
671}
672
673void resetSize_Widget(iWidget *d) {
674 if (~d->flags & fixedWidth_WidgetFlag) {
675 d->rect.size.x = d->minSize.x;
676 }
677 if (~d->flags & fixedHeight_WidgetFlag) {
678 d->rect.size.y = d->minSize.y;
679 }
680 iForEach(ObjectList, i, children_Widget(d)) {
681 iWidget *child = as_Widget(i.object);
682 if (isArranged_Widget_(child)) {
683 resetSize_Widget(child);
684 }
569 } 685 }
570} 686}
571 687
688void arrange_Widget(iWidget *d) {
689 //resetSize_Widget_(d); /* back to initial default sizes */
690 arrange_Widget_(d);
691}
692
572static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) { 693static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) {
573 if (d->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) { 694 if (d->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) {
574 const int off = iRound(value_Anim(&d->visualOffset)); 695 const int off = iRound(value_Anim(&d->visualOffset));
@@ -1354,6 +1475,7 @@ void refresh_Widget(const iAnyObject *d) {
1354 postRefresh_App(); 1475 postRefresh_App();
1355} 1476}
1356 1477
1478/* Debug utility for inspecting widget trees. */
1357#include "labelwidget.h" 1479#include "labelwidget.h"
1358static void printTree_Widget_(const iWidget *d, int indent) { 1480static void printTree_Widget_(const iWidget *d, int indent) {
1359 for (int i = 0; i < indent; ++i) { 1481 for (int i = 0; i < indent; ++i) {
@@ -1365,9 +1487,17 @@ static void printTree_Widget_(const iWidget *d, int indent) {
1365 cstr_String(text_LabelWidget((const iLabelWidget *) d)), 1487 cstr_String(text_LabelWidget((const iLabelWidget *) d)),
1366 cstr_String(command_LabelWidget((const iLabelWidget *) d))); 1488 cstr_String(command_LabelWidget((const iLabelWidget *) d)));
1367 } 1489 }
1368 printf("size:%dx%d [%d..%d %d:%d] flags:%08llx%s\n", d->rect.size.x, d->rect.size.y, 1490 printf("size:%dx%d {min:%dx%d} [%d..%d %d:%d] flags:%08llx%s%s%s%s%s\n",
1369 d->padding[0], d->padding[2], d->padding[1], d->padding[3], 1491 d->rect.size.x, d->rect.size.y,
1370 (long long unsigned int) d->flags, d->flags & tight_WidgetFlag ? " tight" : ""); 1492 d->minSize.x, d->minSize.y,
1493 d->padding[0], d->padding[2],
1494 d->padding[1], d->padding[3],
1495 (long long unsigned int) d->flags,
1496 d->flags & expand_WidgetFlag ? " exp" : "",
1497 d->flags & tight_WidgetFlag ? " tight" : "",
1498 d->flags & fixedWidth_WidgetFlag ? " fixW" : "",
1499 d->flags & fixedHeight_WidgetFlag ? " fixH" : "",
1500 d->flags & resizeToParentWidth_WidgetFlag ? " rsPrnW" : "");
1371 iConstForEach(ObjectList, i, d->children) { 1501 iConstForEach(ObjectList, i, d->children) {
1372 printTree_Widget_(i.object, indent + 1); 1502 printTree_Widget_(i.object, indent + 1);
1373 } 1503 }