Skip to content

Fix dialog w/scrollbar wrong size in a particular case (fix #5396)#5481

Closed
Gasparoken wants to merge 1 commit into
aseprite:mainfrom
Gasparoken:fix-dialog-size
Closed

Fix dialog w/scrollbar wrong size in a particular case (fix #5396)#5481
Gasparoken wants to merge 1 commit into
aseprite:mainfrom
Gasparoken:fix-dialog-size

Conversation

@Gasparoken

@Gasparoken Gasparoken commented Oct 23, 2025

Copy link
Copy Markdown
Member

fix #5396

@Gasparoken Gasparoken self-assigned this Oct 23, 2025
@Gasparoken Gasparoken requested a review from dacap as a code owner October 23, 2025 12:28

@aseprite-bot aseprite-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

Comment thread src/app/script/dialog_class.cpp Outdated
View* view = static_cast<View*>(dlg->grid.parent()->parent());
if (newBounds.size().w > workarea.w) {
newBounds.w = std::min(newBounds.size().w, workarea.w);
if (newBounds.size().h < workarea.h && view->horizontalBar())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: implicit conversion 'ScrollBar *' -> 'bool' [readability-implicit-bool-conversion]

Suggested change
if (newBounds.size().h < workarea.h && view->horizontalBar())
if (newBounds.size().h < workarea.h && (view->horizontalBar() != nullptr))

Comment thread src/app/script/dialog_class.cpp Outdated
}
if (newBounds.size().h > workarea.h) {
newBounds.h = std::min(newBounds.size().h, workarea.h);
if (newBounds.size().w < workarea.w && view->verticalBar())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: implicit conversion 'ScrollBar *' -> 'bool' [readability-implicit-bool-conversion]

Suggested change
if (newBounds.size().w < workarea.w && view->verticalBar())
if (newBounds.size().w < workarea.w && (view->verticalBar() != nullptr))

Comment thread src/ui/viewport.cpp Outdated
void Viewport::onSizeHint(SizeHintEvent& ev)
{
ev.setSizeHint(gfx::Size(1 + border().width(), 1 + border().height()));
for (auto child : children()) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 'auto child' can be declared as 'auto *child' [readability-qualified-auto]

Suggested change
for (auto child : children()) {
for (auto *child : children()) {

@martincapello martincapello left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested this and it seems to work. I'm just not sure how the expected UX should be, but this fixes the issue it claims to fix.

@dacap dacap left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments to work on, I'll be testing a little more tomorrow with multiple monitors.

Comment thread src/ui/viewport.cpp Outdated
Comment on lines +61 to +66
ev.setSizeHint(gfx::Size(1 + border().width(), 1 + border().height()));
gfx::Size sz = ev.sizeHint();
for (auto child : children()) {
sz += child->sizeHint();
ev.setSizeHint(sz);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not quite sure if we should change the viewport size here (as it affects all viewports in the app), and have make this change explicit so the user must change the minimum size of the parent View to specify a minimum size (check that several elements in .xml widgets change the minwidth/height fields).

I'd prefer if we revert this change and in someway change the minimum size of the view explicitly (the view could be stored in a field of the Dialog class).

Just in case we need this change, we could do something like:

  gfx::Size sz(1, 1);
  for (auto* child : children())
    sz |= child->sizeHint();
  ev.setSizeHint(sz);

But I'm not sure to apply this change to main directly (as it might break something else)

Comment on lines +1703 to +1704
const bool allowVResize = bool(dlg->autofit & ui::TOP) ^ bool(dlg->autofit & ui::BOTTOM);
const bool allowHResize = bool(dlg->autofit & ui::LEFT) ^ bool(dlg->autofit & ui::RIGHT);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this right? This logic looks confusing, like it wants to say "allow vertical resize if top or bottom, but not both are enabled", but probably you want to specify it (a comment might help in these cases).

Should be this change to?

Suggested change
const bool allowVResize = bool(dlg->autofit & ui::TOP) ^ bool(dlg->autofit & ui::BOTTOM);
const bool allowHResize = bool(dlg->autofit & ui::LEFT) ^ bool(dlg->autofit & ui::RIGHT);
const bool allowVResize = bool(dlg->autofit & ui::TOP) | bool(dlg->autofit & ui::BOTTOM);
const bool allowHResize = bool(dlg->autofit & ui::LEFT) | bool(dlg->autofit & ui::RIGHT);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm confused in interpreting the API documentation that says: "...(eg. when autofitting with Align.LEFT | Align.TOP, the dialog bounds will shrink to the minimum size anchored at the top left of the dialog)". Therefore, I assume that if we anchor, for example, TOP and BOTTOM, the size would remain fixed given the anchoring concept. I'll need your confirmation this the behavior I'm describing is correct.
On the other hand, but following the logic of anchoring, how should a dialogue behave without Align?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's as the API says, but never thought about the possibility of having TOP|BOTTOM or LEFT|RIGHT as anchors. The anchor should be one corner/edge (0, TOP|LEFT, TOP, TOP|RIGHT, LEFT, RIGHT, BOTTOM|LEFT, BOTTOM, BOTTOM|RIGHT), but probably we can support the case you say too.

Without autofit the default is TOP|LEFT (just changing the size without changing the origin).

Comment thread src/app/script/dialog_class.cpp Outdated
allowHResize ? dlg->window.sizeHint().w : oldBounds.w,
allowVResize ? dlg->window.sizeHint().h : oldBounds.h);

if (auto* view = dynamic_cast<View*>(View::getView(&dlg->grid))) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably it'd be better to have the view pointer directly in the Dialog class and doing something like:

Suggested change
if (auto* view = dynamic_cast<View*>(View::getView(&dlg->grid))) {
if (View* view = dlg->view) {

Comment thread src/app/script/dialog_class.cpp Outdated
Comment on lines 1712 to 1745
if (newBounds.size().w > workarea.w && allowHResize) {
newBounds.w = std::min(newBounds.size().w, workarea.w);
if (newBounds.size().h < workarea.h && view->horizontalBar() && allowVResize)
newBounds.h += view->horizontalBar()->getBarWidth();
}
if (newBounds.size().h > workarea.h && allowVResize) {
newBounds.h = std::min(newBounds.size().h, workarea.h);
if (newBounds.size().w < workarea.w && view->verticalBar() && allowHResize)
newBounds.w += view->verticalBar()->getBarWidth();
}
if ((dlg->autofit & ui::BOTTOM) && allowVResize)
newBounds.y = oldBounds.y2() - newBounds.h;
if ((dlg->autofit & ui::RIGHT) && allowHResize)
newBounds.x = oldBounds.x2() - newBounds.w;

// Trim of dialog areas outside the workarea
if (newBounds.x2() > workarea.x2())
newBounds.w -= (newBounds.x2() - workarea.x2());
if (newBounds.y2() > workarea.y2())
newBounds.h -= (newBounds.y2() - workarea.y2());
if (newBounds.x < workarea.x) {
newBounds.w = oldBounds.x2() - workarea.x;
newBounds.x = workarea.x;
}
if (newBounds.y < workarea.y) {
newBounds.h = oldBounds.y2() - workarea.y;
newBounds.y = workarea.y;
}

// Restore newBounds refered to the mainWindows
if (get_multiple_displays())
newBounds.offset(-mainWindowBounds.origin());
}
dlg->setWindowBounds(newBounds);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll test this tomorrow, I've detected that with multiples monitors it doesn't work as expected. Wouldn't be possible to use fit_bounds() function in this case?

@dacap dacap assigned Gasparoken and unassigned dacap Oct 27, 2025
@Gasparoken Gasparoken force-pushed the fix-dialog-size branch 2 times, most recently from 23769c7 to ca090e2 Compare October 31, 2025 14:38
@aseprite-bot

Copy link
Copy Markdown
Collaborator

clang-tidy review says "All clean, LGTM! 👍"

1 similar comment
@aseprite-bot

Copy link
Copy Markdown
Collaborator

clang-tidy review says "All clean, LGTM! 👍"

@Gasparoken Gasparoken assigned dacap and Gasparoken and unassigned Gasparoken and dacap Nov 3, 2025
…5396)

Prior to this fix, changing the visibility of a widget
in an autoscrolling dialog would collapse the size of the dialog.
@aseprite-bot

Copy link
Copy Markdown
Collaborator

clang-tidy review says "All clean, LGTM! 👍"

@Gasparoken Gasparoken assigned dacap and unassigned Gasparoken Nov 5, 2025
@dacap

dacap commented Nov 10, 2025

Copy link
Copy Markdown
Member

I have to test this a little more this, but I'm not sure if we should modify the dialog size when it has a view/autoscrollbars, as the user might have changed the dialog size to something preferred, and modifying that size is just making things worse (changing the user preference / viewport size).

dacap pushed a commit that referenced this pull request Nov 10, 2025
…5481)

Prior to this fix, changing the visibility of a widget
in an autoscrolling dialog would collapse the size of the dialog.
@dacap

dacap commented Nov 10, 2025

Copy link
Copy Markdown
Member

I've cherry-picked the commit in 71dd383 (as laf has conflicts), and I'll continue from there.

@dacap dacap closed this Nov 10, 2025
@dacap

dacap commented Nov 11, 2025

Copy link
Copy Markdown
Member

There are a couple of issues I'm trying to fix of this patch (now merged in main): 1) getCurrentWorkarea() doesn't return a rectangle on all paths, 2) a crash where dlg->view used but it's nullptr.

dacap added a commit that referenced this pull request Nov 11, 2025
Fixed some regressions introduced in #5481 / 71dd383

* Replaced Dialog::getCurrentWorkarea() with ui::fit_bounds()
  (getCurrentWorkarea() wasn't returning a valid rectangle for all
  cases)
* Fixed accessing a nullptr Dialog::view pointer
* Use View::makeVisibleAllScrollableArea() instead of setMinSize()
  directly
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Modifying widget visibility on a dialog with autoscrolls shrink the dialog size

4 participants