-
-
Notifications
You must be signed in to change notification settings - Fork 7k
Fix ButtonSet widget with icons resizing when UIScale is changed #3942
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This PR will have two commits:
|
Ready for review. |
I think some areas of the editor need resizing when UI scaling occurs, like the layer name cells on the timeline and perhaps the size of the color bar. |
Issues discovered in some windows like Export Sprite Sheet. It's not ready for review. |
Ready for review.
Possible improvement related to '4': save/load the center of the window frame instead the top-left pos. Note: as per how '4' was implemented, stored preferences related to window sizes will result in unsuitable window sizes until the first dialog resize. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good so far! I've made some comments to review.
Just as a little tip if you enable the dev mode (ENABLE_DEVMODE=ON
), you can use Ctrl+F1 to quickly switch/rotate between UI/Screen scaling values: https://github.com/aseprite/aseprite/blob/main/src/README.md#debugging-tricks
src/app/modules/gui.cpp
Outdated
Rect frame = get_config_rect(section, "WindowFrame", gfx::Rect()); | ||
if (!frame.isEmpty()) { | ||
// Re-scale the window size. | ||
frame.w *= guiscale(); | ||
frame.h *= guiscale(); | ||
limit_with_workarea(parentDisplay, frame); | ||
window->loadNativeFrame(frame); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can have two fields, one new "WindowFrameUnscaled"
which is not scaled with guiscale() / is normalized, and use the previous "WindowFrame"
when the new one is not available. Something like this:
Rect frame = get_config_rect(section, "WindowFrame", gfx::Rect()); | |
if (!frame.isEmpty()) { | |
// Re-scale the window size. | |
frame.w *= guiscale(); | |
frame.h *= guiscale(); | |
limit_with_workarea(parentDisplay, frame); | |
window->loadNativeFrame(frame); | |
} | |
// First try to read the new "WindowFrameUnscaled" field (which is unscaled) | |
Rect frame = get_config_rect(section, "WindowFrameUnscaled", gfx::Rect()); | |
if (!frame.isEmpty()) { | |
// Scale the window size with the UI scaling factor. | |
frame.w *= guiscale(); | |
frame.h *= guiscale(); | |
} | |
// If it's empty read the backward compatible "WindowFrame" field (which is | |
// already scaled with UI scaling) | |
else { | |
frame = get_config_rect(section, "WindowFrame", gfx::Rect()); | |
} | |
if (!frame.isEmpty()) { | |
limit_with_workarea(parentDisplay, frame); | |
window->loadNativeFrame(frame); | |
} |
src/app/modules/gui.cpp
Outdated
// De-scale the window size to save it normalized. | ||
rc.w /= guiscale(); | ||
rc.h /= guiscale(); | ||
set_config_rect(section, "WindowFrame", rc); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And here we can save both fields (just to keep backward compatibility if the user open an older version of Aseprite):
// De-scale the window size to save it normalized. | |
rc.w /= guiscale(); | |
rc.h /= guiscale(); | |
set_config_rect(section, "WindowFrame", rc); | |
set_config_rect(section, "WindowFrame", rc); | |
// De-scale the window size to save it normalized. | |
rc.w /= guiscale(); | |
rc.h /= guiscale(); | |
set_config_rect(section, "WindowFrameUnscaled", rc); |
src/app/modules/gui.cpp
Outdated
set_config_rect(section, "WindowFrame", rc); | ||
rc.offset(-mainNativeWindow->frame().origin()); | ||
rc /= mainNativeWindow->scale(); | ||
} | ||
else { | ||
del_config_value(section, "WindowFrame"); | ||
rc = window->bounds(); | ||
// De-scale the window size to save it normalized. | ||
rc.w /= guiscale(); | ||
rc.h /= guiscale(); | ||
} | ||
|
||
set_config_rect(section, "WindowPos", rc); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what happens with this "WindowPos"
field, it looks like this field now has changed too. Probably we need a "WindowPosUnscaled"
too (used when multiple displays is disabled mainly).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably we need a "WindowPosUnscaled" too (used when multiple displays is disabled mainly).
Yes, I agree.
For the moment, WindowPos maintains the same position on the screen. This may be fine, but I feel like it's not correct in my opinion.
Example:
- Guiscale 200%, go to File > Export > Export Sprite Sheet, suppose the dialog is centered on the screen. Close the dialog.
- Change the guiscale to 100%, open again the Export Sprite Sheet dialog.
- Result: The window will appear to be shifted to the top/left. When it would have been desirable to find it centered on the screen.
For this reason, I am going to propose to save the unscaled central position of the dialog, to be able to use it and re-scale it as desired guiscale (of course limiting the top/left corner of the window inside the editor).
src/ui/theme.cpp
Outdated
int maxInt = std::numeric_limits<int>::max(); | ||
if (sz.w == maxInt || style->maxSize().w < maxInt) | ||
sz.w = style->maxSize().w; | ||
if (sz.h == maxInt || style->maxSize().h < maxInt) | ||
sz.h = style->maxSize().h; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably something similar to the min case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also tried it: regression when guiscale is increased (for example 100% --> 300%). Some cases:
- Playback control buttons on the timeline.
- ContextBar > selection mode buttons with the Marquee tool active.
- ContextBar > Radial/Linear buttons with thee Gradient tool active.
src/ui/widget.cpp
Outdated
if (m_theme) | ||
m_font.reset(m_theme->getWidgetFont(this)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This breaks the purpose of the m_font variable which is to cache the value of the widget font (to avoid asking the theme for the font again).
I would revert this change and give a try to this other (probable) fix in Widget::onBroadcastMouseMessage
:
@@ -1691,6 +1690,9 @@ void Widget::onBroadcastMouseMessage(const gfx::Point& screenPos,
void Widget::onInitTheme(InitThemeEvent& ev)
{
+ // Reset cached font
+ m_font = nullptr;
+
// Create a copy of the children list and iterate it, just in case a
// initTheme() modifies this list (e.g. this can happen in some
// strange cases with viewports, where scrollbars are added/removed
As a side note @Gasparoken which I forgot to mention: there is no need to close a PR and open another one, you can just fix your branch/force push changes in your |
Thank you for the review, I'll take a look to this. About commit '3' (Layer name cell on the Timeline), I'll change the approach.
I used to do it this way, but in some cases, I want to preserve the history for some reason, for example: keep some comment from my reviewer with the well-referenced piece of code. |
Generally the history is best preserved if the PR is not replaced by a new one e.g. you can expand the resolved comments/review, see the history of the PR, if we replace it with a new PR the old one is a little lost in the history of the commit/new PR. Another thing I'd like to fix in my workflow, is to rebase PRs properly with GitHub (this use case to rebase PRs is not well handled yet in GitHub with different emails, I'll try to fix this ASAP). |
The '5' commit is as a possible alternative way to manage the position/size of windows in a more intuitive way. What do you think @dacap? Additional issue to solve: 1.3rc4: the size of the timeline dropdown settings menu is not managed correctly when guiscale is changed. |
351d7b3
to
b7d597a
Compare
Ready for review. Commit summary:
|
I would prefer to merge this PR without 6010a99 and b7d597a. About 6010a99 I think I prefer to avoid modifying the native frame and just load/save the native frame as it is in About b7d597a, I'm not sure what specific situation this patch fixes, but an important comment: redefining a non-virtual method ( |
This fix avoids involuntary window resizing and re-location. It's annoying if we change the UI scale frecuently
Example: This last issue can fix automatically re-starting Aseprite On the other hand, the problem fixed in 6010a99 it's more damaging to the artist's workflow as a restart won't resolve saved custom window sizes (all windows with custom bounds should be resized once UI scaling is changed). Alternatives:
@dacap What do you think about this two alternatives? (I prefer "2") |
Probably I'd prefer to merge the PR with the initial commits which already is a lot better than the current situation, and then discuss the other changes with more time and detail (I'm trying to prepare the next release probably for tomorrow). |
OK, I'll push-force a PR with the first three commits only. I'll create new issues for #3942 (comment) |
Tested and ready to merge. |
No description provided.