Commit Graph

234 Commits

Author SHA1 Message Date
Ian Hobson 30277233ce
Add support for the safe area on iOS (#7578)
This PR is a continuation of #4915 by @frederik-uni and @lucasmerlin
that introduces support for keeping egui content within the 'safe area'
on iOS (avoiding the notch / dynamic island / menu bar etc.), with the
following changes:

- `SafeArea` now wraps `MarginF32` and has been renamed to
`SafeAreaInsets` to clarify its purpose.
- `InputState::screen_rect` is now marked as deprecated in favour of
either `viewport_rect` (which contains the entire screen), or
`content_rect` (which is the viewport rect with the safe area insets
removed).
- I added some comments to the safe area insets logic pointing out the
[safe area API coming in winit
v0.31](https://github.com/rust-windowing/winit/issues/3910).

---------

Co-authored-by: frederik-uni <147479464+frederik-uni@users.noreply.github.com>
Co-authored-by: Lucas Meurer <hi@lucasmerlin.me>
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-10-07 12:30:09 +02:00
Lucas Meurer 65249013c4
Fix stuck menu when submenu vanishes (#7589)
* Closes https://github.com/rerun-io/rerun/issues/11301

This fixes a bug where a menu could get stuck, not closing at all, when
the currently open submenu stops being shown.
I also added a way to reproduce this to the demo, as well as a test
ensuring that there is no race condition in the fix.
2025-10-07 10:16:35 +02:00
Emil Ernerfeldt bd45406fad
Use a lot more let-else (#7582) 2025-10-02 19:47:00 +02:00
Alan Everett b0c568a78e
Add rotation gesture support for trackpad sources (#7453)
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
Co-authored-by: Lucas Meurer <hi@lucasmerlin.me>
2025-09-11 12:44:17 +02:00
Emil Ernerfeldt c2912369ca
Improve text demo: more fine control of letter spacing (#7520) 2025-09-09 09:35:25 +02:00
Emil Ernerfeldt 01ee23c1a0
Add Zoom Factor to options panel (#7517) 2025-09-08 18:27:28 +02:00
valadaptive d5b0a6f446
More even text kerning (#7431)
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-09-08 17:29:41 +02:00
ozwaldorf 454af7aa6c
fix: `SubMenu` should not display when ui is disabled (#7428)
<!--
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!
-->

Adds a check for `ui.is_enabled()` when displaying the SubMenu items.
There were a few places the condition could be placed, but I figured
there was simplest. The inner button will already not be able to be
clicked due to ui being disabled.

cc @lucasmerlin 

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

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-08-24 14:43:31 +02:00
Emil Ernerfeldt 3024c39eaf
Enable and fix some more clippy lints (#7426)
One can never have too many lints
2025-08-08 09:57:53 +02:00
Lucas Meurer e8e99a0bb6
Fix manual `Popup` not closing (#7383)
Fixes manually created popups (via `Popup::new`) not closing, since
widget_clicked_elsewhere was always false.

This example would never close:

```rs
    let mut open = true;

    eframe::run_simple_native("My egui App", options, move |ctx, _frame| {
        egui::CentralPanel::default().show(ctx, |ui| {
            let response = egui::Popup::new(
                Id::new("popup"),
                ctx.clone(),
                PopupAnchor::Position(Pos2::new(10.0, 10.0)),
                LayerId::new(Order::Foreground, Id::new("popup")),
            )
            .open(open)
            .show(|ui| {
                ui.label("This is a popup!");
                ui.label("You can put anything in here.");
            });

            if let Some(response) = response {
                if response.response.should_close() {
                    open = false;
                }
            }
        });
    })
```

I also noticed that the Color submenu in the popups example had a double
arrow (must have been broken in the atoms PR):

<img width="248" height="110" alt="Screenshot 2025-08-07 at 13 42 28"
src="https://github.com/user-attachments/assets/a4e0c267-ae71-4b2c-a1f0-f53f9662d026"
/>

Also fixed this in the PR.
2025-08-07 14:18:04 +02:00
Emil Ernerfeldt 36a4981f29
Enable `clippy::iter_over_hash_type` lint (#7421)
This helped discover a few things that _might_ have been buggy.
2025-08-06 13:55:53 +02:00
Emil Ernerfeldt 9478a6223b
Rename `egui::containers::menu::Bar` to `egui::MenuBar` (#7327)
The old name is still there, just deprecated.
2025-07-10 10:33:48 +02:00
Lucas Meurer 9fd0ad36e0
Implement `BitOr` and `BitOrAssign` for `Rect` (#7319) 2025-07-09 15:29:51 +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 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 09596a5e7b
egui_kittest: more ergonomic functions taking `Impl Into<String>` (#7307) 2025-07-07 13:50:53 +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
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 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 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
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
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
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
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
Emil Ernerfeldt 2cf6a3a9a6
Track original SVG size (#7098)
This fixes bugs related to how an `Image` follows the size of an SVG.

We track the "source size" of each image, i.e. the original width/height
of the SVG, which can be different from whatever it was rasterized as.
2025-05-28 08:33:01 +02:00
Emil Ernerfeldt b8334f365b
Fix sometimes blurry SVGs (#7071)
* Closes https://github.com/emilk/egui/issues/3501

The problem occurs when you want to render the same SVG at different
scales, either at the same time in different parts of your UI, or at two
different times (e.g. the DPI changes).

The solution is to use the `SizeHint` as part of the key.

However, when you have an SVG in a resizable container, that can lead to
hundreds of versions of the same SVG. So new eviction code is added to
handle this case.
2025-05-21 20:01:40 +02:00
Emil Ernerfeldt f57cb27386
Include test windows in `egui_demo_lib` snapshot tests (#7070) 2025-05-21 17:44:27 +02:00
Emil Ernerfeldt 54ae2360ec
Fix incorrect color fringe colors on SVG:s (#7069)
This is a problem that affected the fringes on all SVG:s with
transparency, especially on a light background.

## Before

![image](https://github.com/user-attachments/assets/342823ad-005c-4f82-83a6-d2dcccfd3221)


## After

![image](https://github.com/user-attachments/assets/73398265-d333-461b-8c2b-fce405d95a9c)
2025-05-21 17:18:36 +02:00
Emil Ernerfeldt d0876a1a60
Rename `master` branch to `main` (#7034)
For consistency with other repositories, i.e. so I can write `git
checkout main` without worrying which repo I'm browsing.
2025-05-08 09:15:42 +02:00
Emil Ernerfeldt f9245954eb
Enable more clippy lints (#6853)
* Follows https://github.com/emilk/egui/pull/6848
2025-04-24 17:32:50 +02:00
Sven Niederberger 61e883be25
Revert "Add `OutputCommand::SetPointerPosition` to set mouse position" (#5867)
Reverts emilk/egui#5776

I noticed that this is already a `ViewportCommand`. Sorry for not seeing
that earlier.
2025-04-22 11:52:20 +02:00
giuseppeferrari c6bd30642a
Avoid infinite extension of ColorTest inside a Window (#5698)
Current implementation of ColorTest infinitely expand horizontally at
each redraw if included in a Window.

The effect can be see replacing the Panel in the ColorTestApp::update
with a Window:
```
egui::CentralPanel::default().show(ctx, |ui| {
   egui::Window::new("Colors").vscroll(true).show(ctx, |ui| {
   if frame.is_web() {
      ui.label(
         "NOTE: Some old browsers stuck on WebGL1 without sRGB support will not pass the color test.",
      );
      ui.separator();
   }
   egui::ScrollArea::both().auto_shrink(false).show(ui, |ui| {
      self.color_test.ui(ui);
   });
   self.color_test.ui(ui);
});
```

The cause is the is the _pixel_test_strokes_ function that, at each
redraw, tries to expand the target rectangle of 2.0 points in each
direction.
2025-04-08 11:38:13 +02:00
Aarni Koskela 36e007bd8c
Add overline option for Table rows (#5637)
* Closes no issue, I just needed this for an app and figured it could be
useful.
* [x] I have followed the instructions in the PR template

This PR adds an `overline` option for `egui_extras::TableRow`, which is
useful for visually grouping rows. The overline consumes no layout
space.

A screenshot of the demo app, showing every 7th row getting an overline.

<img width="704" alt="Screenshot 2025-01-25 at 14 40 08"
src="https://github.com/user-attachments/assets/9ccbee3d-296d-4afd-9290-c669e4ede1c0"
/>

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-04-08 11:36:43 +02:00
kernelkind fe631ff9ea
Use `TextBuffer` for `layouter` in `TextEdit` instead of `&str` (#5712)
This change allows `layouter` to use the `TextBuffer` instead of `&str`
in the closure. It is necessary when layout decisions depend on more
than just the raw string content, such as metadata stored in the
concrete type implementing `TextBuffer`.

In [our use case](https://github.com/damus-io/notedeck/pull/723), we
needed this to support mention highlighting when a user selects a
mention. Since mentions can contain spaces, determining mention
boundaries from the `&str` alone is impossible. Instead, we use the
`TextBuffer` implementation to retrieve the correct bounds.

See the video below for a demonstration:


https://github.com/user-attachments/assets/3cba2906-5546-4b52-b728-1da9c56a83e1


# Breaking change

This PR introduces a breaking change to the `layouter` function in
`TextEdit`.

Previous API:
```rust
pub fn layouter(mut self, layouter: &'t mut dyn FnMut(&Ui, &str, f32) -> Arc<Galley>) -> Self
```

New API:
```rust
pub fn layouter(mut self, layouter: &'t mut dyn FnMut(&Ui, &dyn TextBuffer, f32) -> Arc<Galley>) -> Self
```


## Impact on Existing Code

• Any existing usage of `layouter` will **no longer compile**.
• Callers must update their closures to use `&dyn TextBuffer` instead of
`&str`.

## Migration Guide

Before:
```rust
let mut layouter = |ui: &Ui, text: &str, wrap_width: f32| {
    let layout_job = my_highlighter(text);
    layout_job.wrap.max_width = wrap_width;
    ui.fonts(|f| f.layout_job(layout_job))
};
```

After:
```rust
let mut layouter = |ui: &Ui, text: &dyn TextBuffer, wrap_width: f32| {
    let layout_job = my_highlighter(text.as_str());
    layout_job.wrap.max_width = wrap_width;
    ui.fonts(|f| f.layout_job(layout_job))
};
```

---

* There is not an issue for this change.
* [x]  I have followed the instructions in the PR template

Signed-off-by: kernelkind <kernelkind@gmail.com>
2025-04-06 18:45:20 +02:00
Nicolas 58b2ac88c0
Add assert messages and print bad argument values in asserts (#5216)
Enabled the `missing_assert_message` lint

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

---------

Co-authored-by: Lucas Meurer <lucasmeurer96@gmail.com>
2025-03-25 09:20:29 +01:00
Emil Ernerfeldt 3f731ec794
Fix semi-transparent colors appearing too bright (#5824)
The bug was in `Color32::from_rgba_unmultiplied` and by extension
affects:

* `Color32::from_rgba_unmultiplied`
* `hex_color!`
* `HexColor`
* `ColorImage::from_rgba_unmultiplied`
* All images with transparency (png, webp, …)
* `Color32::from_white_alpha`

The bug caused translucent colors to appear too bright.

## More
Color is hard.

When I started out egui I thought "linear space is objectively better,
for everything!" and then I've been slowly walking that back for various
reasons:

* sRGB textures not available everywhere
* gamma-space is more _perceptually_ even, so it makes sense to use for
anti-aliasing
* other applications do everything in gamma space, so that's what people
expect (this PR)

Similarly, pre-multiplied alpha _makes sense_ for blending colors. It
also enables additive colors, which is nice. But it does complicate
things. Especially when mixed with sRGB/gamma (As @karhu [points
out](https://github.com/emilk/egui/pull/5824#issuecomment-2738099254)).

## Related
* Closes https://github.com/emilk/egui/issues/5751
* Closes https://github.com/emilk/egui/issues/5771 ? (probably; hard to
tell without a repro)
* But not https://github.com/emilk/egui/issues/5810

## TODO
* [x] I broke the RGBA u8 color picker. Fix it

---------

Co-authored-by: Andreas Reich <andreas@rerun.io>
2025-03-21 10:45:25 +01:00
Sven Niederberger b0bbca4e69
Add `OutputCommand::SetPointerPosition` to set mouse position (#5776)
<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/master/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!
-->

This is not supported on the web and not yet on Wayland.

~~I also had to update `ring` and add an exception for `paste` being
unmaintained.~~ Has since been updated on master.

* [x] I have followed the instructions in the PR template
2025-03-20 10:51:02 +01:00
valadaptive 267485976b
Simplify the text cursor API (#5785)
<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/master/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 N/A, but this is part of
https://github.com/emilk/egui/issues/3378
* [x] I have followed the instructions in the PR template

Other text layout libraries in Rust--namely, Parley and Cosmic
Text--have one canonical text cursor type (Parley's is a byte index,
Cosmic Text's also stores the line index). To prepare for migrating egui
to one of those libraries, it should also have only one text cursor
type. I also think simplifying the API is a good idea in and of
itself--having three different cursor types that you have to convert
between (and a `Cursor` struct which contains all three at once) is
confusing.

After a bit of experimentation, I found that the best cursor type to
coalesce around is `CCursor`. In the few places where we need a
paragraph index or row/column position, we can calculate them as
necessary.

I've removed `CursorRange` and `PCursorRange` (the latter appears to
have never been used), merging the functionality with `CCursorRange`. To
preserve the cursor position when navigating row-by-row, `CCursorRange`
now stores the previous horizontal position of the cursor.

I've also removed `PCursor`, and renamed `RowCursor` to `LayoutCursor`
(since it includes not only the row but the column). I have not renamed
either `CCursorRange` or `CCursor` as those names are used in a lot of
places, and I don't want to clutter this PR with a bunch of renames.
I'll leave it for a later PR.

Finally, I've removed the deprecated methods from `TextEditState`--it
made the refactoring easier, and it should be pretty easy to migrate to
the equivalent `TextCursorState` methods.

I'm not sure how many breaking changes people will actually encounter. A
lot of these APIs were technically public, but I don't think many were
useful. The `TextBuffer` trait now takes `&CCursorRange` instead of
`&CursorRange` in a couple of methods, and I renamed
`CCursorRange::sorted` to `CCursorRange::sorted_cursors` to match
`CursorRange`.

I did encounter a couple of apparent minor bugs when testing out text
cursor behavior, but I checked them against the current version of egui
and they're all pre-existing.
2025-03-20 10:49:38 +01:00
Lucas Meurer 93c06c3405
Add color picker menu item example (#5755)
* To be merged after #5756 



https://github.com/user-attachments/assets/ad40c172-cad2-4cc5-a3ef-3284b6545e94
2025-03-19 09:33:17 +01:00
lucasmerlin cd22517280
⚠️ Improved menu based on `egui::Popup` (#5716)
Continuation of #5713

**Silently breaking changes:**
- Menus now close on click by default, this is configurable via
`PopupCloseBehavior`

**Additional additions:**
- `Button::right_text`
- `StyleModifier`

This is a rewrite of the egui menus, with the following goals:
- submenu buttons should work everywhere, in a popup, context menu,
area, in some random Ui
- remove the menu state from Ui
- should work just like the previous menu
- ~proper support for keyboard navigation~
  - It's better now but requires further work to be perfect
- support `PopupCloseBehavior`

* Closes #4607 
* [x] I have followed the instructions in the PR template
2025-03-03 14:56:30 +01:00
lucasmerlin f5b058b908
Add `Ui::close` and `Response::should_close` (#5729)
This adds a generic way of telling containers to close from their child
`Ui`s.

* Part of #5727 
* [x] I have followed the instructions in the PR template

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-02-20 17:59:29 +01:00
lucasmerlin a8e98d3f9b
Add `Popup` and `Tooltip`, unifying the previous behaviours (#5713)
This introduces new `Tooltip` and `Popup` structs that unify and extend
the old popups and tooltips.

`Popup` handles the positioning and optionally stores state on whether
the popup is open (for click based popups like `ComboBox`, menus,
context menus).
`Tooltip` is based on `Popup` and handles state of whether the tooltip
should be shown (which turns out to be quite complex to handles all the
edge cases).

Both `Popup` and `Tooltip` can easily be constructed from a `Response`
and then customized via builder methods.

This also introduces `PositionAlign`, for aligning something outside of
a `Rect` (in contrast to `Align2` for aligning inside a `Rect`). But I
don't like the name, any suggestions? Inspired by [mui's tooltip
positioning](https://mui.com/material-ui/react-tooltip/#positioned-tooltips).

* Part of #4607 
* [x] I have followed the instructions in the PR template

TODOs:
- [x] Automatic tooltip positioning based on available space
- [x] Review / fix / remove all code TODOs 
- [x] ~Update the helper fns on `Response` to be consistent in naming
and parameters (Some use tooltip, some hover_ui, some take &self, some
take self)~ actually, I think the naming and parameter make sense on
second thought
- [x] Make sure all old code is marked deprecated

For discussion during review:
- the following check in `show_tooltip_for` still necessary?:
```rust
     let is_touch_screen = ctx.input(|i| i.any_touches());
     let allow_placing_below = !is_touch_screen; // There is a finger below. TODO: Needed?
```
2025-02-18 15:53:07 +01:00
Emil Ernerfeldt 0db56dc9f1 Fix the magnification range of the tessellation test 2025-02-04 17:35:55 +01:00
Emil Ernerfeldt 985e569542 Fix warning 2025-02-04 17:04:29 +01:00
Emil Ernerfeldt c90b97f4ef
Fix sharp corners for rectangles with StrokeKind != Inside (#5675)
Oops!
2025-02-04 14:36:29 +01:00
lucasmerlin b8051cc301
Add `SnapshotResults` struct to egui_kittest (#5672)
I got annoyed by all the slightly different variations of "collect
snapshot results and unwrap them at the end of test" I've written, so I
added a struct to make this nice and simple.

One controversial thing: It panics when dropped. I wanted to ensure
people cannot forget to unwrap the results at the end, and this was the
best thing I could come up with. I don't think this is possible via
clippy lint or something like that.

* [x] I have followed the instructions in the PR template
2025-02-04 14:01:32 +01:00
Emil Ernerfeldt 23ed49334e
⚠️ Rename `Rounding` to `CornerRadius` (#5673)
Breaking change!

* `Rounding` -> `CornerRadius`
* `rounding` -> `corner_radius`

This is to:
* Clarify
* Conform to other systems (e.g. Figma)
* Avoid confusion with `GuiRounding`
2025-02-04 12:53:18 +01:00
Emil Ernerfeldt 3c07e01d08
Improve tessellation quality (#5669)
## Defining what `Rounding` is
This PR defines what `Rounding` means: it is the corner radius of
underlying `RectShape` rectangle. If you use `StrokeKind::Inside`, this
means the rounding is of the outer part of the stroke. Conversely, if
you use `StrokeKind::Outside`, the stroke is outside the rounded
rectangle, so the stroke has an inner radius or `rounding`, and an outer
radius that is larger by `stroke.width`.

This definitions is the same as Figma uses.

## Improving general shape rendering
The rendering of filled shapes (rectangles, circles, paths, bezier) has
been rewritten. Instead of first painting the fill with the stroke on
top, we now paint them as one single mesh with shared vertices at the
border. This has several benefits:

* Less work (faster and with fewer vertices produced)
* No overdraw (nicer rendering of translucent shapes)
* Correct blending of stroke and fill

The logic for rendering thin strokes has also been improved, so that the
width of a stroke of `StrokeKind::Outside` never affects the filled area
(this used to be wrong for thin strokes).

## Improving of rectangle rendering
Rectangles also has specific improvements in how thin rectangles are
painted.
The handling of "Blur width" is also a lot better, and now works for
rectangles with strokes.
There also used to be bugs with specific combinations of corner radius
and stroke width, that are now fixed.

##  But why?
With the new `egui::Scene` we end up with a lot of zoomed out shapes,
with sub-pixel strokes. These need to look good! One thing led to
another, and then I became obsessive 😅

## Tessellation Test
In order to investigate the rendering, I created a Tessellation Test in
the `egui_demo_lib`.

[Try it
here](https://egui-pr-preview.github.io/pr/5669-emilkimprove-tessellator)

![Screenshot 2025-02-04 at 08 45
50](https://github.com/user-attachments/assets/20b47a30-de6a-4ff5-885b-2e2fd6d88321)


![image](https://github.com/user-attachments/assets/e17c50eb-5ae7-48d4-bb0d-4f2165075897)
2025-02-04 11:30:12 +01:00
Emil Ernerfeldt 04fca9c324
Remove date button from Scene demo, so as not to fail tests each day (#5657) 2025-01-30 20:51:12 +01:00