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.
* 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.
This PR corrects the deprecation note on ComboBox::from_id_source:
Changed:
`#[deprecated = "Renamed id_salt"]`
To:
`#[deprecated = "Renamed from_id_salt"]`
With kittest it was difficult to wait for images to be loaded before
taking a snapshot test.
This PR adds `Harness::with_wait_for_pending_images` (true by default)
which will cause `Harness::run` to sleep until all images are loaded (or
`HarnessBuilder::with_max_steps` is exceeded).
It also adds a new ImageLoader::has_pending and
BytesLoader::has_pending, which should be implemented if things are
loaded / decoded asynchronously.
It reverts https://github.com/emilk/egui/pull/6901 which was my previous
attempt to fix this (but this didn't work since only the tested crate is
compiled with cfg(test) and not it's dependencies)
* 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.
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>
* 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!
Enabled the `missing_assert_message` lint
* [x] I have followed the instructions in the PR template
---------
Co-authored-by: Lucas Meurer <lucasmeurer96@gmail.com>
This removes the `expand(1.0)` on text background colors, since it makes
translucent background colors have bad looking bleeding.
There is probably a smarter solution than disabling the highlighting
entirely, but I don't see a way to do that while keeping the area
consumed consistent between translucent/solid colors, or adding a decent
step up in complexity.
Since this makes it impossible to tell if selected text is highlighted,
this also adds a blanket `0.5` gamma multiply to the text selection
background color. If that is undesirable because it's a bad arbitrary
number choice, or if it's too much of an unexpected change and just the
default values should be changed, please let me know.
These changes cause the tests that use screenshots with highlighted text
to fail, though I am not sure how to update those tests to match the
changes.
<details>
<summary>Comparison Images</summary>
Current:

After changes:

</details>
<details>
<summary>Code used to make comparison images</summary>
```rs
fn color_text_format(ui: &Ui, color: Color32) -> TextFormat {
TextFormat { font_id: FontId::monospace(ui.text_style_height(&egui::TextStyle::Monospace)), background: color, ..Default::default() }
}
fn color_sequence_galley(ui: &Ui, text: &str, colors: [Color32; 3]) -> Arc<Galley> {
let mut layout_job = LayoutJob::default();
for color in colors {
layout_job.append(text, 0.0, color_text_format(ui, color));
}
ui.fonts(|f| f.layout_job(layout_job))
}
fn color_sequence_row(ui: &mut Ui, label_text: &str, text: &str, colors: [Color32; 3]) {
ui.label(label_text);
ui.label(color_sequence_galley(ui, text, colors));
ui.end_row();
}
egui::Grid::new("comparison display").show(ui, |ui| {
ui.ctx().set_pixels_per_point(2.0);
let transparent = Color32::TRANSPARENT;
let solid = Color32::RED;
let solid_2 = Color32::GREEN;
let translucent_1 = Color32::GRAY.gamma_multiply(0.5);
let translucent_2 = Color32::GREEN.gamma_multiply(0.5);
color_sequence_row(ui, "Transparent to Solid:", " ", [transparent, solid, transparent]);
color_sequence_row(ui, "Translucent to Transparent:", " ", [transparent, translucent_1, transparent]);
color_sequence_row(ui, "Solid to Transparent:", " ", [solid, solid_2, solid]);
color_sequence_row(ui, "Solid to Solid:", " ", [solid, transparent, solid]);
color_sequence_row(ui, "Solid to Translucent:", " ", [solid, translucent_1, solid]);
color_sequence_row(ui, "Translucent to Translucent:", " ", [translucent_1, translucent_2, translucent_1]);
color_sequence_row(ui, "Transparent to Solid:", "a", [transparent, solid, transparent]);
color_sequence_row(ui, "Translucent to Transparent:", "a", [transparent, translucent_1, transparent]);
color_sequence_row(ui, "Solid to Transparent:", "a", [solid, solid_2, solid]);
color_sequence_row(ui, "Solid to Solid:", "a", [solid, transparent, solid]);
color_sequence_row(ui, "Solid to Translucent:", "a", [solid, translucent_1, solid]);
color_sequence_row(ui, "Translucent to Translucent:", "a", [translucent_1, translucent_2, translucent_1]);
})
```
</details>
* [x] I have followed the instructions in the PR template
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
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>
Add an option called `movable_by_window_background` alongside a new
builder method. When set to true, the window is movable by dragging its
background ([Apple
Docs](https://developer.apple.com/documentation/appkit/nswindow/ismovablebywindowbackground))
This is exclusive to macOS systems, similar to `fullsize_content_view`.
* [x] I have followed the instructions in the PR template
Breaking changes:
- When using the Memory::popup state, it's now required to call
keep_popup_open each frame or the popup will close.
- Usually handled by the `Popup` struct, but required for custom popups
using the state in `Memory` directly
-----
If a popup is abandoned `Memory::popup` would remain `Some`. This is
problematic if, for example, you have logic that checks
`is_any_popup_open`.
This PR adds a new requirement for popups keeping their open state in
`Memory::popup`. They must call `Memory::keep_popup_open` as long as
they are being rendered. The recent changes in #5716 make this easy to
implement.
Supersedes #4697 which had an awkward implementation
These two videos show a case where a context menu was open when the
underlying widget got removed.
Before (`any_popup_open` remains `true`)

After

* Closes https://github.com/emilk/egui/issues/3657
* [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!
-->
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
<!--
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.
<!--
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/5507
* [x] I have followed the instructions in the PR template
* [x] I have followed the instructions in the PR template
This PR fixes an issue, where `DragValue` would expand when it enters
editing state. There were 3 contributing problems:
- A workaround introduced in #4276 caused the `DragValue` to report
incorrect outer size.
- The `DragValue` uses `TextEdit` internally and sets both `min_size`
and `desired_width` to the same value - desired width is used **before**
padding is applied - this is in contrast to `Button` (also used
internally by `DragValue`), which only uses `min_size`. This caused the
`DragValue` to expand horizontally by the size of button padding.
- The height of the `TextEdit` is (among other things) determined by the
height of the row, which was not present in `Button`. This caused a
small vertical expansion, when the contents (including padding) were
larger than the `min_size`.

Here the dimensions set in code are:
- padding: 20 x 20 pt
- interact size: 80 x 30 pt
*Note: I do not know what's up with the tests. When I ran the check
script, they were failing because of 3 UI missmatches, so I updated the
snapshots. Now, the updated snapshots cause the same failure in CI, that
appeared locally before the update. Now the locally run tests fail with
`The platform you're compiling for is not supported by winit` and couple
more following errors coming from the same source (`winit 0.30.7`).*
Fixes kinetic scrolling on android (and possibly other touch devices),
by calculating the final velocity before clearing the position history
on PointerGone events.
* Closes#5311
* [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!
-->
Menus currently have their own style that removes outlines and
backgrounds. This is nice if the menu only contains buttons. However if
the menu contains other widgets, e.g. a drag value, the style change
makes it quite difficult to identify such widgets. This is a simple way
to make this configurable.
* [x] I have followed the instructions in the PR template
* Closes https://github.com/emilk/egui/issues/5789
* [x] I have followed the instructions in the PR template
While this change fixes the TextEdit specific issue, I'm worried that
the underlying problem is more fundamental and could show up in other
widgets, and I'm wondering if there's a more general solution?