summaryrefslogtreecommitdiff
path: root/src/ui/widget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/widget.c')
-rw-r--r--src/ui/widget.c218
1 files changed, 176 insertions, 42 deletions
diff --git a/src/ui/widget.c b/src/ui/widget.c
index e19a9482..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,26 +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 if (isEmpty_Rect(bounds)) {
523 bounds = child->rect;
524 }
525 else {
526 bounds = union_Rect(bounds, child->rect);
527 }
528 }
529 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]);
530 if (d->flags & arrangeWidth_WidgetFlag) { 630 if (d->flags & arrangeWidth_WidgetFlag) {
531 setWidth_Widget_(d, bounds.size.x); 631 setWidth_Widget_(d, bounds.size.x);
@@ -535,14 +635,15 @@ void arrange_Widget(iWidget *d) {
535 if (child->flags & 635 if (child->flags &
536 (resizeToParentWidth_WidgetFlag | 636 (resizeToParentWidth_WidgetFlag |
537 moveToParentLeftEdge_WidgetFlag | 637 moveToParentLeftEdge_WidgetFlag |
538 moveToParentBottomEdge_WidgetFlag |
539 moveToParentRightEdge_WidgetFlag)) { 638 moveToParentRightEdge_WidgetFlag)) {
540 arrange_Widget(child); 639 TRACE(d, "rearranging child %p because its size or position depends on parent width", child);
640 arrange_Widget_(child);
541 } 641 }
542 } 642 }
543 if (d->flags & moveToParentRightEdge_WidgetFlag) { 643 if (d->flags & moveToParentRightEdge_WidgetFlag) {
544 /* TODO: Fix this: not DRY. See beginning of method. */ 644 /* TODO: Fix this: not DRY. See beginning of method. */
545 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);
546 } 647 }
547 } 648 }
548 if (d->flags & arrangeHeight_WidgetFlag) { 649 if (d->flags & arrangeHeight_WidgetFlag) {
@@ -550,8 +651,10 @@ void arrange_Widget(iWidget *d) {
550 /* Parent size changed, must update the children.*/ 651 /* Parent size changed, must update the children.*/
551 iForEach(ObjectList, j, d->children) { 652 iForEach(ObjectList, j, d->children) {
552 iWidget *child = as_Widget(j.object); 653 iWidget *child = as_Widget(j.object);
553 if (child->flags & resizeToParentHeight_WidgetFlag) { 654 if (child->flags & (resizeToParentHeight_WidgetFlag |
554 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);
555 } 658 }
556 } 659 }
557 } 660 }
@@ -562,9 +665,31 @@ void arrange_Widget(iWidget *d) {
562 if (d->flags & centerHorizontal_WidgetFlag) { 665 if (d->flags & centerHorizontal_WidgetFlag) {
563 centerHorizontal_Widget_(d); 666 centerHorizontal_Widget_(d);
564 } 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 }
565 } 685 }
566} 686}
567 687
688void arrange_Widget(iWidget *d) {
689 //resetSize_Widget_(d); /* back to initial default sizes */
690 arrange_Widget_(d);
691}
692
568static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) { 693static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) {
569 if (d->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) { 694 if (d->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) {
570 const int off = iRound(value_Anim(&d->visualOffset)); 695 const int off = iRound(value_Anim(&d->visualOffset));
@@ -1350,6 +1475,7 @@ void refresh_Widget(const iAnyObject *d) {
1350 postRefresh_App(); 1475 postRefresh_App();
1351} 1476}
1352 1477
1478/* Debug utility for inspecting widget trees. */
1353#include "labelwidget.h" 1479#include "labelwidget.h"
1354static void printTree_Widget_(const iWidget *d, int indent) { 1480static void printTree_Widget_(const iWidget *d, int indent) {
1355 for (int i = 0; i < indent; ++i) { 1481 for (int i = 0; i < indent; ++i) {
@@ -1361,9 +1487,17 @@ static void printTree_Widget_(const iWidget *d, int indent) {
1361 cstr_String(text_LabelWidget((const iLabelWidget *) d)), 1487 cstr_String(text_LabelWidget((const iLabelWidget *) d)),
1362 cstr_String(command_LabelWidget((const iLabelWidget *) d))); 1488 cstr_String(command_LabelWidget((const iLabelWidget *) d)));
1363 } 1489 }
1364 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",
1365 d->padding[0], d->padding[2], d->padding[1], d->padding[3], 1491 d->rect.size.x, d->rect.size.y,
1366 (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" : "");
1367 iConstForEach(ObjectList, i, d->children) { 1501 iConstForEach(ObjectList, i, d->children) {
1368 printTree_Widget_(i.object, indent + 1); 1502 printTree_Widget_(i.object, indent + 1);
1369 } 1503 }