This pull request modifies the `BytesLoader` implementation for
`FileLoader` in `crates/egui_extras/src/loaders/file_loader.rs` to
improve thread safety and handle unexpected states more gracefully.
### Changes to thread safety and state handling:
* Updated the cache logic to check if the `uri` exists in the cache
before inserting the result. If the `uri` is not found, a log message is
added to indicate the loading was canceled. This change prevents
overwriting cache entries unexpectedly.
* Closes <https://github.com/emilk/egui/issues/6755>
* [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/main/CONTRIBUTING.md)
before opening a Pull Request!
* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to test and add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.
Please be patient! I will review your PR, but my time is limited!
-->
* Closes <https://github.com/emilk/egui/issues/3964>
* [X] I have followed the instructions in the PR template
This PR adds support for syntax highlighting with custom
`syntect::parsing::SyntaxSet` and `syntect::highlighting::ThemeSet`. It
adds a new `egui_extras::highlight_with` function (enabled with `feature
= "syntect"`), which takes a new public`struct SyntectSettings`
containing the syntax and theme sets.
```rust
let mut builder = SyntaxSetBuilder::new();
builder.add_from_folder("syntax", true).unwrap();
let ps = builder.build();
let ts = syntect::highlighting::ThemeSet::load_defaults();
let syntax =
egui_extras::syntax_highlighting::SyntectSettings { ps, ts };
// ...elsewhere
egui_extras::syntax_highlighting::highlight_with(
ui.ctx(),
ui.style(),
&theme,
buf,
"rhai",
&syntax,
);
```
There's a little bit of architectural complexity, but it all emerges
naturally from the problem's constraints.
Previously, the `Highlighter` both contained the `syntect` settings
_and_ implemented `egui::cache::ComputerMut` to highlight a string; the
settings would never change. After this change, the `syntect` settings
have become part of the cache key, so we should redo highlighting if
they change. The `Highlighter` becomes an empty `struct` which just
serves to implement `ComputerMut`.
`SyntaxSet` and `ThemeSet` are not hasheable themselves, so can't be
used as cache keys direction. Instead, we can use the *address* of the
`&SyntectSettings` as the key. This requires an object with a custom
`Hash` implementation, so I added a new `HighlightSettings(&'a
SyntectSettings)`, implementing `Hash` using `std::ptr::hash` on the
reference. I think using the address is reasonable – it would be _weird_
for a user to be constantly moving around their `SyntectSettings`, and
there's a warning in the docstring to this effect.
To work _without_ custom settings, `SyntectSettings::default` preserves
the same behavior as before, using `SyntaxSet::load_defaults_newlines`
and `ThemeSet::load_defaults`. If the user doesn't provide custom
settings, then we instantiate a singleton `SyntectSettings` in `data`
and use it; this will only be constructed once.
Finally, in cases where the `syntect` feature is disabled,
`SyntectSettings` are replaced with a unit `()`. This adds a _tiny_
amount of overhead – one singleton `Arc<()>` allocation and a lookup in
`data` per `highlight` – but I think that's better than dramatically
different implementations. If this is an issue, I can refactor to make
it zero-cost when the feature is disabled.
Using physical window sizes leads to all kinds of fun stuff: winit
always uses scale factor 1.0 on start to convert it back to logical
pixels and uses these logical pixels to set min/max size for
non-resizeable windows. You're supposed to adjust size after getting a
scale change event if you're using physical sizes, but adjusting min/max
sizes doesn't seem to work on sway, so the window is stuck with an
incorrect size.
The scale factor we guessed might also be wrong even if there's only a
single display since it doesn't take fractional scale into account.
TL;DR: winit actually wants logical sizes in these methods (since
Wayland in general operates mostly on logical sizes) and converting them
back and forth is lossy.
<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/main/CONTRIBUTING.md)
before opening a Pull Request!
* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to test and add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.
Please be patient! I will review your PR, but my time is limited!
-->
* Closes https://github.com/emilk/egui/issues/7095
* [x] I have followed the instructions in the PR template
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
The color picker popup is now aligned to the bottom left edge (instead
of the bottom right), but I think this makes more sense and is aligned
with ComboBox etc. It also gets the new nice auto positioning.
* closes#5832
* [x] I have followed the instructions in the PR template
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
Add the ability to set the `DatePickerButton`'s start and end years via
new `start_year` and `end_year` methods.
Continue to use the existing today - 100 years and today + 10 years
behavior if a year is not specified.
* This more fully closes <https://github.com/emilk/egui/issues/3597> and
expands on <https://github.com/emilk/egui/pull/3599>.
* [x] I have followed the instructions in the PR template
Closes#7077.
This fixes the problem shown in #7077 where clearing a `TextEdit`
wouldn't reset its cursor position. I've fixed that by adding back the
`TextCursorState::range` method, which clamps the selection range to
that of the passed `Galley`, and calling it in the same places where it
was called before #5785.
(/cc @juancampa)
* [x] I have followed the instructions in the PR template
This pull request introduces a change to the `Hsva` struct in the
`crates/ecolor/src/hsva.rs` file to enable serialization and
deserialization when the `serde` feature is enabled.
* Closes <https://github.com/emilk/egui/issues/7131>
* [x] I have followed the instructions in the PR template
When your press a Back button on Android (for example at
`native-activity`), [Winit translates this
key](47b938dbe7/src/platform_impl/android/keycodes.rs (L237C42-L237C53))
as `NamedKey::BrowserBack`. Added convertion to `Key::Escape` at
`egui-winit` module.
---------
Co-authored-by: Advocat <advocat@ogr.local>
Usually input events automatically trigger a repaint. But since
consume_key would remove the event egui would think there were no events
and not trigger a repaint. This fixes it by setting a flag on InputState
on consume_key.
* related: https://github.com/rerun-io/rerun/issues/10165
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).
Improves the `ComboBox` example with some code that shows how to handle
changes in the `ComboBox`’s selection. The approach is based on the
advice given in https://github.com/emilk/egui/discussions/923 . I hope
this saves future me (and hopefully others) a web search for how to do
this.
* [x] I have followed the instructions in the PR template
* Closes https://github.com/emilk/egui/issues/7120
You can now zoom only the X axis by holding down shift, and zoom only
the Y axis by holding down ALT.
In summary
* `Shift`: horizontal
* `Alt`: vertical
* `Ctrl`: zoom (`Cmd` on Mac)
Thus follows:
* `scroll`: pan both axis (at least for trackpads and mice with two-axis
scroll)
* `Shift + scroll`: pan only horizontal axis
* `Alt + scroll`: pan only vertical axis
* `Ctrl + scroll`: zoom all axes
* `Ctrl + Shift + scroll`: zoom only horizontal axis
* `Ctrl + Alt + scroll`: zoom only vertical axis
This is provided the application uses `zoom_delta_2d` for its zooming
needs.
The modifiers are exposed in `InputOptions`, but it is strongly
recommended that you do not change them.
## Testing
Unfortunately we have no nice way of testing this in egui.
But I've tested it in `egui_plot`.
<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/main/CONTRIBUTING.md)
before opening a Pull Request!
* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to test and add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.
Please be patient! I will review your PR, but my time is limited!
-->