Fixes manually created popups (via `Popup::new`) not closing, since
widget_clicked_elsewhere was always false.
This example would never close:
```rs
let mut open = true;
eframe::run_simple_native("My egui App", options, move |ctx, _frame| {
egui::CentralPanel::default().show(ctx, |ui| {
let response = egui::Popup::new(
Id::new("popup"),
ctx.clone(),
PopupAnchor::Position(Pos2::new(10.0, 10.0)),
LayerId::new(Order::Foreground, Id::new("popup")),
)
.open(open)
.show(|ui| {
ui.label("This is a popup!");
ui.label("You can put anything in here.");
});
if let Some(response) = response {
if response.response.should_close() {
open = false;
}
}
});
})
```
I also noticed that the Color submenu in the popups example had a double
arrow (must have been broken in the atoms PR):
<img width="248" height="110" alt="Screenshot 2025-08-07 at 13 42 28"
src="https://github.com/user-attachments/assets/a4e0c267-ae71-4b2c-a1f0-f53f9662d026"
/>
Also fixed this in the PR.
* Closes #7037
* Closes#7297
This deprecates all popup-related function in `Memory`, replacing them
with the new `egui::Popup`.
The new API is nicer in all ways, so we should encourage people to use
it.
* [x] I have followed the instructions in the PR template
Splitting this out from the Parley work as requested. This removes
`FontImage` and makes the font atlas use a `ColorImage`. It converts
alpha to coverage at glyph-drawing time, not at delta-upload time.
This doesn't do much now, but will allow for color emoji rendering once
we start using Parley.
I've changed things around so that we pass in `text_alpha_to_coverage`
to the `Fonts` the same way we do with `pixels_per_point` and
`max_texture_side`, reusing the existing code to check if the setting
differs and recreating the font atlas if so. I'm not quite sure why this
wasn't done in the first place.
I've left `ImageData` as an enum for now, in case we want to add support
for more texture pixel formats in the future (which I personally think
would be worthwhile). If you'd like, I can just remove that enum
entirely.
* part of https://github.com/emilk/egui/issues/7264
* removes SelectableLabel (Use `Button::selectable` instead)
* updates `Ui::selectable_value/label` with IntoAtoms support
Had to make some changes to `Button` since the SelecatbleLabel had no
frame unless selected.
I thought about this - so we have two options here:
1. adding it to `SnapshotOptions`
2. adding it to every function which I do not like as this would be a
huge breaking change
## Summary
This pull request introduces a new feature to the `SnapshotOptions`
struct in the `egui_kittest` crate, allowing users to specify a
permissible percentage of pixel differences (`diff_percentage`) before a
snapshot comparison is considered a failure. This feature provides more
flexibility in handling minor visual discrepancies during snapshot
testing.
### Additions to `SnapshotOptions`:
* Added a new field `diff_percentage` of type `Option<f64>` to the
`SnapshotOptions` struct. This field allows users to define a tolerance
for pixel differences, with a default value of `None` (interpreted as 0%
tolerance).
* Updated the `Default` implementation of `SnapshotOptions` to
initialize `diff_percentage` to `None`.
### Integration into snapshot comparison logic:
* Updated the `try_image_snapshot_options` function to handle the new
`diff_percentage` field. If a `diff_percentage` is specified, the
function calculates the percentage of differing pixels and allows the
snapshot to pass if the difference is within the specified tolerance.
[[1]](diffhunk://#diff-6f481b5866b82a4fe126b7df2e6c9669040c79d1d200d76b87f376de5dec5065R204)
[[2]](diffhunk://#diff-6f481b5866b82a4fe126b7df2e6c9669040c79d1d200d76b87f376de5dec5065R294-R301)
* Closes <https://github.com/emilk/egui/issues/5683>
* [x] I have followed the instructions in the PR template
---------
Co-authored-by: lucasmerlin <hi@lucasmerlin.me>
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This adds a custom Node struct with proper support for egui types
(`Key`, `Modifiers`, `egui::Event`, `Rect`) instead of needing to use
the kittest / accesskit types.
I also changed the `click` function to do a proper mouse move / mouse
down instead of the accesskit click. Also added `accesskit_click` to
trigger the accesskit event. This resulted in some changed snapshots,
since the elements are now hovered.
Also renamed `press_key` to `key_press` for consistency with
`key_down/key_up`.
Also removed the Deref to the AccessKit Node, to make it clearer when to
expect egui and when to expect accesskit types.
* Closes#5705
* [x] I have followed the instructions in the PR template
Today each widget does its own custom layout, which has some drawbacks:
- not very flexible
- you can add an `Image` to `Button` but it will always be shown on the
left side
- you can't add a `Image` to a e.g. a `SelectableLabel`
- a lot of duplicated code
This PR introduces `Atoms` and `AtomLayout` which abstracts over "widget
content" and layout within widgets, so it'd be possible to add images /
text / custom rendering (for e.g. the checkbox) to any widget.
A simple custom button implementation is now as easy as this:
```rs
pub struct ALButton<'a> {
al: AtomicLayout<'a>,
}
impl<'a> ALButton<'a> {
pub fn new(content: impl IntoAtomics) -> Self {
Self { al: content.into_atomics() }
}
}
impl<'a> Widget for ALButton<'a> {
fn ui(mut self, ui: &mut Ui) -> Response {
let response = ui.ctx().read_response(ui.next_auto_id());
let visuals = response.map_or(&ui.style().visuals.widgets.inactive, |response| {
ui.style().interact(&response)
});
self.al.frame = self
.al
.frame
.inner_margin(ui.style().spacing.button_padding)
.fill(visuals.bg_fill)
.stroke(visuals.bg_stroke)
.corner_radius(visuals.corner_radius);
self.al.show(ui)
}
}
```
The initial implementation only does very basic layout, just enough to
be able to implement most current egui widgets, so:
- only horizontal layout
- everything is centered
- a single item may grow/shrink based on the available space
- everything can be contained in a Frame
There is a trait `IntoAtoms` that conveniently allows you to construct
`Atoms` from a tuple
```
ui.button((Image::new("image.png"), "Click me!"))
```
to get a button with image and text.
This PR reimplements three egui widgets based on the new AtomLayout:
- Button
- matches the old button pixel-by-pixel
- Button with image is now [properly
aligned](https://github.com/emilk/egui/pull/5830/files#diff-962ce2c68ab50724b01c6b64c683c4067edd9b79fcdcb39a6071021e33ebe772)
in justified layouts
- selected button style now matches SelecatbleLabel look
- For some reason the DragValue text seems shifted by a pixel almost
everywhere, but I think it's more centered now, yay?
- Checkbox
- basically pixel-perfect but apparently the check mesh is very slightly
different so I had to update the snapshot
- somehow needs a bit more space in some snapshot tests?
- RadioButton
- pixel-perfect
- somehow needs a bit more space in some snapshot tests?
I plan on updating TextEdit based on AtomLayout in a separate PR (so
you could use it to add a icon within the textedit frame).
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 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.
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>
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>
<!--
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>
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>
<!--
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.
Continuation of #5713
**Silently breaking changes:**
- Menus now close on click by default, this is configurable via
`PopupCloseBehavior`
**Additional additions:**
- `Button::right_text`
- `StyleModifier`
This is a rewrite of the egui menus, with the following goals:
- submenu buttons should work everywhere, in a popup, context menu,
area, in some random Ui
- remove the menu state from Ui
- should work just like the previous menu
- ~proper support for keyboard navigation~
- It's better now but requires further work to be perfect
- support `PopupCloseBehavior`
* Closes#4607
* [x] I have followed the instructions in the PR template
This PR reverts a change introduced in PR
https://github.com/emilk/egui/pull/3660 that caused a regression with
`TextEdit::singleline`. The original PR attempted to fix an issue with
the cursor in `TextEdit` inside `ScrollArea`, but it did so by adding
unnecessary size allocation to `TextEdit`, which breaks the layout when
`TextEdit::singleline` is used outside of `ScrollArea`.

The regression introduced by #3660 is more severe, as it completely
breaks the layout of applications using `TextEdit::singleline`, as shown
in the following issues:
* Closes https://github.com/emilk/egui/issues/5500
* Closes https://github.com/emilk/egui/issues/5597
Furthermore, I was unable to reproduce the original bug from PR #3660 in
the current version of egui using the following code:
```rust
impl eframe::App for MyEguiApp {
fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
ctx.set_debug_on_hover(true);
egui::CentralPanel::default().show(ctx, |ui| {
ScrollArea::vertical().max_height(100.0).show(ui, |ui| {
ui.add(TextEdit::multiline(&mut self.text).hint_text("Enter text here..."))
});
});
}
}
```
This code attempts to recreate the layout shown in the video from PR
#3660, using a `ScrollArea` with limited height and a `TextEdit` inside.
However, the cursor hiding issue was not reproducible.

Therefore, I believe the code added in PR #3660 is no longer necessary
and only creates more problems.
* Closes https://github.com/emilk/egui/issues/5500
* Closes https://github.com/emilk/egui/issues/5597
* [x] I have followed the instructions in the PR template
This adds a generic way of telling containers to close from their child
`Ui`s.
* Part of #5727
* [x] I have followed the instructions in the PR template
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This introduces new `Tooltip` and `Popup` structs that unify and extend
the old popups and tooltips.
`Popup` handles the positioning and optionally stores state on whether
the popup is open (for click based popups like `ComboBox`, menus,
context menus).
`Tooltip` is based on `Popup` and handles state of whether the tooltip
should be shown (which turns out to be quite complex to handles all the
edge cases).
Both `Popup` and `Tooltip` can easily be constructed from a `Response`
and then customized via builder methods.
This also introduces `PositionAlign`, for aligning something outside of
a `Rect` (in contrast to `Align2` for aligning inside a `Rect`). But I
don't like the name, any suggestions? Inspired by [mui's tooltip
positioning](https://mui.com/material-ui/react-tooltip/#positioned-tooltips).
* Part of #4607
* [x] I have followed the instructions in the PR template
TODOs:
- [x] Automatic tooltip positioning based on available space
- [x] Review / fix / remove all code TODOs
- [x] ~Update the helper fns on `Response` to be consistent in naming
and parameters (Some use tooltip, some hover_ui, some take &self, some
take self)~ actually, I think the naming and parameter make sense on
second thought
- [x] Make sure all old code is marked deprecated
For discussion during review:
- the following check in `show_tooltip_for` still necessary?:
```rust
let is_touch_screen = ctx.input(|i| i.any_touches());
let allow_placing_below = !is_touch_screen; // There is a finger below. TODO: Needed?
```