Marking widgets as disabled was not reflected in the accesskit output,
now the disabled status should match.
---------
Co-authored-by: Wybe Westra <w.westra@kwantcontrols.nl>
The default `Plot` formatter now picks precision intelligently based on
zoom level. The width of the Y axis are is now much smaller by default,
and expands as needed.
Also deprecates `Plot::y_axis_with`; replaced with `y_axis_min_width`.
<!--
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 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!
-->
Can fix translating with high zoom out
https://github.com/emilk/egui/issues/3462
* Maybe related to https://github.com/emilk/egui/issues/3656
* Fixes#3808
* Fixes#2307
This PR improves the behaviour of auto-bounds with data that:
- is a single point
- where all X values are the same (e.g. vertical line)
- where all Y values are the same (e.g. horizontal line)
In all case, the auto-bound now aim to center on the data. For span,
when available, it use the same as the other axis. If the data range of
the other axis is also degenerate, then it defaults to +/- 1.0.
https://github.com/emilk/egui/assets/49431240/a62d2b5b-7856-4415-8534-83dc58cfac98
<details>
<summary>Test code</summary>
```rust
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::egui;
use egui_plot::{Legend, Line, Plot, PlotPoints, Points};
fn main() -> Result<(), eframe::Error> {
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default().with_inner_size([350.0, 200.0]),
..Default::default()
};
eframe::run_native(
"My egui App with a plot",
options,
Box::new(|_cc| Ok(Box::<MyApp>::default())),
)
}
#[derive(Default)]
struct MyApp {}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
let mut plot_rect = None;
egui::CentralPanel::default().show(ctx, |ui| {
if ui.button("Save Plot").clicked() {
ctx.send_viewport_cmd(egui::ViewportCommand::Screenshot);
}
let my_plot = Plot::new("My Plot").legend(Legend::default());
// let's create a dummy line in the plot
let inner = my_plot.show(ui, |plot_ui| {
plot_ui.line(
Line::new(PlotPoints::from(vec![
[0.0, 10.0],
[2.0, 10.0],
[3.0, 10.0],
]))
.name("y = 10.0"),
);
plot_ui.line(
Line::new(PlotPoints::from(vec![
[10.0, 10.0],
[10.0, 11.0],
[10.0, 12.0],
]))
.name("x = 10.0"),
);
plot_ui.points(
Points::new(PlotPoints::from(vec![[5.0, 5.0]]))
.name("(5,5)")
.radius(3.0),
);
plot_ui.points(
Points::new(PlotPoints::from(vec![[5.0, 7.0]]))
.name("(5,7)")
.radius(3.0),
);
});
// Remember the position of the plot
plot_rect = Some(inner.response.rect);
});
// Check for returned screenshot:
let screenshot = ctx.input(|i| {
for event in &i.raw.events {
if let egui::Event::Screenshot { image, .. } = event {
return Some(image.clone());
}
}
None
});
if let (Some(screenshot), Some(plot_location)) = (screenshot, plot_rect) {
if let Some(mut path) = rfd::FileDialog::new().save_file() {
path.set_extension("png");
// for a full size application, we should put this in a different thread,
// so that the GUI doesn't lag during saving
let pixels_per_point = ctx.pixels_per_point();
let plot = screenshot.region(&plot_location, Some(pixels_per_point));
// save the plot to png
image::save_buffer(
&path,
plot.as_raw(),
plot.width() as u32,
plot.height() as u32,
image::ColorType::Rgba8,
)
.unwrap();
eprintln!("Image saved to {path:?}.");
}
}
}
}
```
</details>
* Closes#4534
This PR:
- Introduces `Ui::stack()`, which returns the `UiStack` structure
providing information on the current `Ui` hierarchy.
- **BREAKING**: `Ui::new()` now takes a `UiStackInfo` argument, which is
used to populate some of this `Ui`'s `UiStack`'s fields.
- **BREAKING**: `Ui::child_ui()` and `Ui::child_ui_with_id_source()` now
take an `Option<UiStackInfo>` argument, which is used to populate some
of the children `Ui`'s `UiStack`'s fields.
- New `Area::kind()` builder function, to set the `UiStackKind` value of
the `Area`'s `Ui`.
- Adds a (minimalistic) demo to egui demo (in the "Misc Demos" window).
- Adds a more thorough `test_ui_stack` test/playground demo.
TODO:
- [x] benchmarks
- [x] add example to demo
Future work:
- Add `UiStackKind` and related support for more container (e.g.
`CollapsingHeader`, etc.)
- Add a tag/property system that would allow adding arbitrary data to a
stack node. This data could then be queried by nested `Ui`s. Probably
needed for #3284.
- Add support to track columnar layouts.
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
* Closes#4473
This PR introduce `Style::wrap_mode`, which adds support for text
truncation in addition to text wrapping. This PR also update some width
calculation of the ComboBox.
#### Core
- Add `egui::TextWrapMode` (pure enum with `Extend`, `Wrap`, `Truncate`)
- Add `Style::wrap_mode: Option<tTextWrapMode>`
- **DEPRECATED**: `Style::wrap`, use `Style::wrap_mode` instead.
- Add `Ui::wrap_mode()` to return the wrap mode to use in the current
ui. If specified in `Style`, return it. Otherwise, return
`TextWrapMode::Wrap` for vertical layout and wrapping horizontal layout,
and `TextWrapMode::Extend` otherwise.
- **DEPRECATED**: `Ui::wrap_text()`, use `Ui::wrap_mode` instead.
#### Widget
- Update the width calculation of the `ComboBox` button (_not_ its popup
menu).
- Now, `ComboBox::width()` (defaulting to `Spacing::combo_width`) is
always considered a minimum width and will extend the `Ui`, regardless
of the selected text width and wrap mode.
- Introduce `ComboBox::wrap_mode`, which overrides `Ui::wrap_mode` for
the selected text layout.
- Note: since `ComboBox` uses `ui.horizontal` internally, the default
wrap mode is always `TextWrapMode::Extend`, regardless of the caller's
`Ui`'s layout.
- The `ComboBox` button no longer extend to `ui.available_width()` with
wrapping is enabled.
- **BREAKING**: `ComboBox::wrap()` no longer has a `bool` argument and
is now a short-hand for `ComboBox::wrap_mode(TextWrapMode::Wrap)`.
- Added `ComboBox::truncate()` as short-hand for
`ComboBox::wrap_mode(TextWrapMode::Truncate)`.
- Update `Label`
- Add `Label::wrap_mode()` to specify the text wrap mode.
- **BREAKING**: `Label::wrap()` no longer has a `bool` argument and is
now a short-hand for `Label::wrap_mode(TextWrapMode::Wrap)`.
- **BREAKING**: `Label::truncate()` no longer has a `bool` argument and
is now a short-hand for `Label::wrap_mode(TextWrapMode::Truncate)`.
- Update `Button`
- Add `Button::wrap_mode()` to specify the text wrap mode.
- **BREAKING**: `Button::wrap()` no longer has a `bool` argument and is
now a short-hand for `Button::wrap_mode(TextWrapMode::Wrap)`.
- Added `Button::truncate()` as short-hand for
`Button::wrap_mode(TextWrapMode::Truncate)`.
#### Low-level
- **BREAKING**: `WidgetText::into_galley()` now takes an
`Option<TextWrapMode>` instead of a `Option<bool>` argument.
- **BREAKING**: `WidgetText::into_galley_impl(()` now takes a
`TextWrapping` argument instead of `wrap: bool` and `availalbe_width:
f32` arguments.
---------
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 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!
-->
Related to #3482
Not sure what the "best practice" is, to me it seems like one should
import from "the original location" if possible, but now it should at
least be possible to not re-export ahash without any breakage in the
egui code base (but possibly in projects using egui, so one should
probably deprecate it if one would like to go that path). It also seems
like epaint re-exports ahash.
* Closes https://github.com/emilk/egui/issues/4434
Shouldn't break anything, because when all arguments have a 'static
lifetime (required without this PR), the Plot is also 'static and can be
used like before.
<!--
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 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!
-->
Inspired by:
44d65f41ac/Cargo.toml (L65)
I took the liberty of removing that comment since I *think* that I got
all "relevant" ones (showing up more than once, sort of).
## Summary
This PR modifies `ScrollArea` and `Plot` to disable their interactions
when the UI is disabled.
## Changes
- Interaction with `ScrollArea` in `egui` is disabled when the UI is
disabled.
- Interaction with `Plot` in `egui_plot` is disabled when the UI is
disabled.
- These changes ensure that `ScrollArea` and `Plot` behave consistently
with the rest of the UI, preventing them from responding to user input
when the UI is in a disabled state.
## Impact
This PR enhances the consistency of `egui`'s UI behavior by ensuring
that all elements, including `ScrollArea` and `Plot`, respect the UI's
disabled state. This prevents unexpected interactions when the UI is
disabled.
Closes#4341
These two items are needed to implement the `PlotItem` trait (which is
already public) when using `PlotGeometry::Rects`.
Specifically, they are used in the return type of
`PlotItem::find_closest` and as arguments to `PlotItem::on_hover`, which
need to be implemented when using `PlotGeometry::Rects`.
Usually this isn't visible (the same label being painted on top of
itself), but it will be visible if the user has a custom formatter (e.g.
`y_axis_formatter`) that choses a different format based on
`GridMark:step_size` (e.g. using fewer decimals for thicker ticks).
This is a fix meant mostly for Rerun, where we sometiems paint a
vertical time-line over the plot (which is interactive). Before this PR
you couldn't zoom or pan the plot while hovering that line, which was
really annoying.
This is particularly interesting if you want to authorize a single hover
tooltip on an item in the event of an interaction.
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
Expose `egui_plot::items::values::PlotGeometry` in public API so that
`PlotItem`, which is already public, can actually be implemented by
applications. Fixes#3464.
---------
Co-authored-by: Dominique Würtz <dom@blaukraut.info>
* Closes https://github.com/emilk/egui/issues/3936
* Closes https://github.com/emilk/egui/issues/3923
* Closes https://github.com/emilk/egui/pull/4058
The interaction code is now done at the start of the frame, using stored
`WidgetRect`s from the previous frame.
The intention is that the new interaction code should be more accurate,
making it easier to hit widgets, and better respecting the rules of
overlapping widgets.
There is a new `style::Interaction::interact_radius` controlling how far
away from a widget the cursor can be and still hit it. This helps big
fat fingers hit small widgets on touch screens.
This PR adds a new `Context::read_response` which lets you read the
`Response` of a `Widget` _before_ you create the widget. This can be
used for styling, or for reading the result of an interaction early (to
prevent frame-delay) for a widget you add late (so it is on top of other
widgets).
# ⚠️ BREAKING CHANGES
`Memory::dragged_id`, `Memory::set_dragged_id` etc have been moved to
`Context`.
The semantics for `Context::dragged_id` is slightly different: a widget
is not considered dragged until egui it is sure this is not a
click-in-progress. For a widget that is only sensitive to drags, that is
right away, but for widgets sensitive to both clicks and drags it is not
until the mouse has moved a certain distance.
# TODO
* [x] Fix panel resizing
* [x] Fix scroll hover weirdness
* [x] Fix Resize widget
* [x] Fix drag-and-drop
* [x] Test all of egui_demo_app
* [x] Change `is_dragging` API
* [x] Consistent naming of start/stop or begin/end drag
* [x] Test `egui_tiles`
* [x] Test Rerun
* [x] Document
* [x] Document breaking changes in PR description
* [x] Test one final time
# Saving for a later PR
* [ ] Fix https://github.com/emilk/egui/issues/4047
* [ ] Specify what the response order for e.g. `ui.horizontal` is
I think both these can be fixed if each `Ui` registers themselves as a
`WidgetRect`, with the possibility to interact with it later, as if the
interaction was under all widgets on top of it.
* Closes https://github.com/emilk/egui/issues/3941
Workspace dependencies can be annoying.
If you don't set them to `default-features=false`, then you cannot opt
out of their default features anywhere else, and get warnings if you
try.
So you set `default-features=false`, and then you need to manually opt
in to the default features everywhere else.
Or, as in my case, don't.
I don't have the energy to do this tonight, so I'll just revert.