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

Round widget coordinates to integers #5163

Closed
emilk opened this issue Sep 25, 2024 · 0 comments · Fixed by #5517
Closed

Round widget coordinates to integers #5163

emilk opened this issue Sep 25, 2024 · 0 comments · Fixed by #5517
Assignees
Labels
egui layout Related to widget layout style visuals and theming

Comments

@emilk
Copy link
Owner

emilk commented Sep 25, 2024

Rounding errors in size calculation can lead to subtle layout bugs.

In particularly when auto-sizing an area, the size is usually the sum of the sizes of many smaller widgets and border margins. If we have rounding errors, we might next frame tell the inner widgets to have a slightly different size than last frame, which could potentially cause drastic changes, like word-breaking some text earlier (see #5161).

Integers up to 2^24 (4Mi) can be represented exactly using f32, so has no rounding errors when adding and subtracting them.
Using integers for layout coordinates therefore seems like a good idea.

This includes margin widths, etc.

To detect problems like these we first want to implement:

Once that is in, we can start fixing these issues.

There is a sliding scale of how aggressively we enforce this.

Best-effort

Make sure all default egui widgets and margins are integers, and that centering layouts (etc) round to integers.

This means the whole egui_demo_app should end up with integer coordinates.

Ui-enforced

We could also have Ui round its cursor, allocated sizes etc to integers, basically pushing integer coordinates onto the user.

Switch from f32 to i32

This is the most aggressive stance, where we switch to integer coordinates everywhere.

I suspect this will be taking it too far because:

  • It is a big undertaking
  • It is a hugely breaking change
  • We should still want to allow f32 for visual things (shapes), so it would requite having an Rectf and a Recti, Pos2f and Pos2i etc, and then have glue-code between the two everywhere

Round to integers or less?

We want to avoid rounding errors due to limited precision, but that doesn't mean we need to round to integers.

We could just as well round to 1/16ths, for instance, and still have plenty of precision in a f32.

The advantage of rounding to a fractional value is that we can get more fine-grained layouts, and smoother scrolling.

Optional: ban the use of .round()/.ceil(),.floor() in clippy.toml to make sure we always either use round_gui or round to physical pixels.

Rounding to ui points vs physical pixels

Rounding to ui points is the only thing that will prevent rounding errors.

Rounding to physical pixels still makes sense when rendering, i.e. to align text and other shapes to the physical pixel grid.
This however should not affect the layout, so it should be done either by the widgets before handing shapes to the painter, or automatically by the tessellator.

See #5164 for more

Related issues

@emilk emilk added layout Related to widget layout egui style visuals and theming labels Sep 25, 2024
@emilk emilk added this to the Next Major Release milestone Sep 25, 2024
emilk added a commit that referenced this issue Sep 25, 2024
This tool highlights coordinates that are non-integer.

* Closes #4927
* Will be used for #5163

This is disabled by default (even in debug builds),
because so many widgets cause un-alignment currently.
emilk added a commit that referenced this issue Sep 25, 2024
* Closes #5106
* Closes #5084


Protect against rounding errors in egui layout code.

Say the user asks to wrap at width 200.0.
The text layout wraps, and reports that the final width was 196.0
points.
This than trickles up the `Ui` chain and gets stored as the width for a
tooltip (say).
On the next frame, this is then set as the max width for the tooltip,
and we end up calling the text layout code again, this time with a wrap
width of 196.0.
Except, somewhere in the `Ui` chain with added margins etc, a rounding
error was introduced,
so that we actually set a wrap-width of 195.9997 instead.
Now the text that fit perfectly at 196.0 needs to wrap one word earlier,
and so the text re-wraps and reports a new width of 185.0 points.
And then the cycle continues.

So this PR limits the text wrap-width to be an integer.

Related issues:
* #4927
* #4928
* #5163

--- 

Pleas test this @rustbasic
emilk added a commit that referenced this issue Sep 25, 2024
This tool highlights coordinates that are non-integer.

* Closes #4927
* Will be used for #5163

This is disabled by default (even in debug builds), because so many
widgets cause un-alignment currently.
emilk added a commit that referenced this issue Sep 30, 2024
hacknus pushed a commit to hacknus/egui that referenced this issue Oct 30, 2024
…k#5161)

* Closes emilk#5106
* Closes emilk#5084


Protect against rounding errors in egui layout code.

Say the user asks to wrap at width 200.0.
The text layout wraps, and reports that the final width was 196.0
points.
This than trickles up the `Ui` chain and gets stored as the width for a
tooltip (say).
On the next frame, this is then set as the max width for the tooltip,
and we end up calling the text layout code again, this time with a wrap
width of 196.0.
Except, somewhere in the `Ui` chain with added margins etc, a rounding
error was introduced,
so that we actually set a wrap-width of 195.9997 instead.
Now the text that fit perfectly at 196.0 needs to wrap one word earlier,
and so the text re-wraps and reports a new width of 185.0 points.
And then the cycle continues.

So this PR limits the text wrap-width to be an integer.

Related issues:
* emilk#4927
* emilk#4928
* emilk#5163

--- 

Pleas test this @rustbasic
hacknus pushed a commit to hacknus/egui that referenced this issue Oct 30, 2024
This tool highlights coordinates that are non-integer.

* Closes emilk#4927
* Will be used for emilk#5163

This is disabled by default (even in debug builds), because so many
widgets cause un-alignment currently.
hacknus pushed a commit to hacknus/egui that referenced this issue Oct 30, 2024
@emilk emilk added this to egui Nov 7, 2024
@emilk emilk moved this to Backlog in egui Nov 7, 2024
@emilk emilk moved this from Backlog to Ready in egui Dec 11, 2024
@emilk emilk removed the status in egui Dec 11, 2024
@emilk emilk moved this to Backlog in egui Dec 11, 2024
@emilk emilk removed the status in egui Dec 11, 2024
@emilk emilk moved this to Next up in egui Dec 11, 2024
@emilk emilk removed this from the Next Major Release milestone Dec 11, 2024
@emilk emilk self-assigned this Dec 26, 2024
emilk added a commit that referenced this issue Dec 26, 2024
* Closes #5197
* Closes #5163

This should help prevent rounding errors in layout code.

@lucasmerlin you may wanna test this with `egui_flex`
@github-project-automation github-project-automation bot moved this from Next up to Done in egui Dec 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
egui layout Related to widget layout style visuals and theming
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

1 participant