Skip to content
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

Make the drawing logic clearer in Button #64351

Merged
merged 1 commit into from
Jan 18, 2024

Conversation

Rindbee
Copy link
Contributor

@Rindbee Rindbee commented Aug 13, 2022

Make the drawing logic clearer.

The drawing logic follows the calculation logic in Button::get_minimum_size. According to the order of stylebox, icon, and text, and follow properties such as alignment mode, to fill the display space of the button.

Add a Button::_set_h_separation_is_valid_when_no_text for Button derived classes (like OptionButton) that expects a h_separation between icon and theme icon even if the text is empty.

Fixes #59202.
Supersedes #59340.
Depends on #64218 (Negative values of h_separation will be treated as 0).

Fixes #80386.

Try to follow the rules in Alpha13, but except when alignment is CENTER. This patch will try to draw inside the yellow rectangle.

captrue

The following is a set of comparison pictures.

Alpha13 This patch + #64218
alpha13 1
1 2
3 4
5 6

@Ayush-singla27
Copy link
Contributor

i would like to work on this issue but this PR is still open. Is there any particular reason why this PR is waiting for a review?

@KoBeWi
Copy link
Member

KoBeWi commented Nov 20, 2022

I don't really like how this adds a special case for inheriting class, but I guess you could fix #68930 as well now.

@Rindbee
Copy link
Contributor Author

Rindbee commented Nov 21, 2022

The drawing of this PR is based on get_minimum_size(), when text is empty, CheckBox/CheckButton will ignore h_separation between the inner icon and icon, but OptionButton class will not ignore it. So OptionButton is a bit special.

@KoBeWi
Copy link
Member

KoBeWi commented Nov 21, 2022

I understand why it needs to be done; it just breaks OOP this way and could be handled better. But it would make the code more complex, so not worth it for a single case.

@Rindbee
Copy link
Contributor Author

Rindbee commented Nov 21, 2022

If the behavior of classes with internal icons (CheckBox/CheckButton/OptionButton) is consistent, no matter whether h_separation is ignored or not, no special handling is required.

@YuriSizov
Copy link
Contributor

If you need a hack like that, then it's better to add an unexposed flag and set it only for the OptionButton. OOP would be preserved, and we'd be safe without weird circular dependencies.

@Rindbee
Copy link
Contributor Author

Rindbee commented Feb 7, 2023

If you need a hack like that, then it's better to add an unexposed flag and set it only for the OptionButton. OOP would be preserved, and we'd be safe without weird circular dependencies.

OK, use h_separation_is_valid_when_no_text to distinguish between OptionButton (true) and other Button derived classes (false).

@akien-mga akien-mga modified the milestones: 4.0, 4.1 Feb 17, 2023
@YuriSizov
Copy link
Contributor

This needs a rebase (and the commit message could be a bit more detailed, the title of the PR itself is good).

The flag should not be a part of the constructor, it can just have a setter method that we call from the OptionButton constructor. That would be cleaner.

Also does it address #68930 or not? It probably should be addressed in this PR, as suggested.

@Rindbee
Copy link
Contributor Author

Rindbee commented Apr 12, 2023

Also does it address #68930 or not? It probably should be addressed in this PR, as suggested.

#68930 is mainly caused by enabling fit_to_longest_item to cache size data, and switching expand_icon does not update the cache data. It's not a drawing problem, but a refreshing problem of cached data. Fixed in #75958.

Maybe fit_to_longest_item can be made a member variable of Button, but only exposed in OptionButton, which can solve the problem of refreshing the cache when switching expand_icon. 🤔

@KoBeWi
Copy link
Member

KoBeWi commented May 2, 2023

Why is there so much empty space between arrow icon and text?
image

Copy link
Member

@KoBeWi KoBeWi left a comment

Choose a reason for hiding this comment

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

Aside from the weird spacing, seems correct.

@YuriSizov
Copy link
Contributor

I still need to review this because before I did extensive testing and found issues, and since then there was a significant change in the implementation so I need to do it all over again.

Copy link
Contributor

@YuriSizov YuriSizov left a comment

Choose a reason for hiding this comment

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

I didn't check all of the implementation, but one bit did stand out to me. And there are regressions in the behavior, which may or may not be related and need to be looked into (see below).

Overall, there are clear improvements in the behavior. Here's a comparison of before and after, which demonstrates both the linked issue being fixed and some inconsistencies being addressed:

Before

godot windows editor dev x86_64_2024-01-15_16-05-08

After

godot windows editor dev x86_64_2024-01-15_16-06-55

There are still some issues which are not addressed by this PR. See the top row of the right side of either image where the icon alignment varies. When the icon is center-aligned the text clipping stops to work. You can see that no matter if you set trimming or ellipses, it just stays in the "trim nothing" mode.

godot.windows.editor.dev.x86_64_2024-01-15_15-38-55.mp4

One new problem the aforementioned regression, is visible with the top-right example. For some reason, if you set the button to "trim nothing", the icon shrinks beyond the size of any other mode, and vertical positioning changes as a result. This was not happening before this patch.

godot.windows.editor.dev.x86_64_2024-01-15_16-10-36.mp4

You can also see that text alignment works funny, this may be related to the bit that I've highlighted in the code review. Left and center alignment are exactly the same, but right alignment is shifted to the left, so it's more to the left than either left or center alignment.

scene/gui/button.h Show resolved Hide resolved
scene/gui/button.cpp Outdated Show resolved Hide resolved
scene/gui/button.cpp Outdated Show resolved Hide resolved
scene/gui/button.cpp Outdated Show resolved Hide resolved
@Rindbee
Copy link
Contributor Author

Rindbee commented Jan 16, 2024

There are still some issues which are not addressed by this PR. See the top row of the right side of either image where the icon alignment varies. When the icon is center-aligned the text clipping stops to work. You can see that no matter if you set trimming or ellipses, it just stays in the "trim nothing" mode.

I'm not sure if the button's text is "Some very long te" or "Some very long text", if it's the former, the width is enough for the text to display, so no change is expected.

One new problem the aforementioned regression, is visible with the top-right example. For some reason, if you set the button to "trim nothing", the icon shrinks beyond the size of any other mode, and vertical positioning changes as a result. This was not happening before this patch.

I can't determine the reason. Maybe the width is larger than the minimum width? It is also possible that the cache has not been refreshed.

0.mp4

You can also see that text alignment works funny, this may be related to the bit that I've highlighted in the code review. Left and center alignment are exactly the same, but right alignment is shifted to the left, so it's more to the left than either left or center alignment.

Forgot to take into account the case of h_separation due to width (icon or text_buf) being 0.

text_buf->set_width() only affects the result of text_buf->get_size() when overrun_behavior != TextServer::OVERRUN_NO_TRIMMING.

0

The text_buf is drawn at the red point, but the display is offset, which seems to be a problem in TextParagraph::draw().

@Rindbee Rindbee force-pushed the fix-button-draw branch 3 times, most recently from 2538295 to 26ca4c6 Compare January 17, 2024 02:45
@YuriSizov
Copy link
Contributor

I'm not sure if the button's text is "Some very long te" or "Some very long text", if it's the former, the width is enough for the text to display, so no change is expected.

It's full text. The issue is that when the icon is vertically aligned to the top, the amount of space available for the text doesn't change. However, with icon's left and right alignment we still subtract icon's size out of the space allocated for the text, but we don't do that with the center alignment. There may be some logical reason for this, but it feels super unintuitive.

That aside, there is still more text in there but it doesn't get trimmed or ellipse'd correctly. But in any case, as I mentioned, that's a pre-existing problem. We don't have to fix it here now. We can move forward with just a subset of issues fixed, as there are still more problems with button icons not tackled by this PR.

@Rindbee
Copy link
Contributor Author

Rindbee commented Jan 17, 2024

I noticed that in "Trim Nothing" mode the text always shows up as "Some very long te", if it doesn't show up completely there might be a cache issue in OptionButton.

Like toggling expand_icon, toggling text_overrun_behavior, clip_text and vertical_icon_alignment may affect the minimum size.

0.mp4

@Rindbee Rindbee force-pushed the fix-button-draw branch 3 times, most recently from e6dba72 to 897cc8b Compare January 18, 2024 05:14

int text_width = MAX(1, is_clipped ? MIN(text_clip, text_buf->get_size().x) : text_buf->get_size().x);
float text_buf_width = MAX(1.0f, drawable_size_remained.width); // The space's width filled by the text_buf.
text_buf->set_width(text_buf_width);
Copy link
Contributor Author

@Rindbee Rindbee Jan 18, 2024

Choose a reason for hiding this comment

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

Due to the conditions added in #80402, the calculated drawable_size_remained.width is less affected by text_buf->get_size(). That is to say, the calculated results are more reliable.

If I understand text_buf->set_width() correctly, doing this will align it horizontally correctly in the remaining space.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Visible characters will be offset in the text‘s reserve space by TextParagraph.

So we can later calculate the offset to this space from the left, as the required values are all determined.

scene/gui/button.cpp Outdated Show resolved Hide resolved
scene/gui/button.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@YuriSizov YuriSizov left a comment

Choose a reason for hiding this comment

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

So one issue was actually my mistake in the test scene, I did actually have the text cut off at te for some reason. That still makes me wonder if the alignment works as expected by the user.

What I mean here is that a top-left-aligned icon takes horizontal space from the text, same with top-right, or bottom-left, or bottom-right. Whereas top-center and bottom-center don't do that. I think that when the icon is to the top or to the bottom, it shouldn't take horizontal space from the text. I don't find this useful.

But that's a new discussion. Let's go ahead with this rework for now, so we can finally put it to rest, and do any new fixes in follow-ups.

The drawing logic follows the calculation logic in `Button::get_minimum_size`.

According to the order of `stylebox`, `icon`, and `text`, and follow properties
such as alignment mode, to fill the display space of the button.

Add a `Button::_set_h_separation_is_valid_when_no_text` for Button derived
classes (like `OptionButton`) that expects a `h_separation` between `icon`
and theme icon even if the `text` is empty.
@Rindbee
Copy link
Contributor Author

Rindbee commented Jan 18, 2024

What I mean here is that a top-left-aligned icon takes horizontal space from the text, same with top-right, or bottom-left, or bottom-right. Whereas top-center and bottom-center don't do that. I think that when the icon is to the top or to the bottom, it shouldn't take horizontal space from the text. I don't find this useful.

Like this:

  1. When vertical_icon_alignment is center, the behavior is consistent with the previous one.
  2. When vertical_icon_alignment is not center, they behave like two lines of text/icon.
2.mp4

@YuriSizov
Copy link
Contributor

Like this:

Yes, this looks perfect!

@Rindbee
Copy link
Contributor Author

Rindbee commented Jan 18, 2024

Does Button::get_minimum_size() need to be modified? I'm not sure how to calculate the new rules, such as h_separation and so on.

@YuriSizov
Copy link
Contributor

Does Button::get_minimum_size() need to be modified? I'm not sure how to calculate the new rules, such as h_separation and so on.

get_minimum_size_for_text_and_icon() doesn't appear to be accounting for internal margins at all. I would say this is a material for another PR. Reviewing this one over and over again gets very complicated.

If there is anything left to fix here, it's my comment above about logic for RIGHT missing. The rest let's address in a new PR after this one is merged.

@YuriSizov
Copy link
Contributor

Thanks a lot!

@YuriSizov YuriSizov merged commit bc88d77 into godotengine:master Jan 18, 2024
16 checks passed
@Rindbee Rindbee deleted the fix-button-draw branch January 18, 2024 23:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants