Add `Ui::close` and `Response::should_close` (#5729)
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 commit is contained in:
parent
264749b8af
commit
f5b058b908
|
|
@ -556,7 +556,8 @@ impl Prepared {
|
|||
.ui_stack_info(UiStackInfo::new(self.kind))
|
||||
.layer_id(self.layer_id)
|
||||
.max_rect(max_rect)
|
||||
.layout(self.layout);
|
||||
.layout(self.layout)
|
||||
.closable();
|
||||
|
||||
if !self.enabled {
|
||||
ui_builder = ui_builder.disabled();
|
||||
|
|
@ -611,6 +612,12 @@ impl Prepared {
|
|||
response.rect = final_rect;
|
||||
response.interact_rect = final_rect;
|
||||
|
||||
// TODO(lucasmerlin): Can the area response be based on Ui::response? Then this won't be needed
|
||||
// Bubble up the close event
|
||||
if content_ui.should_close() {
|
||||
response.set_close();
|
||||
}
|
||||
|
||||
ctx.memory_mut(|m| m.areas_mut().set_state(layer_id, state));
|
||||
|
||||
if sizing_pass {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ClosableTag {
|
||||
pub close: AtomicBool,
|
||||
}
|
||||
|
||||
impl ClosableTag {
|
||||
pub const NAME: &'static str = "egui_close_tag";
|
||||
|
||||
/// Set close to `true`
|
||||
pub fn set_close(&self) {
|
||||
self.close.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Returns `true` if [`ClosableTag::set_close`] has been called.
|
||||
pub fn should_close(&self) -> bool {
|
||||
self.close.load(std::sync::atomic::Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,8 @@ use std::hash::Hash;
|
|||
|
||||
use crate::{
|
||||
emath, epaint, pos2, remap, remap_clamp, vec2, Context, Id, InnerResponse, NumExt, Rect,
|
||||
Response, Sense, Stroke, TextStyle, TextWrapMode, Ui, Vec2, WidgetInfo, WidgetText, WidgetType,
|
||||
Response, Sense, Stroke, TextStyle, TextWrapMode, Ui, UiBuilder, UiKind, UiStackInfo, Vec2,
|
||||
WidgetInfo, WidgetText, WidgetType,
|
||||
};
|
||||
use emath::GuiRounding as _;
|
||||
use epaint::{Shape, StrokeKind};
|
||||
|
|
@ -203,11 +204,16 @@ impl CollapsingState {
|
|||
add_body: impl FnOnce(&mut Ui) -> R,
|
||||
) -> Option<InnerResponse<R>> {
|
||||
let openness = self.openness(ui.ctx());
|
||||
|
||||
let builder = UiBuilder::new()
|
||||
.ui_stack_info(UiStackInfo::new(UiKind::Collapsible))
|
||||
.closable();
|
||||
|
||||
if openness <= 0.0 {
|
||||
self.store(ui.ctx()); // we store any earlier toggling as promised in the docstring
|
||||
None
|
||||
} else if openness < 1.0 {
|
||||
Some(ui.scope(|child_ui| {
|
||||
Some(ui.scope_builder(builder, |child_ui| {
|
||||
let max_height = if self.state.open && self.state.open_height.is_none() {
|
||||
// First frame of expansion.
|
||||
// We don't know full height yet, but we will next frame.
|
||||
|
|
@ -226,6 +232,9 @@ impl CollapsingState {
|
|||
|
||||
let mut min_rect = child_ui.min_rect();
|
||||
self.state.open_height = Some(min_rect.height());
|
||||
if child_ui.should_close() {
|
||||
self.state.open = false;
|
||||
}
|
||||
self.store(child_ui.ctx()); // remember the height
|
||||
|
||||
// Pretend children took up at most `max_height` space:
|
||||
|
|
@ -234,7 +243,10 @@ impl CollapsingState {
|
|||
ret
|
||||
}))
|
||||
} else {
|
||||
let ret_response = ui.scope(add_body);
|
||||
let ret_response = ui.scope_builder(builder, add_body);
|
||||
if ret_response.response.should_close() {
|
||||
self.state.open = false;
|
||||
}
|
||||
let full_size = ret_response.response.rect.size();
|
||||
self.state.open_height = Some(full_size.y);
|
||||
self.store(ui.ctx()); // remember the height
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
//! For instance, a [`Frame`] adds a frame and background to some contained UI.
|
||||
|
||||
pub(crate) mod area;
|
||||
pub mod close_tag;
|
||||
pub mod collapsing_header;
|
||||
mod combo_box;
|
||||
pub mod frame;
|
||||
|
|
|
|||
|
|
@ -150,7 +150,10 @@ impl<T> ModalResponse<T> {
|
|||
let escape_clicked =
|
||||
|| ctx.input_mut(|i| i.consume_key(crate::Modifiers::NONE, crate::Key::Escape));
|
||||
|
||||
let ui_close_called = self.response.should_close();
|
||||
|
||||
self.backdrop_response.clicked()
|
||||
|| ui_close_called
|
||||
|| (self.is_top_modal && !self.any_popup_open && escape_clicked())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -542,7 +542,9 @@ impl<'a> Popup<'a> {
|
|||
PopupCloseBehavior::IgnoreClicks => false,
|
||||
};
|
||||
|
||||
should_close || ctx.input(|i| i.key_pressed(Key::Escape))
|
||||
should_close
|
||||
|| ctx.input(|i| i.key_pressed(Key::Escape))
|
||||
|| response.response.should_close()
|
||||
};
|
||||
|
||||
match open_kind {
|
||||
|
|
|
|||
|
|
@ -434,7 +434,7 @@ impl Window<'_> {
|
|||
) -> Option<InnerResponse<Option<R>>> {
|
||||
let Window {
|
||||
title,
|
||||
open,
|
||||
mut open,
|
||||
area,
|
||||
frame,
|
||||
resize,
|
||||
|
|
@ -634,7 +634,7 @@ impl Window<'_> {
|
|||
title_bar.ui(
|
||||
&mut area_content_ui,
|
||||
&content_response,
|
||||
open,
|
||||
open.as_deref_mut(),
|
||||
&mut collapsing,
|
||||
collapsible,
|
||||
);
|
||||
|
|
@ -650,6 +650,12 @@ impl Window<'_> {
|
|||
|
||||
let full_response = area.end(ctx, area_content_ui);
|
||||
|
||||
if full_response.should_close() {
|
||||
if let Some(open) = open {
|
||||
*open = false;
|
||||
}
|
||||
}
|
||||
|
||||
let inner_response = InnerResponse {
|
||||
inner: content_inner,
|
||||
response: full_response,
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ pub fn zoom_menu_buttons(ui: &mut Ui) {
|
|||
.clicked()
|
||||
{
|
||||
zoom_in(ui.ctx());
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
|
||||
if ui
|
||||
|
|
@ -99,7 +99,7 @@ pub fn zoom_menu_buttons(ui: &mut Ui) {
|
|||
.clicked()
|
||||
{
|
||||
zoom_out(ui.ctx());
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
|
||||
if ui
|
||||
|
|
@ -110,6 +110,6 @@ pub fn zoom_menu_buttons(ui: &mut Ui) {
|
|||
.clicked()
|
||||
{
|
||||
ui.ctx().set_zoom_factor(1.0);
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -364,7 +364,10 @@ impl MenuRoot {
|
|||
let menu_state = self.menu_state.read();
|
||||
|
||||
let escape_pressed = button.ctx.input(|i| i.key_pressed(Key::Escape));
|
||||
if menu_state.response.is_close() || escape_pressed {
|
||||
if menu_state.response.is_close()
|
||||
|| escape_pressed
|
||||
|| inner_response.response.should_close()
|
||||
{
|
||||
return (MenuResponse::Close, Some(inner_response));
|
||||
}
|
||||
}
|
||||
|
|
@ -667,6 +670,9 @@ impl MenuState {
|
|||
) -> Option<R> {
|
||||
let (sub_response, response) = self.submenu(id).map(|sub| {
|
||||
let inner_response = menu_popup(ctx, parent_layer, sub, id, add_contents);
|
||||
if inner_response.response.should_close() {
|
||||
sub.write().close();
|
||||
}
|
||||
(sub.read().response, inner_response.inner)
|
||||
})?;
|
||||
self.cascade_close_response(sub_response);
|
||||
|
|
|
|||
|
|
@ -133,6 +133,9 @@ bitflags::bitflags! {
|
|||
/// Note that this can be `true` even if the user did not interact with the widget,
|
||||
/// for instance if an existing slider value was clamped to the given range.
|
||||
const CHANGED = 1<<11;
|
||||
|
||||
/// Should this container be closed?
|
||||
const CLOSE = 1<<12;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -528,6 +531,21 @@ impl Response {
|
|||
self.flags.set(Flags::CHANGED, true);
|
||||
}
|
||||
|
||||
/// Should the container be closed?
|
||||
///
|
||||
/// Will e.g. be set by calling [`Ui::close`] in a child [`Ui`] or by calling
|
||||
/// [`Self::set_close`].
|
||||
pub fn should_close(&self) -> bool {
|
||||
self.flags.contains(Flags::CLOSE)
|
||||
}
|
||||
|
||||
/// Set the [`Flags::CLOSE`] flag.
|
||||
///
|
||||
/// Can be used to e.g. signal that a container should be closed.
|
||||
pub fn set_close(&mut self) {
|
||||
self.flags.set(Flags::CLOSE, true);
|
||||
}
|
||||
|
||||
/// Show this UI if the widget was hovered (i.e. a tooltip).
|
||||
///
|
||||
/// The text will not be visible if the widget is not enabled.
|
||||
|
|
@ -909,13 +927,13 @@ impl Response {
|
|||
/// let response = ui.add(Label::new("Right-click me!").sense(Sense::click()));
|
||||
/// response.context_menu(|ui| {
|
||||
/// if ui.button("Close the menu").clicked() {
|
||||
/// ui.close_menu();
|
||||
/// ui.close();
|
||||
/// }
|
||||
/// });
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// See also: [`Ui::menu_button`] and [`Ui::close_menu`].
|
||||
/// See also: [`Ui::menu_button`] and [`Ui::close`].
|
||||
pub fn context_menu(&self, add_contents: impl FnOnce(&mut Ui)) -> Option<InnerResponse<()>> {
|
||||
menu::context_menu(self, add_contents)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
#![warn(missing_docs)] // Let's keep `Ui` well-documented.
|
||||
#![allow(clippy::use_self)]
|
||||
|
||||
use std::{any::Any, hash::Hash, sync::Arc};
|
||||
|
||||
use emath::GuiRounding as _;
|
||||
use epaint::mutex::RwLock;
|
||||
use std::{any::Any, hash::Hash, sync::Arc};
|
||||
|
||||
use crate::close_tag::ClosableTag;
|
||||
#[cfg(debug_assertions)]
|
||||
use crate::Stroke;
|
||||
use crate::{
|
||||
containers::{CollapsingHeader, CollapsingResponse, Frame},
|
||||
ecolor::Hsva,
|
||||
|
|
@ -26,11 +28,9 @@ use crate::{
|
|||
},
|
||||
Align, Color32, Context, CursorIcon, DragAndDrop, Id, InnerResponse, InputState, LayerId,
|
||||
Memory, Order, Painter, PlatformOutput, Pos2, Rangef, Rect, Response, Rgba, RichText, Sense,
|
||||
Style, TextStyle, TextWrapMode, UiBuilder, UiStack, UiStackInfo, Vec2, WidgetRect, WidgetText,
|
||||
Style, TextStyle, TextWrapMode, UiBuilder, UiKind, UiStack, UiStackInfo, Vec2, WidgetRect,
|
||||
WidgetText,
|
||||
};
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
use crate::Stroke;
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// This is what you use to place widgets.
|
||||
|
|
@ -1095,7 +1095,8 @@ impl Ui {
|
|||
// This is the inverse of Context::read_response. We prefer a response
|
||||
// based on last frame's widget rect since the one from this frame is Rect::NOTHING until
|
||||
// Ui::interact_bg is called or the Ui is dropped.
|
||||
self.ctx()
|
||||
let mut response = self
|
||||
.ctx()
|
||||
.viewport(|viewport| {
|
||||
viewport
|
||||
.prev_pass
|
||||
|
|
@ -1107,7 +1108,11 @@ impl Ui {
|
|||
.map(|widget_rect| self.ctx().get_response(widget_rect))
|
||||
.expect(
|
||||
"Since we always call Context::create_widget in Ui::new, this should never be None",
|
||||
)
|
||||
);
|
||||
if self.should_close() {
|
||||
response.set_close();
|
||||
}
|
||||
response
|
||||
}
|
||||
|
||||
/// Update the [`WidgetRect`] created in [`Ui::new`] or [`Ui::new_child`] with the current
|
||||
|
|
@ -1121,7 +1126,7 @@ impl Ui {
|
|||
fs.used_ids.remove(&self.unique_id);
|
||||
});
|
||||
// This will update the WidgetRect that was first created in `Ui::new`.
|
||||
self.ctx().create_widget(
|
||||
let mut response = self.ctx().create_widget(
|
||||
WidgetRect {
|
||||
id: self.unique_id,
|
||||
layer_id: self.layer_id(),
|
||||
|
|
@ -1131,7 +1136,11 @@ impl Ui {
|
|||
enabled: self.enabled,
|
||||
},
|
||||
false,
|
||||
)
|
||||
);
|
||||
if self.should_close() {
|
||||
response.set_close();
|
||||
}
|
||||
response
|
||||
}
|
||||
|
||||
/// Interact with the background of this [`Ui`],
|
||||
|
|
@ -1165,6 +1174,69 @@ impl Ui {
|
|||
pub fn ui_contains_pointer(&self) -> bool {
|
||||
self.rect_contains_pointer(self.min_rect())
|
||||
}
|
||||
|
||||
/// Find and close the first closable parent.
|
||||
///
|
||||
/// Use [`UiBuilder::closable`] to make a [`Ui`] closable.
|
||||
/// You can then use [`Ui::should_close`] to check if it should be closed.
|
||||
///
|
||||
/// This is implemented for all egui containers, e.g. [`crate::Popup`], [`crate::Modal`],
|
||||
/// [`crate::Area`], [`crate::Window`], [`crate::CollapsingHeader`], etc.
|
||||
///
|
||||
/// What exactly happens when you close a container depends on the container implementation.
|
||||
/// [`crate::Area`] e.g. will return true from it's [`Response::should_close`] method.
|
||||
///
|
||||
/// If you want to close a specific kind of container, use [`Ui::close_kind`] instead.
|
||||
pub fn close(&self) {
|
||||
let tag = self.stack.iter().find_map(|stack| {
|
||||
stack
|
||||
.info
|
||||
.tags
|
||||
.get_downcast::<ClosableTag>(ClosableTag::NAME)
|
||||
});
|
||||
if let Some(tag) = tag {
|
||||
tag.set_close();
|
||||
} else {
|
||||
#[cfg(feature = "log")]
|
||||
log::warn!("Called ui.close() on a Ui that has no closable parent.");
|
||||
}
|
||||
}
|
||||
|
||||
/// Find and close the first closable parent of a specific [`UiKind`].
|
||||
///
|
||||
/// This is useful if you want to e.g. close a [`crate::Window`]. Since it contains a
|
||||
/// `Collapsible`, [`Ui::close`] would close the `Collapsible` instead.
|
||||
/// You can close the [`crate::Window`] by calling `ui.close_kind(UiKind::Window)`.
|
||||
pub fn close_kind(&self, ui_kind: UiKind) {
|
||||
let tag = self
|
||||
.stack
|
||||
.iter()
|
||||
.filter(|stack| stack.info.kind == Some(ui_kind))
|
||||
.find_map(|stack| {
|
||||
stack
|
||||
.info
|
||||
.tags
|
||||
.get_downcast::<ClosableTag>(ClosableTag::NAME)
|
||||
});
|
||||
if let Some(tag) = tag {
|
||||
tag.set_close();
|
||||
} else {
|
||||
#[cfg(feature = "log")]
|
||||
log::warn!("Called ui.close_kind({ui_kind:?}) on ui with no such closable parent.");
|
||||
}
|
||||
}
|
||||
|
||||
/// Was [`Ui::close`] called on this [`Ui`] or any of its children?
|
||||
/// Only works if the [`Ui`] was created with [`UiBuilder::closable`].
|
||||
///
|
||||
/// You can also check via this [`Ui`]'s [`Response::should_close`].
|
||||
pub fn should_close(&self) -> bool {
|
||||
self.stack
|
||||
.info
|
||||
.tags
|
||||
.get_downcast(ClosableTag::NAME)
|
||||
.is_some_and(|tag: &ClosableTag| tag.should_close())
|
||||
}
|
||||
}
|
||||
|
||||
/// # Allocating space: where do I put my widgets?
|
||||
|
|
@ -2900,11 +2972,9 @@ impl Ui {
|
|||
/// Close the menu we are in (including submenus), if any.
|
||||
///
|
||||
/// See also: [`Self::menu_button`] and [`Response::context_menu`].
|
||||
pub fn close_menu(&mut self) {
|
||||
if let Some(menu_state) = &mut self.menu_state {
|
||||
menu_state.write().close();
|
||||
}
|
||||
self.menu_state = None;
|
||||
#[deprecated = "Use `ui.close()` or `ui.close_kind(UiKind::Menu)` instead"]
|
||||
pub fn close_menu(&self) {
|
||||
self.close_kind(UiKind::Menu);
|
||||
}
|
||||
|
||||
pub(crate) fn set_menu_state(&mut self, menu_state: Option<Arc<RwLock<MenuState>>>) {
|
||||
|
|
@ -2921,14 +2991,14 @@ impl Ui {
|
|||
/// ui.menu_button("My menu", |ui| {
|
||||
/// ui.menu_button("My sub-menu", |ui| {
|
||||
/// if ui.button("Close the menu").clicked() {
|
||||
/// ui.close_menu();
|
||||
/// ui.close();
|
||||
/// }
|
||||
/// });
|
||||
/// });
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// See also: [`Self::close_menu`] and [`Response::context_menu`].
|
||||
/// See also: [`Self::close`] and [`Response::context_menu`].
|
||||
pub fn menu_button<R>(
|
||||
&mut self,
|
||||
title: impl Into<WidgetText>,
|
||||
|
|
@ -2952,7 +3022,7 @@ impl Ui {
|
|||
/// ui.menu_image_button(title, img, |ui| {
|
||||
/// ui.menu_button("My sub-menu", |ui| {
|
||||
/// if ui.button("Close the menu").clicked() {
|
||||
/// ui.close_menu();
|
||||
/// ui.close();
|
||||
/// }
|
||||
/// });
|
||||
/// });
|
||||
|
|
@ -2960,7 +3030,7 @@ impl Ui {
|
|||
/// ```
|
||||
///
|
||||
///
|
||||
/// See also: [`Self::close_menu`] and [`Response::context_menu`].
|
||||
/// See also: [`Self::close`] and [`Response::context_menu`].
|
||||
#[inline]
|
||||
pub fn menu_image_button<'a, R>(
|
||||
&mut self,
|
||||
|
|
@ -2986,14 +3056,14 @@ impl Ui {
|
|||
/// ui.menu_image_text_button(img, title, |ui| {
|
||||
/// ui.menu_button("My sub-menu", |ui| {
|
||||
/// if ui.button("Close the menu").clicked() {
|
||||
/// ui.close_menu();
|
||||
/// ui.close();
|
||||
/// }
|
||||
/// });
|
||||
/// });
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// See also: [`Self::close_menu`] and [`Response::context_menu`].
|
||||
/// See also: [`Self::close`] and [`Response::context_menu`].
|
||||
#[inline]
|
||||
pub fn menu_image_text_button<'a, R>(
|
||||
&mut self,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use std::{hash::Hash, sync::Arc};
|
||||
|
||||
use crate::{Id, LayerId, Layout, Rect, Sense, Style, UiStackInfo};
|
||||
|
||||
use crate::close_tag::ClosableTag;
|
||||
#[allow(unused_imports)] // Used for doclinks
|
||||
use crate::Ui;
|
||||
use crate::{Id, LayerId, Layout, Rect, Sense, Style, UiStackInfo};
|
||||
|
||||
/// Build a [`Ui`] as the child of another [`Ui`].
|
||||
///
|
||||
|
|
@ -125,6 +125,7 @@ impl UiBuilder {
|
|||
}
|
||||
|
||||
/// Set if you want sense clicks and/or drags. Default is [`Sense::hover`].
|
||||
///
|
||||
/// The sense will be registered below the Senses of any widgets contained in this [`Ui`], so
|
||||
/// if the user clicks a button contained within this [`Ui`], that button will receive the click
|
||||
/// instead.
|
||||
|
|
@ -135,4 +136,19 @@ impl UiBuilder {
|
|||
self.sense = Some(sense);
|
||||
self
|
||||
}
|
||||
|
||||
/// Make this [`Ui`] closable.
|
||||
///
|
||||
/// Calling [`Ui::close`] in a child [`Ui`] will mark this [`Ui`] for closing.
|
||||
/// After [`Ui::close`] was called, [`Ui::should_close`] and [`crate::Response::should_close`] will
|
||||
/// return `true` (for this frame).
|
||||
///
|
||||
/// This works by adding a [`ClosableTag`] to the [`UiStackInfo`].
|
||||
#[inline]
|
||||
pub fn closable(mut self) -> Self {
|
||||
self.ui_stack_info
|
||||
.tags
|
||||
.insert(ClosableTag::NAME, Some(Arc::new(ClosableTag::default())));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@ pub enum UiKind {
|
|||
|
||||
/// An [`crate::Area`] that is not of any other kind.
|
||||
GenericArea,
|
||||
|
||||
/// A collapsible container, e.g. a [`crate::CollapsingHeader`].
|
||||
Collapsible,
|
||||
}
|
||||
|
||||
impl UiKind {
|
||||
|
|
@ -81,6 +84,7 @@ impl UiKind {
|
|||
| Self::Frame
|
||||
| Self::ScrollArea
|
||||
| Self::Resize
|
||||
| Self::Collapsible
|
||||
| Self::TableCell => false,
|
||||
|
||||
Self::Window
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ fn integration_ui(ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
|
|||
.send_viewport_cmd(egui::ViewportCommand::InnerSize(size));
|
||||
ui.ctx()
|
||||
.send_viewport_cmd(egui::ViewportCommand::Fullscreen(false));
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -384,12 +384,12 @@ impl WrapApp {
|
|||
.clicked()
|
||||
{
|
||||
ui.ctx().memory_mut(|mem| *mem = Default::default());
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
|
||||
if ui.button("Reset everything").clicked() {
|
||||
*cmd = Command::ResetEverything;
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,25 +59,25 @@ impl ContextMenus {
|
|||
ui.set_max_width(200.0); // To make sure we wrap long text
|
||||
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
ui.menu_button("SubMenu", |ui| {
|
||||
ui.menu_button("SubMenu", |ui| {
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
let _ = ui.button("Item");
|
||||
ui.menu_button("Recursive", Self::nested_menus)
|
||||
});
|
||||
ui.menu_button("SubMenu", |ui| {
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
let _ = ui.button("Item");
|
||||
});
|
||||
let _ = ui.button("Item");
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
ui.menu_button("SubMenu", |ui| {
|
||||
|
|
@ -86,7 +86,7 @@ impl ContextMenus {
|
|||
let _ = ui.button("Item3");
|
||||
let _ = ui.button("Item4");
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
let _ = ui.button("Very long text for this item that should be wrapped");
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ impl DemoWindows {
|
|||
ui.set_style(ui.ctx().style()); // ignore the "menu" style set by `menu_button`.
|
||||
self.demo_list_ui(ui);
|
||||
if ui.ui_contains_pointer() && ui.input(|i| i.pointer.any_click()) {
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -345,7 +345,7 @@ fn file_menu_button(ui: &mut Ui) {
|
|||
.clicked()
|
||||
{
|
||||
ui.ctx().memory_mut(|mem| mem.reset_areas());
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
|
||||
if ui
|
||||
|
|
@ -357,7 +357,7 @@ fn file_menu_button(ui: &mut Ui) {
|
|||
.clicked()
|
||||
{
|
||||
ui.ctx().memory_mut(|mem| *mem = Default::default());
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,9 @@ impl crate::View for Modals {
|
|||
*save_modal_open = true;
|
||||
}
|
||||
if ui.button("Cancel").clicked() {
|
||||
*user_modal_open = false;
|
||||
// You can call `ui.close()` to close the modal.
|
||||
// (This causes the current modals `should_close` to return true)
|
||||
ui.close();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
@ -123,7 +125,7 @@ impl crate::View for Modals {
|
|||
}
|
||||
|
||||
if ui.button("No Thanks").clicked() {
|
||||
*save_modal_open = false;
|
||||
ui.close();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -153,6 +153,10 @@ impl crate::View for PopupsDemo {
|
|||
.show(|ui| {
|
||||
_ = ui.button("Menu item 1");
|
||||
_ = ui.button("Menu item 2");
|
||||
|
||||
if ui.button("I always close the menu").clicked() {
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
|
||||
self.apply_options(Popup::context_menu(&response).id(Id::new("context_menu")))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use egui::Vec2b;
|
||||
use egui::{UiKind, Vec2b};
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
|
|
@ -149,6 +149,16 @@ impl crate::View for WindowOptions {
|
|||
self.disabled_time = ui.input(|i| i.time);
|
||||
}
|
||||
egui::reset_button(ui, self, "Reset");
|
||||
if ui
|
||||
.button("Close")
|
||||
.on_hover_text("You can collapse / close Windows via Ui::close")
|
||||
.clicked()
|
||||
{
|
||||
// Calling close would close the collapsible within the window
|
||||
// ui.close();
|
||||
// Instead, we close the window itself
|
||||
ui.close_kind(UiKind::Window);
|
||||
}
|
||||
ui.add(crate::egui_github_link_file!());
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3411a4a8939b7e731c9c1a6331921b0ac905f4e3e86a51af70bdb38d9446f5e1
|
||||
size 35193
|
||||
oid sha256:e67b1e676ff994cb9557939db3dca5ddd15c69d167afd96c0957a2a3b75c0fd8
|
||||
size 36007
|
||||
|
|
|
|||
Loading…
Reference in New Issue