<!--
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!
-->
Did not test on platforms other than my phone, but I can't imagine it
causing problems. AFAIK if highp isn't supported then `precision highp
float;` needs to still not cause the program to fail to link/compile or
anything; it should just silently use some other precision.
* Fixes https://github.com/emilk/egui/issues/4268 for me but I only
tested it on a native Android app and I don't know whether backends
other than glow are affected.
* [x] I have followed the instructions in the PR template (but the
change is trivial so I'm just doing it from the master branch)
Before:

After:

## What
Fail all PRs that are opened from the master/main branch of the fork.
## Why
PR:s opened from the `master` branch cannot be collaborated on. That is,
we maintainers cannot push our own commits to it (e.g. to fix smaller
problems with it before merging).
## How
Untested code straight from Claude 3.7 😅
https://github.com/emilk/egui/pull/5394 made it so images would load on
a background thread, which is great. But this makes snapshot tests that
have images via include_image!() flakey since they might or might not
load by the time the snapshot is rendered.
This is no perfect solution, since the underlying problem of "waiting
for something async to happen" still exists and we should add some more
general solution for that.
<!--
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#2875
* Closes https://github.com/emilk/egui/pull/3340
* [x] I have followed the instructions in the PR template
Adds `create_native`. Similiar to `run_native` but it returns an
`EframeWinitApplication` which is a `winit::ApplicationHandler`. This
can be run on your own event loop. A helper fn `pump_eframe_app` is
provided to pump the event loop and get the control flow state back.
I have been using this approach for a few months.
---------
Co-authored-by: Will Brown <opensource@rebeagle.com>
This helped me benchmark the atomic layout (#5830) changes.
I also realized that the label benchmark wasn't testing the painting,
since the buttons at some point will be placed outside the screen_rect,
meaning it won't be painted.
This fixes it by benching the label in a child ui.
The `label &str` benchmark went from 483 ns to 535 ns with these
changes.
EDIT:
I fixed another benchmark problem, since the benchmark would show the
same widget millions of times for a single frame, the WidgetRects
hashmap would get huge, causing each iteration to slow down a bit more
and causing the benchmark to have unreliable results.
With this the `label &str` benchmark went from 535ns to 298ns. Also the
`label format!` benchmark now takes almost the same time (302 ns).
Before, it was a lot slower since it reused the same Context which
already had millions of widget ids.
* Closes <https://github.com/emilk/egui/issues/5406>
* [x] I have followed the instructions in the PR template
The changes follow what is described in the issue with a couple changes:
- Scroll bars are not hidden when dragging is disabled, for that
`ScrollArea::scroll_bar_visibility()` has to be used, this is as not to
limit the user configurability by imposing a specific function. The user
might want to retain the scrollbars visibility to show the current
position.
- The input for mouse wheel scrolling is unchanged. When I inspected the
code initially I made a mistake in recognizing the source of scrolling.
Current implementation is in fact using
`InputState::smooth_scroll_delta` and not `PassState::scroll_delta`,
therefore it is possible to prevent scrolling by setting the
`InputState::smooth_scroll_delta` to zero before painting the
`ScrollArea`.
A simple demo is available at
https://github.com/MStarha/egui_scroll_area_test
* [x] I have followed the instructions in the PR template
Previously, navigating text in `TextEdit` with Ctrl + left/right arrow
would jump inside words that contained combining characters (i.e.
diacritics). This PR introduces new dependency of `unicode-segmentation`
to handle grapheme encoding. The new implementation ignores whitespace
and other separators such as `-` (dash) between words, but respects `_`
(underscore).
---------
Co-authored-by: lucasmerlin <hi@lucasmerlin.me>
Fix: Popups do not appear in certain situations.
* Closes#5080
* Related #5107
The root cause is that `last_move_time` is not updated in certain
situations (slow situations?).
This adds an option for specifying the set of pointer buttons that can
be used to pan the scene via clicking and dragging.
The original behaviour where all buttons can pan the scene by default is
maintained.
Addresses part of #5891.
---
Edit: It looks like the failing test is unrelated and also appears on
master:
https://github.com/emilk/egui/actions/runs/14330259861/job/40164414607.
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
Starting with 77244cd4c5 the popup
open-state is cleaned up per memory pass.
This becomes problematic for implementations that share memory between
viewports (i.e. all of them, as far as i understand it), because each
viewport gets a context pass, and thus a memory pass, which cleans out
popup open state.
To illustrate my issue, i have modifed the multiple viewport example to
include a popup menu for the labels:
https://gist.github.com/mkalte666/4ecd6b658003df4c6d532ae2060c7595
(changes not included in this pr).
Then, when i try to use the popups, i get this:
https://github.com/user-attachments/assets/7d04b872-5396-4823-bf30-824122925528
Immediate viewports just break popup handling in general, while deferred
viewports kinda work, or dont. In this example ill be honest, it kind of
still did, sometimes. In my more complex app with multiple viewports
(where i encountered this first) it also just broke - even when just
showing root and one nother. Probably to do with the order wgpu vs glow
draws the viewports? Im not sure. In any case:
This commit adds `Memory::popup` (now `Memory::popups`) to the
per-viewport state of memory, including viewport aware cleanup, and
adding it to the list of things cleaned if a viewport goes away.
This results in the expected behavior:
https://github.com/user-attachments/assets/fd1f74b7-d3b2-4edc-8dc4-2ad3cfa2160e
I will note that with this, changing focus does not cause a popup to be
closed, which is consistent with current behavior on a single app.
Hope this helps
~Malte
<!--
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/THE_RELEVANT_ISSUE>
* [x] I have followed the instructions in the PR template
* [x] ~~I have run check.sh locally~~ CI on the fork, including checks,
went through.
**Added**
* Create `svg_text` feature flag to support text rendering & loading of
system fonts.
**Changed**
* Updates `resvg` to `0.45`.
* Adds `usvg::Options` field to the `SvgLoader` structure.
* Change function signatures to support passing `usvg::Options` to
downstream `load_svg_bytes_with_size`.
**Additional Info**
* I used this PR as a reference:
https://github.com/emilk/egui/pull/4659. @xNWP can you see if this
adequately resolves your concern from your original PR?
* Closes https://github.com/emilk/egui/issues/5977 (we may want to open
another issue for my other thoughts in this issue)
* Also, I would like to thank @xNWP and their original PR for being a
good reference for this one.
* [x] I have followed the instructions in the PR template
For some reason the pipeline in https://github.com/emilk/egui/pull/5698
succeeded even though the snapshots should have been updated. This
updates the snapshots.
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.
* 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>
<!--
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!
-->
A quick fix for a broken link: https://github.com/rerun/kittest ->
https://github.com/rerun-io/kittest
* [X] I have followed the instructions in the PR template
This changes the `Scene` behaviour to call `set_transform_layer` prior
to calling the user content fn, rather than after.
### Motivation
This provides a simple way for the user to access the `TSTransform` that
will be applied to the `Scene` within the user content function, e.g.
```rust
ui.ctx().layer_transform_to_global(ui.layer_id())
```
Previously getting the transform like this still kind of worked, but
resulted in the user content lagging behind the actual scene position by
a single frame, which looks a bit strange.
With this PR, the user content using the transform no longer lags by a
frame, and matches the scene's transform perfectly.
Accessing the `TSTransform` of the `Scene` within the user content
function is useful for the case where the user may want to instantiate
new `Ui` sublayers that also track the scene (by default, sublayers do
*not* apply the same transform as the scene, likely the cause of #5682).
With these changes, the user can have sublayers track the scene like so:
```rust
let scene_layer = ui.layer_id();
let sub_layer = egui::LayerId::new(scene_layer.order, self.id);
ui.ctx().set_sublayer(scene_layer, sub_layer);
let scene_transform = ui.ctx().layer_transform_to_global(scene_layer).unwrap();
ui.ctx().set_transform_layer(sub_layer, scene_transform);
```
### Tested with
- `egui_demo_app` scene example.
- Local `egui_graph` demo example.
---
<!--
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/THE_RELEVANT_ISSUE>
* [x] I have followed the instructions in the PR template
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>
## What
(written by @emilk)
When editing long text (thousands of line), egui would previously
re-layout the entire text on each edit. This could be slow.
With this PR, we instead split the text into paragraphs (split on `\n`)
and then cache each such paragraph. When editing text then, only the
changed paragraph needs to be laid out again.
Still, there is overhead from splitting the text, hashing each
paragraph, and then joining the results, so the runtime complexity is
still O(N).
In our benchmark, editing a 2000 line string goes from ~8ms to ~300 ms,
a speedup of ~25x.
In the future, we could also consider laying out each paragraph in
parallel, to speed up the initial layout of the text.
## Details
This is an ~~almost complete~~ implementation of the approach described
by emilk [in this
comment](<https://github.com/emilk/egui/issues/3086#issuecomment-1724205777>),
excluding CoW semantics for `LayoutJob` (but including them for `Row`).
It supersedes the previous unsuccessful attempt here:
https://github.com/emilk/egui/pull/4000.
Draft because:
- [X] ~~Currently individual rows will have `ends_with_newline` always
set to false.
This breaks selection with Ctrl+A (and probably many other things)~~
- [X] ~~The whole block for doing the splitting and merging should
probably become a function (I'll do that later).~~
- [X] ~~I haven't run the check script, the tests, and haven't made sure
all of the examples build (although I assume they probably don't rely on
Galley internals).~~
- [x] ~~Layout is sometimes incorrect (missing empty lines, wrapping
sometimes makes text overlap).~~
- A lot of text-related code had to be changed so this needs to be
properly tested to ensure no layout issues were introduced, especially
relating to the now row-relative coordinate system of `Row`s. Also this
requires that we're fine making these very breaking changes.
It does significantly improve the performance of rendering large blocks
of text (if they have many newlines), this is the test program I used to
test it (adapted from <https://github.com/emilk/egui/issues/3086>):
<details>
<summary>code</summary>
```rust
use eframe::egui::{self, CentralPanel, TextEdit};
use std::fmt::Write;
fn main() -> Result<(), eframe::Error> {
let options = eframe::NativeOptions {
..Default::default()
};
eframe::run_native(
"editor big file test",
options,
Box::new(|_cc| Ok(Box::<MyApp>::new(MyApp::new()))),
)
}
struct MyApp {
text: String,
}
impl MyApp {
fn new() -> Self {
let mut string = String::new();
for line_bytes in (0..50000).map(|_| (0u8..50)) {
for byte in line_bytes {
write!(string, " {byte:02x}").unwrap();
}
write!(string, "\n").unwrap();
}
println!("total bytes: {}", string.len());
MyApp { text: string }
}
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
CentralPanel::default().show(ctx, |ui| {
let start = std::time::Instant::now();
egui::ScrollArea::vertical().show(ui, |ui| {
let code_editor = TextEdit::multiline(&mut self.text)
.code_editor()
.desired_width(f32::INFINITY)
.desired_rows(40);
let response = code_editor.show(ui).response;
if response.changed() {
println!("total bytes now: {}", self.text.len());
}
});
let end = std::time::Instant::now();
let time_to_update = end - start;
if time_to_update.as_secs_f32() > 0.5 {
println!("Long update took {:.3}s", time_to_update.as_secs_f32())
}
});
}
}
```
</details>
I think the way to proceed would be to make a new type, something like
`PositionedRow`, that would wrap an `Arc<Row>` but have a separate `pos`
~~and `ends_with_newline`~~ (that would mean `Row` only holds a `size`
instead of a `rect`). This type would of course have getters that would
allow you to easily get a `Rect` from it and probably a `Deref` to the
underlying `Row`.
~~I haven't done this yet because I wanted to get some opinions whether
this would be an acceptable API first.~~ This is now implemented, but of
course I'm still open to discussion about this approach and whether it's
what we want to do.
Breaking changes (currently):
- The `Galley::rows` field has a different type.
- There is now a `PlacedRow` wrapper for `Row`.
- `Row` now uses a coordinate system relative to itself instead of the
`Galley`.
* Closes <https://github.com/emilk/egui/issues/3086>
* [X] I have followed the instructions in the PR template
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
Minor bug fix when transforming a `TextShape` with a `underline` (used
for e.g. hyperlinks). Before the underline width would not scale
properly; now it will.
This should prevent compilation errors (which I ran into) where eframe
tries to use HtmlElement::set_autofocus(), which doesn't exist until
0.3.73.
```
error[E0599]: no method named `set_autofocus` found for struct `HtmlElement` in the current scope
--> C:\Users\wareya\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\eframe-0.31.1\src\web\text_agent.rs:24:15
|
24 | input.set_autofocus(true)?;
| ^^^^^^^^^^^^^
|
help: there is a method `set_onfocus` with a similar name
|
24 | input.set_onfocus(true)?;
| ~~~~~~~~~~~
```
<!--
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
Might want to draw from `interaction.interact_radius` style instead of
hard-coding the margin, but I didn't want to create a breaking change.
If desired, I can follow up with a separate PR to address that concern.
* Closes <https://github.com/emilk/egui/issues/5796>
* [x] I have followed the instructions in the PR template
* [x] I have followed the instructions in the PR template
Currently eframe [calls
`prevent_default()`](962c7c7516/crates/eframe/src/web/events.rs (L307-L369))
for all copy / paste events on the
[*document*](962c7c7516/crates/eframe/src/web/events.rs (L88)),
making embedding an egui application in a page (e.g. an react
application) hard (as all copy & paste functionality for other elements
on the page is broken by this).
I'm not sure what the motivation for this is, if any.
This commit / PR adds a callback (`should_prevent_default`), similar to
`should_propgate_event`, that an egui application can use to overwrite
this behavior. It defaults to returning `true` for all events, to keep
the existing behavior.
I call `should_prevent_default` in every place that
`should_propagate_event` is called (which is not all places that
`prevent_default` is called!). I'm not sure for the motivation of not
calling `should_propagate_event` everywhere that `stop_propagation` is
called, but I kept that behavior for the `should_prevent_default`
callback too.
Please let me know if I'm missing some existing functionality that would
allow me to do this, or if there's a reason that we don't want
applications to be able to customize this (i.e. if there's a reason to
always `prevent_default` for all copy / paste events on the whole
document)
* related to #5832
(I want to keep that open and actually update the button to use the new
popup, but this should be enough to fix it for now)
* [X] I have followed the instructions in the PR template
lien -> line
<!--
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/THE_RELEVANT_ISSUE>
* [ x ] I have followed the instructions in the PR template
<!--
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
# Overview
This is a small change that supports draggable elements inside a
`Scene`.
When a Scene is initialized with a `Rect::Zero`, following the [example
in the
demo](https://github.com/emilk/egui/blob/master/crates/egui_demo_lib/src/demo/scene.rs#L15),
it will [automatically be reset to the `inner_rect` of the
UI](https://github.com/emilk/egui/blob/master/crates/egui/src/containers/scene.rs#L120-L123).
This centers the scene on the inner-rect contents, however the resulting
`scene_rect` doesn't fill the entire `outer_rect`. This probably isn't
an issue for most users of `Scene`.
However, I want to support draggable elements on a `Scene`, and to do
that I need to map the pointer-position in the window to the scene_rect
position.
As is, the example of draggable elements on Scene works after the user
has modified the scene rect in some way (zoom or pan), when `scene_rect`
is set to `to_global.inverse() * outer_rect`
([here](https://github.com/emilk/egui/blob/master/crates/egui/src/containers/scene.rs#L114-L118)).
Before a user modifies the scene rect, the pointer-position cannot be
reliably mapped to the scene_rect, since the scene_rect doesn't span the
entire window.
This PR just forces that translation to always run after the scene_rect
is reset to `inner_rect`. The practical result is that the scene_rect
will now always span the full outer_rect.
# Example
Here's a small app that demonstrates the functionality I'm trying to
support. I'm new to Egui so there may be better patterns for what I'm
trying to do, but if you run this against `main` and this branch you'll
notice the difference.
```rs
use eframe::egui::*;
/// Map coordinates from the src rect to the target rect
fn map_to_rect(position: Pos2, src_rect: Rect, dest_rect: Rect) -> Pos2 {
let x = (position.x - src_rect.min.x) / (src_rect.max.x - src_rect.min.x)
* (dest_rect.max.x - dest_rect.min.x)
+ dest_rect.min.x;
let y = (position.y - src_rect.min.y) / (src_rect.max.y - src_rect.min.y)
* (dest_rect.max.y - dest_rect.min.y)
+ dest_rect.min.y;
Pos2::new(x, y)
}
pub fn draggable_scene_element(
ui: &mut Ui,
id: Id,
position: &mut Rect,
scene_rect: Rect,
container_rect: Rect,
) -> Response {
let is_being_dragged = ui.ctx().is_being_dragged(id);
if is_being_dragged {
let r = ui.put(*position, |ui: &mut Ui| ui.label("Draggable"));
if let Some(pointer_pos) = ui.ctx().pointer_interact_pos() {
let pointer_pos = map_to_rect(pointer_pos, container_rect, scene_rect);
let delta = pointer_pos.to_vec2() - position.center().to_vec2();
*position = position.translate(delta);
};
r
} else {
let r = ui.put(*position, |ui: &mut Ui| ui.label("Draggable"));
ui
.interact(position.clone(), id, Sense::drag())
.on_hover_cursor(CursorIcon::Grab);
r
}
}
struct MyApp {
scene_rect: Rect,
position: Rect,
}
impl MyApp {
fn new() -> Self {
Self {
scene_rect: Rect::ZERO,
position: Rect::from_min_size(Pos2::new(-50., -50.), Vec2::new(100., 100.)),
}
}
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) {
CentralPanel::default().show(ctx, |ui| {
let scene_rect = self.scene_rect.clone();
let container_rect = ui.min_rect();
Scene::default().show(ui, &mut self.scene_rect, |ui| {
ui.put(
Rect::from_min_size(Pos2::new(100., 200.), Vec2::new(100., 100.)),
|ui: &mut Ui| ui.label("static element"),
);
ui.put(self.position, |ui: &mut Ui| {
draggable_scene_element(
ui,
Id::from("demo"),
&mut self.position,
scene_rect,
container_rect,
)
});
});
});
}
}
```
# Summary
I need a way to map pointer coordinates to scene coordinates, in order
to support draggable elements in a scene. This patch makes that easier
by ensuring the scene_rect will always be the full size of the
outer_rect.
If you have a better way to accomplish what I'm after, I'm happy to
close this. Thanks!
This is the same change as in #4069 but as this is stale I wanted to
reopen a non stale PR
Modifies ImageLoader's load function to use background threads for the
image decoding work. This avoids blocking the main thread that is
especially noticeable when loading many images at once.
This was modelled after the other loader implementations that also use
threads.
* Closes <https://github.com/emilk/egui/issues/5375>
* [x] I have followed the instructions in the PR template
---------
Co-authored-by: lucasmerlin <lucasmeurer96@gmail.com>
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>