diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-05-19 11:52:24 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-05-19 11:52:24 +0300 |
commit | d2a76230effce8586b7d90beff519e221e744bf7 (patch) | |
tree | ec72b695c4d7e96f64219d5d8a754d37cce0e9db /src | |
parent | 31840540e60d85ddef2642d9a748258d45241186 (diff) |
Widget: Fixed arrangement bug
Whenever a widget is resized, we may need to rearrange its children. The up-to-date sizes must be used for determining positions for other children.
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/documentwidget.c | 5 | ||||
-rw-r--r-- | src/ui/widget.c | 46 |
2 files changed, 33 insertions, 18 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index e227bcef..0906a1d4 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -571,10 +571,11 @@ static float normScrollPos_DocumentWidget_(const iDocumentWidget *d) { | |||
571 | } | 571 | } |
572 | 572 | ||
573 | static int scrollMax_DocumentWidget_(const iDocumentWidget *d) { | 573 | static int scrollMax_DocumentWidget_(const iDocumentWidget *d) { |
574 | int sm = size_GmDocument(d->doc).y - height_Rect(bounds_Widget(constAs_Widget(d))) + | 574 | const iWidget *w = constAs_Widget(d); |
575 | int sm = size_GmDocument(d->doc).y - height_Rect(bounds_Widget(w)) + | ||
575 | (hasSiteBanner_GmDocument(d->doc) ? 1 : 2) * d->pageMargin * gap_UI; | 576 | (hasSiteBanner_GmDocument(d->doc) ? 1 : 2) * d->pageMargin * gap_UI; |
576 | if (d->phoneToolbar) { | 577 | if (d->phoneToolbar) { |
577 | sm += size_Root(constAs_Widget(d)->root).y - | 578 | sm += size_Root(w->root).y - |
578 | top_Rect(boundsWithoutVisualOffset_Widget(d->phoneToolbar)); | 579 | top_Rect(boundsWithoutVisualOffset_Widget(d->phoneToolbar)); |
579 | } | 580 | } |
580 | return sm; | 581 | return sm; |
diff --git a/src/ui/widget.c b/src/ui/widget.c index 3ff2e713..43bbe56e 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -314,50 +314,48 @@ static void printf_Widget_(const iWidget *d, const char *format, ...) { | |||
314 | delete_String(msg); | 314 | delete_String(msg); |
315 | } | 315 | } |
316 | 316 | ||
317 | static void setWidth_Widget_(iWidget *d, int width) { | 317 | static iBool setWidth_Widget_(iWidget *d, int width) { |
318 | iAssert(width >= 0); | 318 | iAssert(width >= 0); |
319 | TRACE(d, "attempt to set width to %d (current: %d, min width: %d)", width, d->rect.size.x, d->minSize.x); | 319 | TRACE(d, "attempt to set width to %d (current: %d, min width: %d)", width, d->rect.size.x, d->minSize.x); |
320 | width = iMax(width, d->minSize.x); | 320 | width = iMax(width, d->minSize.x); |
321 | if (~d->flags & fixedWidth_WidgetFlag) { //} || d->flags & collapse_WidgetFlag) { | 321 | if (~d->flags & fixedWidth_WidgetFlag) { |
322 | if (d->rect.size.x != width) { | 322 | if (d->rect.size.x != width) { |
323 | d->rect.size.x = width; | 323 | d->rect.size.x = width; |
324 | TRACE(d, "width has changed to %d", width); | 324 | TRACE(d, "width has changed to %d", width); |
325 | if (class_Widget(d)->sizeChanged) { | 325 | if (class_Widget(d)->sizeChanged) { |
326 | const int oldHeight = d->rect.size.y; | 326 | const int oldHeight = d->rect.size.y; |
327 | class_Widget(d)->sizeChanged(d); | 327 | class_Widget(d)->sizeChanged(d); |
328 | if (d->rect.size.y != oldHeight) { | ||
329 | TRACE(d, "sizeChanged() cuased height change to %d; redoing parent", d->rect.size.y); | ||
330 | /* Widget updated its height. */ | ||
331 | arrange_Widget_(d->parent); | ||
332 | TRACE(d, "parent layout redone"); | ||
333 | } | ||
334 | } | 328 | } |
329 | return iTrue; | ||
335 | } | 330 | } |
336 | } | 331 | } |
337 | else { | 332 | else { |
338 | TRACE(d, "changing width not allowed; flags: %x", d->flags); | 333 | TRACE(d, "changing width not allowed; flags: %x", d->flags); |
339 | } | 334 | } |
335 | return iFalse; | ||
340 | } | 336 | } |
341 | 337 | ||
342 | static void setHeight_Widget_(iWidget *d, int height) { | 338 | static iBool setHeight_Widget_(iWidget *d, int height) { |
343 | iAssert(height >= 0); | 339 | iAssert(height >= 0); |
344 | if (d->sizeRef) { | 340 | if (d->sizeRef) { |
345 | return; /* height defined by another widget */ | 341 | return; /* height defined by another widget */ |
346 | } | 342 | } |
347 | TRACE(d, "attempt to set height to %d (current: %d, min height: %d)", height, d->rect.size.y, d->minSize.y); | 343 | TRACE(d, "attempt to set height to %d (current: %d, min height: %d)", height, d->rect.size.y, d->minSize.y); |
348 | height = iMax(height, d->minSize.y); | 344 | height = iMax(height, d->minSize.y); |
349 | if (~d->flags & fixedHeight_WidgetFlag) { //} || d->flags & collapse_WidgetFlag) { | 345 | if (~d->flags & fixedHeight_WidgetFlag) { |
350 | if (d->rect.size.y != height) { | 346 | if (d->rect.size.y != height) { |
351 | d->rect.size.y = height; | 347 | d->rect.size.y = height; |
352 | TRACE(d, "height has changed to %d", height); | 348 | TRACE(d, "height has changed to %d", height); |
353 | if (class_Widget(d)->sizeChanged) { | 349 | if (class_Widget(d)->sizeChanged) { |
354 | class_Widget(d)->sizeChanged(d); | 350 | class_Widget(d)->sizeChanged(d); |
355 | } | 351 | } |
352 | return iTrue; | ||
356 | } | 353 | } |
357 | } | 354 | } |
358 | else { | 355 | else { |
359 | TRACE(d, "changing height not allowed; flags: %x", d->flags); | 356 | TRACE(d, "changing height not allowed; flags: %x", d->flags); |
360 | } | 357 | } |
358 | return iFalse; | ||
361 | } | 359 | } |
362 | 360 | ||
363 | iLocalDef iRect innerRect_Widget_(const iWidget *d) { | 361 | iLocalDef iRect innerRect_Widget_(const iWidget *d) { |
@@ -578,6 +576,12 @@ static void arrange_Widget_(iWidget *d) { | |||
578 | TRACE(d, "...done changing child sizes (EVEN mode)"); | 576 | TRACE(d, "...done changing child sizes (EVEN mode)"); |
579 | } | 577 | } |
580 | } | 578 | } |
579 | /* Children arrange themselves. */ { | ||
580 | iForEach(ObjectList, i, d->children) { | ||
581 | iWidget *child = as_Widget(i.object); | ||
582 | arrange_Widget_(child); | ||
583 | } | ||
584 | } | ||
581 | /* Resize the expanding children to fill the remaining available space. */ | 585 | /* Resize the expanding children to fill the remaining available space. */ |
582 | if (expCount > 0 && (d->flags & (arrangeHorizontal_WidgetFlag | arrangeVertical_WidgetFlag))) { | 586 | if (expCount > 0 && (d->flags & (arrangeHorizontal_WidgetFlag | arrangeVertical_WidgetFlag))) { |
583 | TRACE(d, "%d expanding children, resizing them %s...", expCount, | 587 | TRACE(d, "%d expanding children, resizing them %s...", expCount, |
@@ -600,16 +604,20 @@ static void arrange_Widget_(iWidget *d) { | |||
600 | TRACE(d, "child %p size is not arranged", child); | 604 | TRACE(d, "child %p size is not arranged", child); |
601 | continue; | 605 | continue; |
602 | } | 606 | } |
607 | iBool sizeChanged = iFalse; | ||
603 | if (child->flags & expand_WidgetFlag) { | 608 | if (child->flags & expand_WidgetFlag) { |
604 | if (d->flags & arrangeHorizontal_WidgetFlag) { | 609 | if (d->flags & arrangeHorizontal_WidgetFlag) { |
605 | setWidth_Widget_(child, avail.x); | 610 | sizeChanged |= setWidth_Widget_(child, avail.x); |
606 | setHeight_Widget_(child, height_Rect(innerRect)); | 611 | sizeChanged |= setHeight_Widget_(child, height_Rect(innerRect)); |
607 | } | 612 | } |
608 | else if (d->flags & arrangeVertical_WidgetFlag) { | 613 | else if (d->flags & arrangeVertical_WidgetFlag) { |
609 | setWidth_Widget_(child, width_Rect(innerRect)); | 614 | sizeChanged |= setWidth_Widget_(child, width_Rect(innerRect)); |
610 | setHeight_Widget_(child, avail.y); | 615 | sizeChanged |= setHeight_Widget_(child, avail.y); |
611 | } | 616 | } |
612 | } | 617 | } |
618 | if (sizeChanged) { | ||
619 | arrange_Widget_(child); /* its children may need rearranging */ | ||
620 | } | ||
613 | } | 621 | } |
614 | } | 622 | } |
615 | if (d->flags & resizeChildrenToWidestChild_WidgetFlag) { | 623 | if (d->flags & resizeChildrenToWidestChild_WidgetFlag) { |
@@ -618,7 +626,9 @@ static void arrange_Widget_(iWidget *d) { | |||
618 | iForEach(ObjectList, i, d->children) { | 626 | iForEach(ObjectList, i, d->children) { |
619 | iWidget *child = as_Widget(i.object); | 627 | iWidget *child = as_Widget(i.object); |
620 | if (isArrangedSize_Widget_(child)) { | 628 | if (isArrangedSize_Widget_(child)) { |
621 | setWidth_Widget_(child, widest); | 629 | if (setWidth_Widget_(child, widest)) { |
630 | arrange_Widget_(child); /* its children may need rearranging */ | ||
631 | } | ||
622 | } | 632 | } |
623 | else { | 633 | else { |
624 | TRACE(d, "child %p cannot be resized (parentCannotResize: %d)", child, | 634 | TRACE(d, "child %p cannot be resized (parentCannotResize: %d)", child, |
@@ -633,7 +643,6 @@ static void arrange_Widget_(iWidget *d) { | |||
633 | d->flags & arrangeVertical_WidgetFlag ? " vert" : ""); | 643 | d->flags & arrangeVertical_WidgetFlag ? " vert" : ""); |
634 | iForEach(ObjectList, i, d->children) { | 644 | iForEach(ObjectList, i, d->children) { |
635 | iWidget *child = as_Widget(i.object); | 645 | iWidget *child = as_Widget(i.object); |
636 | arrange_Widget_(child); | ||
637 | if (isCollapsed_Widget_(child) || !isArrangedPos_Widget_(child)) { | 646 | if (isCollapsed_Widget_(child) || !isArrangedPos_Widget_(child)) { |
638 | TRACE(d, "child %p arranging prohibited", child); | 647 | TRACE(d, "child %p arranging prohibited", child); |
639 | continue; | 648 | continue; |
@@ -743,6 +752,11 @@ static void resetArrangement_Widget_(iWidget *d) { | |||
743 | 752 | ||
744 | void arrange_Widget(iWidget *d) { | 753 | void arrange_Widget(iWidget *d) { |
745 | if (d) { | 754 | if (d) { |
755 | #if !defined (NDEBUG) | ||
756 | if (tracing_) { | ||
757 | puts("\n==== NEW WIDGET ARRANGEMENT ====\n"); | ||
758 | } | ||
759 | #endif | ||
746 | resetArrangement_Widget_(d); /* back to initial default sizes */ | 760 | resetArrangement_Widget_(d); /* back to initial default sizes */ |
747 | arrange_Widget_(d); | 761 | arrange_Widget_(d); |
748 | } | 762 | } |