1
0
mirror of https://github.com/emilk/egui.git synced 2026-06-26 22:53:14 -04:00
Commit Graph

1523 Commits

Author SHA1 Message Date
lucasmerlin
341c26267e Very wip textedit atoms / textedit split 2025-07-03 20:00:30 +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
Azkellas
96c34139fd Select all text in DragValue when gaining focus via keyboard (#7107)
Previously, the `DragValue` widget selected all text when focus was
gained via a mouse click, but didn't when focus was gained via keyboard.


https://github.com/user-attachments/assets/5e82ca2c-0214-4201-ad2d-056dabc05e92

This PR makes both gained focus behaving the same way by selecting the
text on focus gained via keyboard.


https://github.com/user-attachments/assets/f246c779-3368-428c-a6b2-cec20dbc20a6

- [x] I have followed the instructions in the PR template

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-06-16 02:11:26 +02:00
valadaptive
54fded362d Clamp text cursor positions in the same places where we used to (#7081)
Closes #7077.

This fixes the problem shown in #7077 where clearing a `TextEdit`
wouldn't reset its cursor position. I've fixed that by adding back the
`TextCursorState::range` method, which clamps the selection range to
that of the passed `Galley`, and calling it in the same places where it
was called before #5785.

(/cc @juancampa)

* [x] I have followed the instructions in the PR template
2025-06-16 01:53:00 +02:00
Patrick Marks
df2c16ef0a Add anchored text rotation method, and clarify related docs (#7130)
Add a helper method to perform rotation about a specified anchor.

* Closes #7051
2025-06-16 01:42:01 +02:00
Nicolas
f33ff2c83d Make HSVA derive serde (#7132)
This pull request introduces a change to the `Hsva` struct in the
`crates/ecolor/src/hsva.rs` file to enable serialization and
deserialization when the `serde` feature is enabled.

* Closes <https://github.com/emilk/egui/issues/7131>
* [x] I have followed the instructions in the PR template
2025-06-16 01:40:42 +02:00
ardocrat
742da95bd7 Support for Back button Key on Android (#7073)
When your press a Back button on Android (for example at
`native-activity`), [Winit translates this
key](47b938dbe7/src/platform_impl/android/keycodes.rs (L237C42-L237C53))
as `NamedKey::BrowserBack`. Added convertion to `Key::Escape` at
`egui-winit` module.

---------

Co-authored-by: Advocat <advocat@ogr.local>
2025-06-16 01:28:27 +02:00
Lucas Meurer
4c04996a72 Fix missing repaint after consume_key (#7134)
Usually input events automatically trigger a repaint. But since
consume_key would remove the event egui would think there were no events
and not trigger a repaint. This fixes it by setting a flag on InputState
on consume_key.

* related: https://github.com/rerun-io/rerun/issues/10165
2025-06-13 14:06:50 +02:00
Lucas Meurer
5bc19f3ca3 Report image alt text as text if widget contains no other text (#7142)
- Same as https://github.com/emilk/egui/pull/7136 but now for atomics
2025-06-13 13:54:07 +02:00
Lucas Meurer
6eb7bb6e08 Add AtomLayout, abstracing layouting within widgets (#5830)
Today each widget does its own custom layout, which has some drawbacks:
- not very flexible
- you can add an `Image` to `Button` but it will always be shown on the
left side
  - you can't add a `Image` to a e.g. a `SelectableLabel`
- a lot of duplicated code

This PR introduces `Atoms` and `AtomLayout` which abstracts over "widget
content" and layout within widgets, so it'd be possible to add images /
text / custom rendering (for e.g. the checkbox) to any widget.

A simple custom button implementation is now as easy as this:
```rs
pub struct ALButton<'a> {
    al: AtomicLayout<'a>,
}

impl<'a> ALButton<'a> {
    pub fn new(content: impl IntoAtomics) -> Self {
        Self { al: content.into_atomics() }
    }
}

impl<'a> Widget for ALButton<'a> {
    fn ui(mut self, ui: &mut Ui) -> Response {
        let response = ui.ctx().read_response(ui.next_auto_id());

        let visuals = response.map_or(&ui.style().visuals.widgets.inactive, |response| {
            ui.style().interact(&response)
        });

        self.al.frame = self
            .al
            .frame
            .inner_margin(ui.style().spacing.button_padding)
            .fill(visuals.bg_fill)
            .stroke(visuals.bg_stroke)
            .corner_radius(visuals.corner_radius);

        self.al.show(ui)
    }
}

```

The initial implementation only does very basic layout, just enough to
be able to implement most current egui widgets, so:
- only horizontal layout
- everything is centered
- a single item may grow/shrink based on the available space
- everything can be contained in a Frame


There is a trait `IntoAtoms` that conveniently allows you to construct
`Atoms` from a tuple
```
   ui.button((Image::new("image.png"), "Click me!"))
```
to get a button with image and text.


This PR reimplements three egui widgets based on the new AtomLayout:
 - Button
   - matches the old button pixel-by-pixel
- Button with image is now [properly
aligned](https://github.com/emilk/egui/pull/5830/files#diff-962ce2c68ab50724b01c6b64c683c4067edd9b79fcdcb39a6071021e33ebe772)
in justified layouts
   - selected button style now matches SelecatbleLabel look
- For some reason the DragValue text seems shifted by a pixel almost
everywhere, but I think it's more centered now, yay?
 - Checkbox
- basically pixel-perfect but apparently the check mesh is very slightly
different so I had to update the snapshot
   - somehow needs a bit more space in some snapshot tests?
 - RadioButton
   - pixel-perfect
   - somehow needs a bit more space in some snapshot tests?

I plan on updating TextEdit based on AtomLayout in a separate PR (so
you could use it to add a icon within the textedit frame).
2025-06-13 09:39:52 +02:00
Emil Ernerfeldt
f0abce9bb8 Button inherits the alt_text of the Image in it, if any (#7136)
If a `Button` has an `Image` in it (and no text), then the
`Image::alt_text` will be used as the accessibility label for the
button.
2025-06-11 23:00:59 +02:00
Nicolas
9f9153805d lint: fix lints appearing in rust stable currently (#7118)
* [x] I have followed the instructions in the PR template
2025-06-11 17:38:06 +02:00
Rinde van Lon
cfb10a04f5 Improve ComboBox doc example (#7116)
Improves the `ComboBox` example with some code that shows how to handle
changes in the `ComboBox`’s selection. The approach is based on the
advice given in https://github.com/emilk/egui/discussions/923 . I hope
this saves future me (and hopefully others) a web search for how to do
this.

* [x] I have followed the instructions in the PR template
2025-06-11 12:01:34 +02:00
Emil Ernerfeldt
bdbe655852 Mark HarnessBuilder build functions with #[must_use] 2025-06-07 17:19:12 -07:00
Emil Ernerfeldt
209e818bd8 Improve deprecation message for old egui::menu 2025-06-07 10:24:28 -07:00
Emil Ernerfeldt
6e34152fa0 Add Context::format_modifiers (#7125)
Convenience
2025-06-07 19:22:16 +02:00
Emil Ernerfeldt
53098fad7b Support vertical-only scrolling by holding down Alt (#7124)
* Closes https://github.com/emilk/egui/issues/7120

You can now zoom only the X axis by holding down shift, and zoom only
the Y axis by holding down ALT.

In summary

* `Shift`: horizontal
* `Alt`: vertical
* `Ctrl`: zoom (`Cmd` on Mac)

Thus follows:
* `scroll`: pan both axis (at least for trackpads and mice with two-axis
scroll)
* `Shift + scroll`: pan only horizontal axis
* `Alt + scroll`: pan only vertical axis
* `Ctrl + scroll`: zoom all axes
* `Ctrl + Shift + scroll`: zoom only horizontal axis
* `Ctrl + Alt + scroll`: zoom only vertical axis

This is provided the application uses `zoom_delta_2d` for its zooming
needs.

The modifiers are exposed in `InputOptions`, but it is strongly
recommended that you do not change them.

## Testing
Unfortunately we have no nice way of testing this in egui.
But I've tested it in `egui_plot`.
2025-06-07 19:18:13 +02:00
Emil Ernerfeldt
1d5b011793 Add OperatingSystem::is_mac (#7122)
* Part of https://github.com/emilk/egui/issues/7120
2025-06-07 18:36:23 +02:00
Emil Ernerfeldt
cbd9c60399 Add Modifiers::matches_any (#7123)
* Part of https://github.com/emilk/egui/issues/7120
2025-06-07 18:36:16 +02:00
Emil Ernerfeldt
9681644936 Move all input-related options into InputOptions (#7121) 2025-06-07 18:25:19 +02:00
Guy Marshall
1abccb3f47 Typo in run_native doc comment (replace "a an" with "an") (#7094)
<!--
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!
-->
2025-06-03 16:57:43 +02:00
Emil Ernerfeldt
92fea8a18f Remove things that have been deprecated for over a year (#7099)
Removes all things that were marked `#[deprecated]` more than 12 months
ago
2025-05-28 09:47:15 +02:00