This makes the sizing pass of an `egui_table` ensure the table uses as
little width as possible.
Subsequently, it will redistribute all non-resizable columns on the
available space, so that a table better follow the parent container as
it is resized.
I also added `table.reset()` for forgetting the current column widths.
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`.
When the layers are reordered at the end of the frame, the sublayers are
placed directly above their respective parents. This allows having Areas
inside Windows, e.g., for the pan-zoom container.
* Closes <https://github.com/emilk/egui/issues/4128>
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This adds most of the "standard" easing functions from
https://easings.net/ to `emath::easing`, and adds helpers in `egui` for
using them.
In particular there is now `ctx.animate_bool_with_easing` and
`ctx.animate_bool_responsive`, that uses a cubic easing function.
All animations in egui now uses cubic ease-out, for a more responsive
feeling (fast at the start, slower towards the end).
You can now set custom tags on the `UiStack`. This allows you to write
code that is situationally aware at runtime. For instance, you could
decide wether or not a label should truncate its text depending on what
part of your ui it is in, without having to pass that info down via the
callstack.
These were confusing, because `set_enabled(true)` and
`set_visible(true)` did nothing.
Instead use one of:
* `ui.add_enabled`, `ui.add_enabled_ui` or `ui.disable()`
* `ui.add_visible`, `ui.add_visible_ui` or `ui.set_invisible()`
* Closes https://github.com/emilk/egui/issues/4327
* 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 https://github.com/emilk/egui/issues/1010
### In short
You can now put interactive widgets, like buttons and hyperlinks, in an
tooltip using `on_hover_ui`. If you do, the tooltip will stay open as
long as the user hovers it.
There is a new demo for this in the egui demo app (egui.rs):

### Design
Tooltips can now contain interactive widgets, such as buttons and links.
If they do, they will stay open when the user moves their pointer over
them.
Widgets that do not contain interactive widgets disappear as soon as you
no longer hover the underlying widget, just like before. This is so that
they won't annoy the user.
To ensure not all tooltips with text in them are considered interactive,
`selectable_labels` is `false` for tooltips contents by default. If you
want selectable text in tooltips, either change the `selectable_labels`
setting, or use `Label::selectable`.
```rs
ui.label("Hover me").on_hover_ui(|ui| {
ui.style_mut().interaction.selectable_labels = true;
ui.label("This text can be selected.");
ui.add(egui::Label::new("This too.").selectable(true));
});
```
### Changes
* Layers in `Order::Tooltip` can now be interacted with
All `Area`s now have a quick fade-in animation. You can turn it off with
`Area::fade_in` or `Window::fade_in` .
The `Window` fade-out animation is now nicer: it fades all elements of
the window, not just the frame.
It can be controlled with `Window::fade_out`.
* Part of https://github.com/emilk/egui/issues/4535
* Closes https://github.com/emilk/egui/issues/3974
This adds a special `sizing_pass` mode to `Ui`, in which we have no
centered or justified layouts, and everything is hidden. This is used by
`Area` to use the first frame to measure the size of its contents so
that it can then set the perfectly correct size the subsequent frames.
For menus, where buttons are justified (span the full width), this
finally the problem of auto-sizing. Before you would have to pick a
width manually, and all buttons would expand to that width. If it was
too wide, it looked weird. If it was too narrow, text would wrap. Now
all menus are exactly the width they need to be. By default menus will
wrap at `Spacing::menu_width`.
This affects all situations when you have something that should be as
small as possible, but still span the full width/height of the parent.
For instance: the `egui::Separator` widget now checks the
`ui.is_sizing_pass` flag before deciding on a size. In the sizing pass a
horizontal separator is always 0 wide, and only in subsequent passes
will it span the full width.
* 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 cranky`.
* 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 introduces the boolean field force_current_scroll_area to
InputState which will be set when scroll_with_delta is called, causing
the ScrollArea to skip the check whether it is focused and always
consume the smooth scroll delta.
* Closes#2783
* Related to #4295
---------
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 cranky`.
* 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!
-->
I had to make a couple types not Copy because closures, but it should'nt
be a massive deal.
I tried my best to make the API change as non breaking as possible.
Anywhere a PathStroke is used, you can just use a normal Stroke instead.
As mentioned above, the bezier paths couldn't be copy anymore, but IMO
that's a minor caveat.
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
* Closes https://github.com/emilk/egui/issues/3444
* Closes https://github.com/emilk/egui/issues/865
On a touch screen, if you press down on a widget and hold for 0.6
seconds (`MAX_CLICK_DURATION`), it will now trigger a secondary click,
i.e. `Response::secondary_clicked` will be `true`. This means you can
now open context menus on touch screens.
This is a refactor on the way to add support for opening context menus
on touch screens via press-and-hold.
This PR changes what `InputState::button_clicked` does (it was ver badly
named before), and also changes `Response::clicked_by` to no longer be
true if clicking with keyboard (i.e. a widget has keyboard focus and the
user presses Space or Enter).
* 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.
⚠️ Removes `Context::translate_layer`, replacing it with a sticky
`set_transform_layer`
Adds the capability to scale layers.
Allows interaction with scaled and transformed widgets inside
transformed layers.
I've also added a demo of how to have zooming and panning in a window
(see the video below).
This probably closes#1811. Having a panning and zooming container would
just be creating a new
`Area` with a new id, and applying zooming and panning with
`ctx.transform_layer`.
I've run the github workflow scripts in my repository, so hopefully the
formatting and `cargo cranky` is satisfied.
I'm not sure if all call sites where transforms would be relevant have
been handled. This might also be missing are transforming clipping
rects, but I'm not sure where / how to accomplish that. In the demo, the
clipping rect is transformed to match, which seems to work.
https://github.com/emilk/egui/assets/70821802/77e7e743-cdfe-402f-86e3-7744b3ee7b0f
---------
Co-authored-by: tweoss <fchua@puffer5.stanford.edu>
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>