Commit Graph

3926 Commits

Author SHA1 Message Date
Lucas Meurer 207e71c2ae
Exclude `\n` when splitting `Galley`s (#7316)
* Follow up to #7146 

Previously when galleys were splitted, each exept the last had an extra
empty row that had to be removed when they were concated. This changes
it to remove the `\n` from the layout jobs when splitting.
2025-07-09 14:53:19 +02:00
Emil Ernerfeldt a7f14ca176
Deprecate `Memory::popup` API in favor of new `Popup` API (#7317)
* Closes  #7037
* Closes #7297

This deprecates all popup-related function in `Memory`, replacing them
with the new `egui::Popup`.

The new API is nicer in all ways, so we should encourage people to use
it.
2025-07-09 12:55:06 +02:00
Emil Ernerfeldt fbe0aadf63
Add `Popup::from_toggle_button_response` (#7315)
Adds a convenience constructor for `Popup`
2025-07-09 10:12:47 +02:00
Lucas Meurer 508c60b2e2
Add `Galley::intrinsic_size` and use it in `AtomLayout` (#7146)
- part of https://github.com/emilk/egui/issues/5762
- also allows me to simplify sizing logic in egui_flex
2025-07-09 08:19:04 +02:00
Emil Ernerfeldt f46926aaf1
Improve texture filtering by doing it in gamma space (#7311)
* Closes https://github.com/emilk/egui/pull/5839

This makes some transparent images look a lot nicer when blended:


![image](https://github.com/user-attachments/assets/7f370aaf-886a-423c-8391-c378849b63ca)

Cursive text will also look nicer.

This unfortunately changes the contract of what
`register_native_texture` expects

---------

Co-authored-by: Adrian Blumer <blumer.adrian@gmail.com>
2025-07-07 17:46:27 +02:00
Emil Ernerfeldt dd1052108e
Add snapshot test for image blending (#7309)
This adds a test that can be used to see the improvements made by this
PR (if any):
* https://github.com/emilk/egui/pull/5839
2025-07-07 13:58:22 +02:00
Emil Ernerfeldt 09596a5e7b
egui_kittest: more ergonomic functions taking `Impl Into<String>` (#7307) 2025-07-07 13:50:53 +02:00
Emil Ernerfeldt b11b77e85f
Save a few CPU cycles with earlier early-out from `Popup::show` (#7306) 2025-07-07 12:07:13 +02:00
Emil Ernerfeldt 933d305159 Improve doc-string for `Image::alt_text` 2025-07-07 12:06:59 +02:00
Emil Ernerfeldt 93d562221b
Change `Rect::area` to return zero for negative rectangles (#7305)
Previously a single-negative rectangle (where `min.x > max.x` XOR `min.y
> max.y`) would return a negative area, while a doubly-negative
rectangle (`min.x > max.x` AND `min.y > max.y`) would return a positive
area. Now both return zero instead.
2025-07-07 12:03:03 +02:00
Emil Ernerfeldt 3622a03a46 Mark `Popup` with `#[must_use]` 2025-07-07 12:02:51 +02:00
Emil Ernerfeldt 6d80707422
Fix tooltips sometimes changing position each frame (#7304)
There was a bug in how we decide where to place a `Tooltip` (or other
`Popup`), which could lead to tooltips jumping around every frame,
especially if it changed size slightly.

The new code is simpler and bug-free.
2025-07-07 12:02:01 +02:00
Emil Ernerfeldt a811b975c2 Better deprecation of SelectableLabel 2025-07-07 09:33:08 +02:00
valadaptive 7ac137bfc1
Make the font atlas use a color image (#7298)
* [x] I have followed the instructions in the PR template

Splitting this out from the Parley work as requested. This removes
`FontImage` and makes the font atlas use a `ColorImage`. It converts
alpha to coverage at glyph-drawing time, not at delta-upload time.

This doesn't do much now, but will allow for color emoji rendering once
we start using Parley.

I've changed things around so that we pass in `text_alpha_to_coverage`
to the `Fonts` the same way we do with `pixels_per_point` and
`max_texture_side`, reusing the existing code to check if the setting
differs and recreating the font atlas if so. I'm not quite sure why this
wasn't done in the first place.

I've left `ImageData` as an enum for now, in case we want to add support
for more texture pixel formats in the future (which I personally think
would be worthwhile). If you'd like, I can just remove that enum
entirely.
2025-07-04 13:15:48 +02:00
Emil Ernerfeldt d94386de3d
Fix `debug_assert` triggered by `menu`/`intersect_ray` (#7299) 2025-07-04 09:55:03 +02:00
Lucas Meurer 47a2bb10b0
Remove `SelectableLabel` (#7277)
* part of https://github.com/emilk/egui/issues/7264
* removes SelectableLabel (Use `Button::selectable` instead)
* updates `Ui::selectable_value/label` with IntoAtoms support

Had to make some changes to `Button` since the SelecatbleLabel had no
frame unless selected.
2025-07-03 16:34:47 +02:00
Lucas Meurer 2b62c68598
Add `egui::Sides` `shrink_left` / `shrink_right` (#7295)
This allows contents (on one of the sides) in egui::Sides to shrink. 

* related https://github.com/rerun-io/rerun/issues/10494
2025-07-03 14:31:35 +02:00
Nicolas 77df407f50
`egui_kittest`: add `failed_pixel_count_threshold` (#7092)
I thought about this - so we have two options here:
1. adding it to `SnapshotOptions` 
2. adding it to every function which I do not like as this would be a
huge breaking change

## Summary

This pull request introduces a new feature to the `SnapshotOptions`
struct in the `egui_kittest` crate, allowing users to specify a
permissible percentage of pixel differences (`diff_percentage`) before a
snapshot comparison is considered a failure. This feature provides more
flexibility in handling minor visual discrepancies during snapshot
testing.

### Additions to `SnapshotOptions`:

* Added a new field `diff_percentage` of type `Option<f64>` to the
`SnapshotOptions` struct. This field allows users to define a tolerance
for pixel differences, with a default value of `None` (interpreted as 0%
tolerance).
* Updated the `Default` implementation of `SnapshotOptions` to
initialize `diff_percentage` to `None`.

### Integration into snapshot comparison logic:

* Updated the `try_image_snapshot_options` function to handle the new
`diff_percentage` field. If a `diff_percentage` is specified, the
function calculates the percentage of differing pixels and allows the
snapshot to pass if the difference is within the specified tolerance.
[[1]](diffhunk://#diff-6f481b5866b82a4fe126b7df2e6c9669040c79d1d200d76b87f376de5dec5065R204)
[[2]](diffhunk://#diff-6f481b5866b82a4fe126b7df2e6c9669040c79d1d200d76b87f376de5dec5065R294-R301)

* Closes <https://github.com/emilk/egui/issues/5683>
* [x] I have followed the instructions in the PR template

---------

Co-authored-by: lucasmerlin <hi@lucasmerlin.me>
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-07-03 14:23:15 +02:00
Emil Ernerfeldt ba577602a4
Fix crash when using infinite widgets (#7296)
* Closes https://github.com/emilk/egui/issues/7100
2025-07-03 13:40:02 +02:00
Blackberry Float db3543d034
Update area struct to allow force resizing (#7114)
This is a really small PR so I am skipping the issue (based on
contributing.md). This change adds an optional field and thus non
breaking for the API.

I ran into an issue during my development of an alerts manager widget
([see PR](https://github.com/blackberryfloat/egui_widget_ext/pull/2))
where I needed a scrollable overlay that did not block clicking areas of
a parent widget when my alerts did not take up the entire parent. To
achieve this I detect the sizing pass via the invisible flag and only
render the alerts content and then on the next pass I add the scroll bar
in around the alert content. Whenever the alert content changed though I
would need to create a new Area with a new id to get proper sizing. That
is a memory leak so I wanted to reset the size state to trigger a sizing
pass. Memory is rightfully protected enough that the path to remove
memory was dropped and I just added a hook to set a resize flag.

I am sure there are better ways but this is what made sense to me.
Looking forward to thoughts.

~~Logistics wise, I have proposed it as a patch because I was based off
0.31.1 for testing. I was also thinking it could be released quickly. I
am happy to cherry pick onto main after. If that is not allowed I can
rebase to main and pull against that.~~ (rebased on main)

---------

Co-authored-by: Wesley Murray <murraywj97@gmail.com>
2025-07-03 13:14:07 +02:00
Lucas Meurer 6d312cc4c7
Add support for scrolling via accesskit / kittest (#7286)
I need to scroll in a snapshot test in my app, and kittest had no
utilities for this. Event::MouseWheel is error prone. This adds support
for some accesskit scroll actions, and uses this in kittest to add
helpers to scroll to a node / scroll the scroll area surrounding a node.

The accesskit code says down/up/left/right `Scrolls by approximately one
screen in a specific direction.`. Unfortunately it's difficult to get
the size of a "screen" (I guess that would be the size of the containing
scroll area)where I implemented the scrolling, so for now I've hardcoded
it to 100px. I think scrolling a fixed amount is still better than not
scrolling at all.

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-07-03 12:02:05 +02:00
Emil Ernerfeldt 378e22e6ec Improve the `ThemePreference` selection UI slightly 2025-07-03 09:16:13 +02:00
Emil Ernerfeldt 40c69cd1ba
Respect and detect `prefers-color-scheme: no-preference` (#7293)
I don't think this will make a difference in practice, but technically
there are three preference states:

* `dark`
* `light`
* `no-preference`

Previously we would only check for `dark`, and if not set would assume
`light`.
Not we also check `light` and if we're neither `dark` or `light` we
assume nothing.
2025-07-03 08:58:45 +02:00
Andreas Reich 1878874f7d
Free textures after submitting queue instead of before with wgpu renderer on Web (#7291) 2025-07-02 16:14:46 +02:00
Emil Ernerfeldt dc79998044
Improve text rendering in light mode (#7290)
This changes how we convert glyph coverage to alpha (and ultimately a
color), but only in light mode.

This is a bit of a hack, because it doesn't fix dark-on-light text in
_dark mode_ (if you have any), but for the common case this PR is a huge
improvement.

You can also tweak this yourself now using
`Visuals::text_alpha_from_coverage` or from the UI (bottom of the
image):


![image](https://github.com/user-attachments/assets/350210d4-c0bb-44b6-84cc-47c2e9d4b9f0)



## Before / After

![widget_gallery_light_x1](https://github.com/user-attachments/assets/21f5a2a0-6b4e-4985-b17f-cd1c7cc01b46)
![widget_gallery_light_x1](https://github.com/user-attachments/assets/5dfec04a-c81c-43ef-8d86-fc48ef7958f1)


## Black text Before/after
If you think the text above looks too weak, it's only because of the
default text color. Here's how it looks like with perfectly `#000000`
black text:


![image](https://github.com/user-attachments/assets/56a4a4f3-c431-4991-b941-a566a4ae94ed)
![Screenshot 2025-07-02 at 13 59
30](https://github.com/user-attachments/assets/df5a91ad-0bb8-4a0f-81a2-50852e7556c1)
2025-07-02 14:58:37 +02:00
Emil Ernerfeldt 8bedaf6e5b
Add light-mode Widget Gallery screenshot test (#7288)
Part of some work to improve text rendering in light mode (again!)
2025-07-02 12:00:36 +02:00
Emil Ernerfeldt 22c6a9ae69
`egui_kittest`: Add `HarnessBuilder::theme` (#7289)
Makes it ergonomic to snapshot test light vs dark mode
2025-07-02 12:00:22 +02:00
Emil Ernerfeldt 0857527f1d
Add `Visuals::weak_text_alpha` and `weak_text_color` (#7285)
* Closes https://github.com/emilk/egui/issues/7262

This also makes the default weak color slightly less weak in most cases.
2025-07-01 20:42:54 +02:00
Emil Ernerfeldt 9d1dce51eb
Extend .typos.toml to enforce american english (#7284)
More or less the same list we use at Rerun
2025-07-01 15:54:00 +02:00
Emil Ernerfeldt 737c61867b
Add `Visuals::text_edit_bg_color` (#7283)
* Closes https://github.com/emilk/egui/issues/7263
2025-07-01 15:13:16 +02:00
Emil Ernerfeldt 9e021f78da
Change `ui.disable()` to modify opacity (#7282)
* Closes https://github.com/emilk/egui/pull/6765


Branched off of https://github.com/emilk/egui/pull/6765 by @tye-exe.

I needed to branch off to update snapshot images

---------

Co-authored-by: tye-exe <tye@mailbox.org>
Co-authored-by: Tye <131195812+tye-exe@users.noreply.github.com>
2025-07-01 14:05:53 +02:00
Emil Ernerfeldt b2995dcb83
Use Rust edition 2024 (#7280) 2025-06-30 14:01:57 +02:00
Emil Ernerfeldt 962c8e26a8
Update MSRV to 1.85 (#7279) 2025-06-30 13:43:27 +02:00
Emil Ernerfeldt 8ba42f322d
Add `Context::cumulative_frame_nr` (#7278) 2025-06-30 13:29:56 +02:00
Emil Ernerfeldt d770cd53a6
Add `Context::current_pass_index` (#7276)
This can be used by developers who wants to add diagnostics when there
is a multi-pass egui frame.
2025-06-30 10:41:27 +02:00
Emil Ernerfeldt 2525546fef Simplify some bezier math 2025-06-30 10:03:54 +02:00
Lukas Rieger c943720eed
Slider: move by at least the next increment when using fixed_decimals (#7066)
fixes https://github.com/emilk/egui/issues/7065
2025-06-29 13:30:39 +02:00
Nicolas ab9f55ab01
Fix crash in `egui_extras::FileLoader` after `forget_image` (#6995)
This pull request modifies the `BytesLoader` implementation for
`FileLoader` in `crates/egui_extras/src/loaders/file_loader.rs` to
improve thread safety and handle unexpected states more gracefully.

### Changes to thread safety and state handling:
* Updated the cache logic to check if the `uri` exists in the cache
before inserting the result. If the `uri` is not found, a log message is
added to indicate the loading was canceled. This change prevents
overwriting cache entries unexpectedly.

* Closes <https://github.com/emilk/egui/issues/6755>
* [x] I have followed the instructions in the PR template
2025-06-27 11:27:03 +02:00
Emil Ernerfeldt ae8363ddb5
eframe web: only cosume copy/cut events if the canvas has focus (#7270)
Previously eframe would "steal" these events (by calling
`stop_propagation/prevent_default`) even when the eframe canvas did not
have focus.
2025-06-27 10:25:47 +02:00
Lucas Meurer 78a8de2e8f
Respect `StyleModifier` in popup `Frame` style (#7265)
This makes it possible to style the Popup's frame using a StyleModifier
2025-06-25 14:26:36 +02:00
Matt Keeter f11a3510ba
Support custom syntect settings in syntax highlighter (#7084)
<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/main/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to test and add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review your PR, but my time is limited!
-->

* Closes <https://github.com/emilk/egui/issues/3964>
* [X] I have followed the instructions in the PR template

This PR adds support for syntax highlighting with custom
`syntect::parsing::SyntaxSet` and `syntect::highlighting::ThemeSet`. It
adds a new `egui_extras::highlight_with` function (enabled with `feature
= "syntect"`), which takes a new public`struct SyntectSettings`
containing the syntax and theme sets.

```rust
let mut builder = SyntaxSetBuilder::new();
builder.add_from_folder("syntax", true).unwrap();
let ps = builder.build();
let ts = syntect::highlighting::ThemeSet::load_defaults();
let syntax =
    egui_extras::syntax_highlighting::SyntectSettings { ps, ts };

// ...elsewhere
egui_extras::syntax_highlighting::highlight_with(
    ui.ctx(),
    ui.style(),
    &theme,
    buf,
    "rhai",
    &syntax,
);
```

There's a little bit of architectural complexity, but it all emerges
naturally from the problem's constraints.

Previously, the `Highlighter` both contained the `syntect` settings
_and_ implemented `egui::cache::ComputerMut` to highlight a string; the
settings would never change. After this change, the `syntect` settings
have become part of the cache key, so we should redo highlighting if
they change. The `Highlighter` becomes an empty `struct` which just
serves to implement `ComputerMut`.

`SyntaxSet` and `ThemeSet` are not hasheable themselves, so can't be
used as cache keys direction. Instead, we can use the *address* of the
`&SyntectSettings` as the key. This requires an object with a custom
`Hash` implementation, so I added a new `HighlightSettings(&'a
SyntectSettings)`, implementing `Hash` using `std::ptr::hash` on the
reference. I think using the address is reasonable – it would be _weird_
for a user to be constantly moving around their `SyntectSettings`, and
there's a warning in the docstring to this effect.

To work _without_ custom settings, `SyntectSettings::default` preserves
the same behavior as before, using `SyntaxSet::load_defaults_newlines`
and `ThemeSet::load_defaults`. If the user doesn't provide custom
settings, then we instantiate a singleton `SyntectSettings` in `data`
and use it; this will only be constructed once.

Finally, in cases where the `syntect` feature is disabled,
`SyntectSettings` are replaced with a unit `()`. This adds a _tiny_
amount of overhead – one singleton `Arc<()>` allocation and a lookup in
`data` per `highlight` – but I think that's better than dramatically
different implementations. If this is an issue, I can refactor to make
it zero-cost when the feature is disabled.
2025-06-24 15:09:29 +02:00
Max “Goldstein” Siling 853feea464
Fix incorrect window sizes for non-resizable windows on Wayland (#7103)
Using physical window sizes leads to all kinds of fun stuff: winit
always uses scale factor 1.0 on start to convert it back to logical
pixels and uses these logical pixels to set min/max size for
non-resizeable windows. You're supposed to adjust size after getting a
scale change event if you're using physical sizes, but adjusting min/max
sizes doesn't seem to work on sway, so the window is stuck with an
incorrect size.

The scale factor we guessed might also be wrong even if there's only a
single display since it doesn't take fractional scale into account.

TL;DR: winit actually wants logical sizes in these methods (since
Wayland in general operates mostly on logical sizes) and converting them
back and forth is lossy.

<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/main/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to test and add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review your PR, but my time is limited!
-->

* Closes https://github.com/emilk/egui/issues/7095
* [x] I have followed the instructions in the PR template

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-06-24 13:44:56 +02:00
Andreas Reich 98add13933
Workaround libpng crash on macos by not creating `NSImage` from png data (#7252) 2025-06-19 10:30:05 +02:00
Lucas Meurer c8b844cd83
Use the new Popup api for the color picker button (#7137)
The color picker popup is now aligned to the bottom left edge (instead
of the bottom right), but I think this makes more sense and is aligned
with ComboBox etc. It also gets the new nice auto positioning.

* closes #5832 
* [x] I have followed the instructions in the PR template
2025-06-18 19:19:05 +02:00
Lucas Meurer 0152a87519
Create custom `egui_kittest::Node` (#7138)
This adds a custom Node struct with proper support for egui types
(`Key`, `Modifiers`, `egui::Event`, `Rect`) instead of needing to use
the kittest / accesskit types.

I also changed the `click` function to do a proper mouse move / mouse
down instead of the accesskit click. Also added `accesskit_click` to
trigger the accesskit event. This resulted in some changed snapshots,
since the elements are now hovered.

Also renamed `press_key` to `key_press` for consistency with
`key_down/key_up`.

Also removed the Deref to the AccessKit Node, to make it clearer when to
expect egui and when to expect accesskit types.

* Closes #5705 
* [x] I have followed the instructions in the PR template
2025-06-17 12:17:38 +02:00
Emil Ernerfeldt 8c2df4802c
Add back old `Tooltip::new` (#7156)
I was a bit too hasty in https://github.com/emilk/egui/pull/7151 and
changed a public API in a breaking way, for no good reason
2025-06-16 19:36:19 +02:00
Zach Bateman 011e0d261a
egui_extras: Enable setting DatePickerButton start and end year explicitly (#7061)
Add the ability to set the `DatePickerButton`'s start and end years via
new `start_year` and `end_year` methods.

Continue to use the existing today - 100 years and today + 10 years
behavior if a year is not specified.

* This more fully closes <https://github.com/emilk/egui/issues/3597> and
expands on <https://github.com/emilk/egui/pull/3599>.
* [x] I have followed the instructions in the PR template
2025-06-16 18:27:26 +02:00
Lucas Meurer 5194c0df3e
Minor atoms improvements (#7145)
Improve some lifetime bounds and add some convenience constructors
2025-06-16 08:42:17 +02:00
Emil Ernerfeldt 06760e1b08
Change API of `Tooltip` slightly (#7151)
We try to be consistent with our parameter order to reduce surprise for
users.

I also renamed a few things to clarify what is what
2025-06-16 08:30:46 +02:00
Emil Ernerfeldt 699be07978 Add Vec2::ONE 2025-06-15 18:01:58 -07:00