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

3487 Commits

Author SHA1 Message Date
lucasmerlin
0f290b4904 Add PR preview deployments (#5131)
This adds preview deployments that will deploy a version of
egui_demo_app for each pull request, making things easier to review /
test.

Some notes on security:
The preview deployment is split in two workflows, preview_build and
preview_deploy.
`preview_build` runs on pull_request, so it won't have any access to the
repositories secrets, so it is safe to
build / execute untrusted code.
`preview_deploy` has access to the repositories secrets (so it can push
to the pr preview repo) but won't run
any untrusted code (it will just extract the build artifact and push it
to the pages branch where it will
automatically be deployed).

To set this up, a DEPLOY_KEY secret needs to be added, which allows the
action to push the compiled artifacts into this repository:
https://github.com/egui-pr-preview/pr
The deploy key is the private key part of a key generated via
ssh-keygen. The public key is set as a deploy key in that repo.
I have created the repo on a separate github org, so it won't be
directly associated with emil or egui in case someone pushes something
naughty.

I have set this up in my fork of egui to show how this works:
- I created a PR: https://github.com/lucasmerlin/egui/pull/2
- The code will be compiled and pushed to the egui-pr-preview/pr repo
and deployed via github pages
- The bot leaves a comment on the pr with a link to the preview
- The preview is available at
https://egui-pr-preview.github.io/pr/2-pr-preview-demo/
(It's unfortunately only available a couple seconds after the bot writes
the comment, because the pages deployment action is run independently on
the other repository)
- Once the PR is merged / closed the preview will be cleaned up
(unfortunately the empty folder will remain, it seems like it's not
possible to remove that via the JamesIves/github-pages-deploy-action
action I use, but I don't think that it's a big issue)

I'll leave the PR in draft until the DEPLOY_KEY is set up
2024-09-20 09:08:58 +02:00
lucasmerlin
9ba97a9a2f Fix empty grids repeatedly requesting a discard (#5133)
* Closes <https://github.com/emilk/egui/issues/5132>
* [x] I have followed the instructions in the PR template

This does cause a slight difference in the amount of space allocated by
a empty grid, is this a problem?
Before:

<img width="113" alt="image"
src="https://github.com/user-attachments/assets/88c9c1a8-2ab8-4b01-8d57-0eb0655fa0e4">

After:

<img width="101" alt="image"
src="https://github.com/user-attachments/assets/8e1c9d1b-54d6-43b9-9e37-2614dd90d6fe">
2024-09-20 09:08:44 +02:00
Emil Ernerfeldt
5cc35d2212 Improve docstring of Ui::new_child 2024-09-19 14:41:18 +02:00
Ilya Zlobintsev
00cb50ebad Add gtk-egui-area integration to README (#5129)
<!--
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!
-->
* [x] I have followed the instructions in the PR template

Hi, I've made an integration that allows egui to be embedded as a widget
inside of a GTK application. I'm planning to use it to draw interactive
plots via `egui_plot`, as I haven't found comparable plotting widgets in
GTK. I hope others will find this integration useful as well.

The library doesn't do its own rendering, it instead relies on
`egui_glow` to render inside of a GTK-provided OpenGL drawing area.

It is published on [crates.io](https://crates.io/crates/gtk-egui-area).
2024-09-19 13:30:43 +02:00
Emil Ernerfeldt
e0f0b7f47f Remember to call ui.register_rect for better debug (#5130) 2024-09-19 12:23:53 +02:00
Emil Ernerfeldt
b1784249d2 Fix merge race 2024-09-19 12:01:10 +02:00
Emil Ernerfeldt
902c54e534 Add 💻 emoji to the system, theme selector 2024-09-19 11:56:54 +02:00
Emil Ernerfeldt
b8d008177a Lower log level of "Loading new fonts" to trace 2024-09-19 11:56:38 +02:00
lucasmerlin
1b8737cf02 Interactive Ui:s: add UiBuilder::sense and Ui::response (#5054)
<!--
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 #5053 
* [x] I have followed the instructions in the PR template


This fixes #5053 by adding a Sense parameter to UiBuilder, using that in
Context::create_widget, so the Widget is registered with the right Sense
/ focusable. Additionally, I've added a ignore_focus param to
create_widget, so the focus isn't surrendered / reregistered on
Ui::interact_bg.

The example from #5053 now works correctly: 


https://github.com/user-attachments/assets/a8a04b5e-7635-4e05-9ed8-e17d64910a35

<details><summary>Updated example code</summary>
<p>

```rust
            ui.button("I can focus");

            ui.scope_builder(
                UiBuilder::new()
                    .sense(Sense::click())
                    .id_source("focus_test"),
                |ui| {
                    ui.label("I can focus for a single frame");
                    let response = ui.interact_bg();
                    let t = if response.has_focus() {
                        "has focus"
                    } else {
                        "doesn't have focus"
                    };
                    ui.label(t);
                },
            );

            ui.button("I can't focus :(");
```

</p>
</details> 



---

Also, I've added `Ui::interact_scope` to make it easier to read a Ui's
response in advance, without having to know about the internals of how
the Ui Ids get created.

This makes it really easy to created interactive container elements or
custom buttons, without having to use Galleys or
Painter::add(Shape::Noop) to style based on the interaction.

<details><summary>
Example usage to create a simple button
</summary>
<p>


```rust
use eframe::egui;
use eframe::egui::{Frame, InnerResponse, Label, RichText, UiBuilder, Widget};
use eframe::NativeOptions;
use egui::{CentralPanel, Sense, WidgetInfo};

pub fn main() -> eframe::Result {
    eframe::run_simple_native("focus test", NativeOptions::default(), |ctx, _frame| {
        CentralPanel::default().show(ctx, |ui| {
            ui.button("Regular egui Button");
            custom_button(ui, |ui| {
                ui.label("Custom Button");
            });

            if custom_button(ui, |ui| {
                ui.label("You can even have buttons inside buttons:");

                if ui.button("button inside button").clicked() {
                    println!("Button inside button clicked!");
                }
            })
            .response
            .clicked()
            {
                println!("Custom button clicked!");
            }
        });
    })
}

fn custom_button<R>(
    ui: &mut egui::Ui,
    content: impl FnOnce(&mut egui::Ui) -> R,
) -> InnerResponse<R> {
    let auto_id = ui.next_auto_id();
    ui.skip_ahead_auto_ids(1);
    let response = ui.interact_scope(
        Sense::click(),
        UiBuilder::new().id_source(auto_id),
        |ui, response| {
            ui.style_mut().interaction.selectable_labels = false;
            let visuals = response
                .map(|r| ui.style().interact(&r))
                .unwrap_or(&ui.visuals().noninteractive());
            let text_color = visuals.text_color();

            Frame::none()
                .fill(visuals.bg_fill)
                .stroke(visuals.bg_stroke)
                .rounding(visuals.rounding)
                .inner_margin(ui.spacing().button_padding)
                .show(ui, |ui| {
                    ui.visuals_mut().override_text_color = Some(text_color);
                    content(ui)
                })
                .inner
        },
    );

    response
        .response
        .widget_info(|| WidgetInfo::new(egui::WidgetType::Button));

    response
}
```

</p>
</details> 



https://github.com/user-attachments/assets/281bd65f-f616-4621-9764-18fd0d07698b

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2024-09-19 11:55:21 +02:00
lucasmerlin
bfafddfdec Add Response::intrinsic_size to enable better layout in 3rd party crates (#5082)
This adds a `intrinsic_size` field to the Response struct which allows
me to grow a egui button frame while still being able to know it's
intrinsic size in
[egui_flex](https://github.com/lucasmerlin/hello_egui/tree/main/crates/egui_flex)

* Related to
https://github.com/emilk/egui/issues/4378#issuecomment-2333800938
* [X] I have followed the instructions in the PR template

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2024-09-19 11:55:09 +02:00
Emil Ernerfeldt
2a40d16e5a Center-align all text vertically (#5117)
* Closes https://github.com/emilk/egui/issues/4929
* Builds on top of https://github.com/emilk/egui/pull/2724 by @lictex
(ptal!)
* Implement `Center` and `Max` vertical text alignment properly
* Change default vertical alignment of text to centering

The end result is that text centers better in buttons and other places,
especially when mixing in emojis.
Before, mixing text of different heights (e.g. emojis and latin text) in
a label or button would cause the text to jump vertically.

## Before
This is `master`, with custom `FontTweak` to move fonts up and down:
<img width="1714" alt="image"
src="https://github.com/user-attachments/assets/a10e2927-e824-4580-baea-124c0b38a527">
<img width="102" alt="image"
src="https://github.com/user-attachments/assets/cd41f415-197b-42cd-9558-d46d63c21dcb">


## After
This PR, with the default (zero) `FontTweak`

<img width="102" alt="image"
src="https://github.com/user-attachments/assets/15e7d896-66b1-4996-ab58-dd1850b19a63">

<img width="1714" alt="image"
src="https://github.com/user-attachments/assets/54ec708c-7698-4754-b1fc-fea0fd240ec9">
2024-09-19 11:44:29 +02:00
valadaptive
bb9e874c83 Update sampler along with texture on wgpu backend (#5122)
<!--
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 #5121
* [x] I have followed the instructions in the PR template

This unifies the code paths in `update_texture` somewhat, so that the
texture sampler and bind group are always replaced.

Not sure whether removing and reinserting the texture from and into the
`textures` map, or creating a new bind group, has much of a performance
impact. An alternative, as described in #5121, would be to split the
functionality for updating a texture's data from updating its options,
so that we don't have to unconditionally update the bind group (or do
something like store the options to check if they're changed).
2024-09-19 09:16:42 +02:00
Emil Ernerfeldt
f4ed394a85 Add UI to modify FontTweak live (#5125)
This will make it easier to get nice sizing and vertical alignments of
fonts
2024-09-18 13:43:33 +02:00
rustbasic
e31b44f1a5 Fix: Event::Copy and Event::Cut behave as if they select the entire text when there is no selection. (#5115)
Fix: `Event::Copy` and `Event::Cut` behave as if they select the entire
text when there is no selection.

It's unexpected and disconcerting that this behavior occurs when there
is no selected area.
2024-09-18 11:17:02 +02:00
Emil Ernerfeldt
24205f572a Fix text selection of only whitespace (#5123)
* Closes https://github.com/emilk/egui/issues/5078
* Closes https://github.com/emilk/egui/pull/5120
2024-09-18 11:14:21 +02:00
Emil Ernerfeldt
ce3911bc0d In the options ui, show only the currently selected theme
* Closes https://github.com/emilk/egui/pull/5101
2024-09-18 11:13:55 +02:00
Emil Ernerfeldt
4dd89e2052 Fix some minor clippy lints from the future 2024-09-18 09:44:23 +02:00
rustbasic
1474c17b0d Fix: panic when dragging window between monitors of different pixels_per_point (#4868)
Fix: panic when dragging window between monitors of different
pixels_per_point

This will continue to help us as we develop `egui`.
I hope you agree with my defense of `panic`.

* Relate #3959
* Relate #4088

* Closes #4178
* Closes #4179


There is also a way to add log if necessary.
```
                log::debug!("Anti-panic behavior occurs");
```

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2024-09-17 19:49:53 +02:00
Emil Ernerfeldt
f38515afe9 Add Slider::clamping for precise clamp control (#5119)
This deprecates `.clamp_to_range` in favor of more control using
`.clamping`.

## Related
* https://github.com/emilk/egui/pull/4728
* Closes https://github.com/emilk/egui/issues/4881
* https://github.com/emilk/egui/pull/4882
* https://github.com/emilk/egui/pull/5118
2024-09-17 15:44:22 +02:00
Emil Ernerfeldt
1191d9fa86 Remove debug-assert that false-positived on large f32 values due to precision problems 2024-09-17 15:32:17 +02:00
Emil Ernerfeldt
7d6c83b37f Fix DragValue range clamping (#5118)
When using a `DragValue`, there are three common modes of range clamping
that the user may want:

A) no clamping
B) clamping only user input (dragging or editing text), but leave
existing value intact
C) always clamp

The difference between mode B and C is:

```rs
let mut x = 42.0;
ui.add(DragValue::new(&mut x).range(0.0..=1.0));
// What will `x` be here?
```

With this PR, we now can get the three behaviors with:

* A): don't call `.range()` (or use `-Inf..=Inf`)
* B) call `.range()` and `.clamp_existing_to_range(false)`
* C) call `.range()`

## Slider clamping
Slider clamping is slightly different, since a slider always has a
range.

For a slider, there are these three cases to consider:

A) no clamping
B) clamp any value that the user enters, but leave existing values
intact
C) always clamp all values

Out of this, C should probably be the default.

I'm not sure what the best API is for this yet. Maybe an `enum` 🤔 


I'll take a pass on that in a future PR.

## Related
* https://github.com/emilk/egui/pull/4728
* https://github.com/emilk/egui/issues/4881
* https://github.com/emilk/egui/pull/4882
2024-09-17 14:44:20 +02:00
Emil Ernerfeldt
89da356b79 Fix: call save when hiding tab, and update when focusing it (#5114)
Fix for a regression in 0.28

* `App::save` will now be called when the web app is hidden (e.g. goes
to a background tab)
* `App::update` will now be called when the web app is un-hidden (e.g.
becomes the foreground tab)
2024-09-16 16:28:54 +02:00
Nicolas
1488ffa35a Use log crate instead of eprintln & remove some unwraps (#5010)
<!--
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!
-->

- I fixed the TODO to use the `log` crate instead of `eprintln`
- Set the rust-version in the `scripts/check.sh` to the same as egui is
on
- I made xtask use anyhow to remove some unwraps 

* [x] I have followed the instructions in the PR template
2024-09-13 14:23:13 +02:00
Emil Ernerfeldt
66076101e1 Add Context::request_discard (#5059)
* Closes https://github.com/emilk/egui/issues/4976
* Part of #4378 
* Implements parts of #843

### Background
Some widgets (like `Grid` and `Table`) needs to know the width of future
elements in order to properly size themselves. For instance, the width
of the first column of a grid may not be known until all rows of the
grid has been added, at which point it is too late. Therefore these
widgets store sizes from the previous frame. This leads to "first-frame
jitter", were the content is placed in the wrong place for one frame,
before being accurately laid out in subsequent frames.

### What
This PR adds the function `ctx.request_discard` which discards the
visual output and does another _pass_, i.e. calls the whole app UI code
once again (in eframe this means calling `App::update` again). This will
thus discard the shapes produced by the wrongly placed widgets, and
replace it with new shapes. Note that only the visual output is
discarded - all other output events are accumulated.

Calling `ctx.request_discard` should only be done in very rare
circumstances, e.g. when a `Grid` is first shown. Calling it every frame
will mean the UI code will become unnecessarily slow.

Two safe-guards are in place:

* `Options::max_passes` is by default 2, meaning egui will never do more
than 2 passes even if `request_discard` is called on every pass
* If multiple passes is done for multiple frames in a row, a warning
will be printed on the screen in debug builds:


![image](https://github.com/user-attachments/assets/c2c1e4a4-b7c9-4d7a-b3ad-abdd74bf449f)

### Breaking changes
A bunch of things that had "frame" in the name now has "pass" in them
instead:

* Functions called `begin_frame` and `end_frame` are now called
`begin_pass` and `end_pass`
* `FrameState` is now `PassState`
* etc


### TODO
* [x] Figure out good names for everything (`ctx.request_discard`)
* [x] Add API to query if we're gonna repeat this frame (to early-out
from expensive rendering)
* [x] Clear up naming confusion (pass vs frame) e.g. for `FrameState`
* [x] Figure out when to call this
* [x] Show warning on screen when there are several frames in a row with
multiple passes
* [x] Document
* [x] Default on or off?
* [x] Change `Context::frame_nr` name/docs
* [x] Rename `Context::begin_frame/end_frame` and deprecate the old ones
* [x] Test with Rerun
* [x] Document breaking changes
2024-09-13 14:20:51 +02:00
9SMTM6
08f5eb30a4 Add opt-out fragile-send-sync-non-atomic-wasm feature for wgpu (#5098)
Note this will break people depending on eframe or egui-wgpu with
--no-default-features.
I don't know what to do about that to be honest.

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

---------

Co-authored-by: Andreas Reich <r_andreas2@web.de>
2024-09-13 13:00:18 +02:00
Emil Ernerfeldt
f658f8b02b Make Slider and DragValue compatible with NonZeroUsize etc (#5105) 2024-09-13 11:27:13 +02:00
Emil Ernerfeldt
2c8df65bf6 Fix: Make sure RawInput::take clears all events, like it says it does (#5104) 2024-09-13 11:26:50 +02:00
Tau Gärtli
b5627c7d40 Make Light & Dark Visuals Customizable When Following The System Theme (#4744)
* Closes <https://github.com/emilk/egui/issues/4490>
* [x] I have followed the instructions in the PR template

---

Unfortunately, this PR contains a bunch of breaking changes because
`Context` no longer has one style, but two. I could try to add some of
the methods back if that's desired.

The most subtle change is probably that `style_mut` mutates both the
dark and the light style (which from the usage in egui itself felt like
the right choice but might be surprising to users).

I decided to deviate a bit from the data structure suggested in the
linked issue.
Instead of this:
```rust
pub theme: Theme, // Dark or Light
pub follow_system_theme: bool, // Change [`Self::theme`] based on `RawInput::system_theme`?
```

I decided to add a `ThemePreference` enum and track the current system
theme separately.
This has a couple of benefits:
* The user's theme choice is not magically overwritten on the next
frame.
* A widget for changing the theme preference only needs to know the
`ThemePreference` and not two values.
* Persisting the `theme_preference` is fine (as opposed to persisting
the `theme` field which may actually be the system theme).

The `small_toggle_button` currently only toggles between dark and light
(so you can never get back to following the system). I think it's easy
to improve on this in a follow-up PR :)
I made the function `pub(crate)` for now because it should eventually be
a method on `ThemePreference`, not `Theme`.

To showcase the new capabilities I added a new example that uses
different "accent" colors in dark and light mode:

<img
src="https://github.com/user-attachments/assets/0bf728c6-2720-47b0-a908-18bd250d15a6"
width="250" alt="A screenshot of egui's widget gallery demo in dark mode
using a purple accent color instead of the default blue accent">

<img
src="https://github.com/user-attachments/assets/e816b380-3e59-4f11-b841-8c20285988d6"
width="250" alt="A screenshot of egui's widget gallery demo in light
mode using a green accent color instead of the default blue accent">

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2024-09-11 17:52:53 +02:00
lampsitter
f4697bc007 Use Style's font size in egui_extras::syntax_highlighting (#5090)
<!--
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 https://github.com/emilk/egui/issues/3549
* [X] I have followed the instructions in the PR template

The syntax highlighting font size was always hardcoded to 12 or 10
depending on what case it was hitting (so not consistent). This is
particularly noticeable when you increase the font size to something
larger for the rest of the ui.

With this the default monospace font size is used by default.

Since the issue is closely related to #3549 I decided to implement the
ability to use override_font_id too.

## Visualized

Default monospace is set to 15 in all the pictures

Before/After without syntect:

![normal](https://github.com/user-attachments/assets/0d058720-47ff-49e7-af77-30d48f5e138c)


Before/after _with_ syntect:

![syntect](https://github.com/user-attachments/assets/e5c380fe-ced1-40ee-b4b1-c26cec18a840)

Font override after without/with syntect (monospace = 20):

![override](https://github.com/user-attachments/assets/efd1b759-3f97-4673-864a-5a18afc64099)

### Breaking changes

- `CodeTheme::dark` and `CodeTheme::light` takes in the font size
- `CodeTheme::from_memory` takes in `Style`
- `highlight` function takes in `Style`
2024-09-10 11:38:26 +02:00
lucasmerlin
89b6055f9c Add Ui::with_visual_transform (#5055)
* [X] I have followed the instructions in the PR template

This allows you to transform widgets without having to put them on a new
layer.
Example usage: 


https://github.com/user-attachments/assets/6b547782-f15e-42ce-835f-e8febe8d2d65

```rust
use eframe::egui;
use eframe::egui::{Button, Frame, InnerResponse, Label, Pos2, RichText, UiBuilder, Widget};
use eframe::emath::TSTransform;
use eframe::NativeOptions;
use egui::{CentralPanel, Sense, WidgetInfo};

pub fn main() -> eframe::Result {
    eframe::run_simple_native("focus test", NativeOptions::default(), |ctx, _frame| {
        CentralPanel::default().show(ctx, |ui| {
            let response = ui.ctx().read_response(ui.next_auto_id());

            let pressed = response
                .as_ref()
                .is_some_and(|r| r.is_pointer_button_down_on());

            let hovered = response.as_ref().is_some_and(|r| r.hovered());

            let target_scale = match (pressed, hovered) {
                (true, _) => 0.94,
                (_, true) => 1.06,
                _ => 1.0,
            };

            let scale = ui
                .ctx()
                .animate_value_with_time(ui.id().with("Down"), target_scale, 0.1);

            let mut center = response
                .as_ref()
                .map(|r| r.rect.center())
                .unwrap_or_else(|| Pos2::new(0.0, 0.0));
            if center.any_nan() {
                center = Pos2::new(0.0, 0.0);
            }

            let transform = TSTransform::from_translation(center.to_vec2())
                * TSTransform::from_scaling(scale)
                * TSTransform::from_translation(-center.to_vec2());

            ui.with_visual_transform(transform, |ui| {
                Button::new(RichText::new("Yaaaay").size(20.0))
                    .sense(Sense::click())
                    .ui(ui)
            });
        });
    })
}

```
2024-09-10 11:04:13 +02:00
YgorSouza
f897405a82 Use precomputed lookup table in Color32::from_rgba_unmultiplied (#5088)
Improves performances significantly (about 40 times) according to the
benchmarks.

* Closes <https://github.com/emilk/egui/issues/5086>
* [x] I have followed the instructions in the PR template
2024-09-10 09:50:56 +02:00
Tiaan Louw
1ccd056d19 Remove reference to egui::Color32. (#5011)
As most of the code refers to types in epaint, it makes sense to use the
Color32 alias from epaint as well.

<!--
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!
-->

- [x] I have followed the instructions in the PR template
2024-09-09 14:34:13 +02:00
Nicolas
1c293d4cc8 Update glow to 0.14 (#4952)
Before making this PR, I did take notice of a similar PR,
https://github.com/emilk/egui/pull/4833, but as it appears to be
abandoned, I decided to make this PR.

**Missing**
One of the checks doesn't pass as wgpu still uses glow `0.13.1`

```shell
cargo deny --all-features --log-level error --target aarch64-apple-darwin check
```

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

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2024-09-09 14:02:06 +02:00
Simon
9000d16d83 Export module egui::frame (#5087)
Remove the crate visibility of the frame module. Useful at least when
using `Frame::begin` as otherwise the returned type is opaque to library
users and prevents from creating containers that use `Frame` with a
similar interface.

Alternative is to only export `frame::Prepared` as `PreparedFrame` or
something, but I saw that other submodules of containers are already
public.

<!--
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 #2106
* [x] I have followed the instructions in the PR template
2024-09-09 11:11:52 +02:00
Tau Gärtli
49fb163ae9 Add return value to with_accessibility_parent (#5083)
Extracted out of #4805

In [`egui-theme-switch`] I'm allocating a response inside the closure
passed to `with_accessibility_parent` so that my radio buttons have the
radio group as parent.

I'm working around the lack of return value with a custom extension
trait for now: [`ContextExt`]

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

[`egui-theme-switch`]:
https://github.com/bash/egui-theme-switch/blob/main/src/lib.rs
[`ContextExt`]:
https://github.com/bash/egui-theme-switch/blob/main/src/context_ext.rs
2024-09-09 10:36:56 +02:00
Tau Gärtli
c6375efa22 Add WidgetType::RadioGroup (#5081)
Extracted out of #4805

I'm using this widget type in [`egui-theme-switch`] but since it's not
built in I have to call `accesskit_node_builder` which is a bit
cumbersome :)

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

[`egui-theme-switch`]:
https://github.com/bash/egui-theme-switch/blob/main/src/lib.rs
2024-09-09 10:36:13 +02:00
Emil Ernerfeldt
6b7f431237 Fix text sometime line-breaking or truncating too early (#5077) 2024-09-06 13:24:11 +02:00
Emil Ernerfeldt
b2dcb7d8db Fix bug in size calculation of truncated text (#5076)
The width of the elision character (`…`) was never included in the size
calculation
2024-09-06 11:30:32 +02:00
Emil Ernerfeldt
7cb61f8031 Deprecate ui.set_sizing_pass (#5074)
Use `UiBuilder::new().sizing_pass().invisible()` instead.

Also changes `UiBuilder::sizing_pass` to no longer turn the ui
invisible. You'll have to opt-in to that instead when it makes sense,
e.g. for the first frame of a tooltip, but not when auto-sizing a column
in a `Table`.
2024-09-05 12:44:12 +02:00
Girts
f74152988f Add Options::input_options for click-delay etc (#4942)
This takes 3 hardcoded constants from `input_state.rs` and puts them in
a `InputOptions` struct that then gets added to `Options`. This allows
adjusting these values at runtime, for example, to increase
`MAX_CLICK_DIST` for touchscreen usage.

* [x] I have followed the instructions in the PR template
2024-09-05 08:49:17 +02:00
Liam Rosenfeld
df9cd21248 Conditionally propagate web events using a filter in WebOptions (#5056)
Currently egui will prevent all web events from propagating. This causes
issues in contexts where you are using egui in a larger web context that
wants to receive events that egui does not directly respond to. For
example, currently using egui in a VSCode extension will block all app
hotkeys, such as saving and opening the panel.

This adds a closure to `WebOptions` that takes in a reference to the
egui event that is generated from a web event and returns if the
corresponding web event should be propagated or not. The default for it
is to always return false.

Alternatives I considered were:
1. Having the propagation filter be a property of the focus in memory.
That way it could be configured by the view currently selected. I opted
away from that because I wanted to avoid lowering eframe implementation
specific stuff into egui.
2. Having events contain a `web_propagate` flag that could be set when
handling them. However, that would not be compatible with the current
system of egui events being handled outside of the web event handler.

I just recently started using egui so I am not sure how idiomatic my
approach here is. I would be happy to switch this over to a different
architecture if there are suggestions.

<!--
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!
-->

* [x] I have followed the instructions in the PR template
2024-09-05 08:48:13 +02:00
Emil Ernerfeldt
2be93aca5d Fix visual glitch in scroll_bar_rect added in #5070 2024-09-05 08:09:35 +02:00
Emil Ernerfeldt
9fe4028f43 Add ScrollArea::scroll_bar_rect (#5070)
Useful for constraining the scroll bars to a smaller area. This will be
used by the new `egui_table` crate
(https://github.com/rerun-io/egui_table)


![egui_table](https://github.com/user-attachments/assets/cf2a4946-914d-4f5f-91f8-63da08345413)
2024-09-04 21:20:26 +02:00
Emil Ernerfeldt
0b92b93233 Add ui.shrink_clip_rect (#5068) 2024-09-04 17:01:41 +02:00
Antoine Beyeler
454abf705b Add generic return values to egui::Sides::show() (#5065)
This addresses this comment:
- https://github.com/rerun-io/rerun/pull/7344#discussion_r1742140870


* [x] I have followed the instructions in the PR template
2024-09-03 16:25:22 +02:00
Tim Straubinger
b9435541df Allow non-static eframe::App lifetime (#5060)
I love egui! Thank you Emil <3

This request specifically enables an `eframe::App` which stores a
lifetime.

In general, I believe this is necessary because `eframe::App` currently
does not seem to provide a good place to allocate and then borrow from
long-lived data between `update()` calls. To attempt to borrow such
long-lived data from a field of the `App` itself would be to create a
self-referential struct. A hacky alternative is to allocate long-lived
data with `Box::leak`, but that's a code smell and would cause problems
if a program ever creates multiple Apps.

As a more specific motivating example, I am developing with the
[inkwell](https://github.com/TheDan64/inkwell/) crate which requires
creating a `inkwell::context::Context` instance which is then borrowed
from by a bazillion things with a dedicated `'ctx` lifetime. I need such
a `inkwell::context::Context` for the duration of my `eframe::App` but I
can't store it as a field of the app. The most natural solution to me is
to simply to lift the inkwell context outside of the App and borrow from
it, but that currently fails because the AppCreator implicitly has a
`'static` lifetime requirement due to the use of `dyn` trait objects.

Here is a simpler, self-contained motivating example adapted from the
current [hello world example](https://docs.rs/eframe/latest/eframe/):

```rust
use eframe::egui;

struct LongLivedThing {
    message: String,
}

fn main() {
    let long_lived_thing = LongLivedThing {
        message: "Hello World!".to_string(),
    };

    let native_options = eframe::NativeOptions::default();
    eframe::run_native(
        "My egui App",
        native_options,
        Box::new(|cc| Ok(Box::new(MyEguiApp::new(cc, &long_lived_thing)))),
        //                                           ^^^^^^^^^^^^^^^^^
        //                                           BORROWING from long_lived_thing in App
    );
}

struct MyEguiApp<'a> {
    long_lived_thing: &'a LongLivedThing,
}

impl<'a> MyEguiApp<'a> {
    fn new(cc: &eframe::CreationContext<'_>, long_lived_thing: &'a LongLivedThing) -> Self {
        // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_visuals.
        // Restore app state using cc.storage (requires the "persistence" feature).
        // Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use
        // for e.g. egui::PaintCallback.
        MyEguiApp { long_lived_thing }
    }
}

impl<'a> eframe::App for MyEguiApp<'a> {
    fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            ui.heading(&self.long_lived_thing.message);
        });
    }
}
```

This currently fails to compile with:
```plaintext
error[E0597]: `long_lived_thing` does not live long enough
  --> src/main.rs:16:55
   |
16 |         Box::new(|cc| Ok(Box::new(MyEguiApp::new(cc, &long_lived_thing)))),
   |         ----------------------------------------------^^^^^^^^^^^^^^^^----
   |         |        |                                    |
   |         |        |                                    borrowed value does not live long enough
   |         |        value captured here
   |         cast requires that `long_lived_thing` is borrowed for `'static`
17 |     );
18 | }
   | - `long_lived_thing` dropped here while still borrowed
   |
   = note: due to object lifetime defaults, `Box<dyn for<'a, 'b> FnOnce(&'a CreationContext<'b>) -> Result<Box<dyn App>, Box<dyn std::error::Error + Send + Sync>>>` actually means `Box<(dyn for<'a, 'b> FnOnce(&'a CreationContext<'b>) -> Result<Box<dyn App>, Box<dyn std::error::Error + Send + Sync>> + 'static)>`
```

With the added lifetimes in this request, I'm able to compile and run
this as expected on Ubuntu + Wayland. I see the CI has been emailing me
about some build failures and I'll do what I can to address those.
Currently running the check.sh script as well.

This is intended to resolve https://github.com/emilk/egui/issues/2152

<!--
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 https://github.com/emilk/egui/issues/2152
* [x] I have followed the instructions in the PR template
2024-09-03 09:29:19 +02:00
Emil Ernerfeldt
7bac528d4d Add egui::Sides for adding UI on left and right sides (#5036)
* Closes https://github.com/emilk/egui/issues/5015
2024-09-02 10:47:20 +02:00
Nicolas
be944f0915 Rename id_source to id_salt (#5025)
* Closes <https://github.com/emilk/egui/issues/5020 >
* [x] I have followed the instructions in the PR template
2024-09-02 09:29:01 +02:00
YgorSouza
edea5a40b9 Remove the directories dependency (#4904)
eframe now has its own logic to find the storage_dir to persist the app
when the persistence feature is enabled, instead of using the
directories crate. The directory should be the same as before (verified
with a unit test).

* Closes <https://github.com/emilk/egui/issues/4884>
* [x] I have followed the instructions in the PR template
2024-09-01 10:47:28 +02:00
rustbasic
2a6a1302b8 Fix viewport not working when minimized (#5042)
Fix: The viewport stops working when the program is minimized.   

Fix: Logically, the weird parts have been normalized.
                                                               
**Issue :**
The viewport stops working when the program is minimized.
                         
* Related #3321
* Related #3877
* Related #3985
* Closes #3972
* Closes #4772
* Related #4832 
* Closes #4892
**Solution :**
When `request_redraw()` is performed in Minimized state, the occasional
screen tearing phenomenon has disappeared.
( Probably expected to be the effect of #4814 )
To address the issue of the `Immediate Viewport` not updating in
Minimized state, we can call `request_redraw()`.
2024-09-01 10:34:48 +02:00