[menu] click outside a menu to close it
This commit is contained in:
parent
3962fae76e
commit
2861bc956a
5 changed files with 79 additions and 27 deletions
|
@ -1,7 +1,6 @@
|
||||||
pub(crate) mod area;
|
pub(crate) mod area;
|
||||||
pub(crate) mod collapsing_header;
|
pub(crate) mod collapsing_header;
|
||||||
pub(crate) mod frame;
|
pub(crate) mod frame;
|
||||||
pub mod menu;
|
|
||||||
pub(crate) mod popup;
|
pub(crate) mod popup;
|
||||||
pub(crate) mod resize;
|
pub(crate) mod resize;
|
||||||
pub(crate) mod scroll_area;
|
pub(crate) mod scroll_area;
|
||||||
|
|
|
@ -215,6 +215,32 @@ impl InputState {
|
||||||
|| self.scroll_delta != Vec2::zero()
|
|| self.scroll_delta != Vec2::zero()
|
||||||
|| !self.events.is_empty()
|
|| !self.events.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Was the given key pressed this frame?
|
||||||
|
pub fn key_pressed(&self, desired_key: Key) -> bool {
|
||||||
|
self.events.iter().any(|event| {
|
||||||
|
matches!(
|
||||||
|
event,
|
||||||
|
Event::Key {
|
||||||
|
key,
|
||||||
|
pressed: true
|
||||||
|
} if *key == desired_key
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Was the given key released this frame?
|
||||||
|
pub fn key_released(&self, desired_key: Key) -> bool {
|
||||||
|
self.events.iter().any(|event| {
|
||||||
|
matches!(
|
||||||
|
event,
|
||||||
|
Event::Key {
|
||||||
|
key,
|
||||||
|
pressed: false
|
||||||
|
} if *key == desired_key
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MouseInput {
|
impl MouseInput {
|
||||||
|
|
|
@ -33,6 +33,7 @@ mod layers;
|
||||||
mod layout;
|
mod layout;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
mod memory;
|
mod memory;
|
||||||
|
pub mod menu;
|
||||||
mod movement_tracker;
|
mod movement_tracker;
|
||||||
pub mod paint;
|
pub mod paint;
|
||||||
mod painter;
|
mod painter;
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
containers::{area, collapsing_header, menu, resize, scroll_area, window},
|
area, collapsing_header, menu, resize, scroll_area, widgets::text_edit, window, Id, Layer,
|
||||||
widgets::text_edit,
|
Pos2, Rect,
|
||||||
Id, Layer, Pos2, Rect,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The data that Egui persists between frames.
|
/// The data that Egui persists between frames.
|
||||||
|
|
|
@ -1,6 +1,21 @@
|
||||||
use crate::{widgets::*, *};
|
//! Menu bar functionality.
|
||||||
|
//!
|
||||||
|
//! Usage:
|
||||||
|
//! ``` rust
|
||||||
|
//! fn show_menu(ui: &mut egui::Ui) {
|
||||||
|
//! use egui::{menu, Button};
|
||||||
|
//!
|
||||||
|
//! menu::bar(ui, |ui| {
|
||||||
|
//! menu::menu(ui, "File", |ui| {
|
||||||
|
//! if ui.add(Button::new("Open")).clicked {
|
||||||
|
//! // ...
|
||||||
|
//! }
|
||||||
|
//! });
|
||||||
|
//! });
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
|
||||||
use super::*;
|
use crate::{widgets::*, *};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
#[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
@ -21,6 +36,26 @@ impl Default for BarState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BarState {
|
||||||
|
fn load(ctx: &Context, bar_id: &Id) -> Self {
|
||||||
|
ctx.memory()
|
||||||
|
.menu_bar
|
||||||
|
.get(bar_id)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save(self, ctx: &Context, bar_id: Id) {
|
||||||
|
ctx.memory().menu_bar.insert(bar_id, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close_menus(ctx: &Context, bar_id: Id) {
|
||||||
|
let mut bar_state = BarState::load(ctx, &bar_id);
|
||||||
|
bar_state.open_menu = None;
|
||||||
|
bar_state.save(ctx, bar_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn bar<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Rect) {
|
pub fn bar<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Rect) {
|
||||||
ui.inner_layout(Layout::horizontal(Align::Center), |ui| {
|
ui.inner_layout(Layout::horizontal(Align::Center), |ui| {
|
||||||
Frame::menu_bar(ui.style()).show(ui, |ui| {
|
Frame::menu_bar(ui.style()).show(ui, |ui| {
|
||||||
|
@ -38,7 +73,17 @@ pub fn bar<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Rect)
|
||||||
let height = ui.style().menu_bar.height;
|
let height = ui.style().menu_bar.height;
|
||||||
ui.set_desired_height(height);
|
ui.set_desired_height(height);
|
||||||
ui.expand_to_size(vec2(ui.available().width(), height));
|
ui.expand_to_size(vec2(ui.available().width(), height));
|
||||||
add_contents(ui)
|
|
||||||
|
let ret = add_contents(ui);
|
||||||
|
|
||||||
|
let clicked_outside = !ui.hovered(ui.rect()) && ui.input().mouse.released;
|
||||||
|
if clicked_outside || ui.input().key_pressed(Key::Escape) {
|
||||||
|
// TODO: this prevent sub-menus in menus. We should fix that.
|
||||||
|
let bar_id = ui.id();
|
||||||
|
BarState::close_menus(ui.ctx(), bar_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -57,12 +102,7 @@ fn menu_impl<'c>(
|
||||||
let bar_id = ui.id();
|
let bar_id = ui.id();
|
||||||
let menu_id = bar_id.with(&title);
|
let menu_id = bar_id.with(&title);
|
||||||
|
|
||||||
let mut bar_state = ui
|
let mut bar_state = BarState::load(ui.ctx(), &bar_id);
|
||||||
.memory()
|
|
||||||
.menu_bar
|
|
||||||
.get(&bar_id)
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
let mut button = Button::new(title);
|
let mut button = Button::new(title);
|
||||||
|
|
||||||
|
@ -105,7 +145,7 @@ fn menu_impl<'c>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.memory().menu_bar.insert(bar_id, bar_state);
|
bar_state.save(ui.ctx(), bar_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interact_with_menu_button(
|
fn interact_with_menu_button(
|
||||||
|
@ -138,17 +178,4 @@ fn interact_with_menu_button(
|
||||||
if button_interact.hovered && bar_state.open_menu.is_some() {
|
if button_interact.hovered && bar_state.open_menu.is_some() {
|
||||||
bar_state.open_menu = Some(menu_id);
|
bar_state.open_menu = Some(menu_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let pressed_escape = input.events.iter().any(|event| {
|
|
||||||
matches!(
|
|
||||||
event,
|
|
||||||
Event::Key {
|
|
||||||
key: Key::Escape,
|
|
||||||
pressed: true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
});
|
|
||||||
if pressed_escape {
|
|
||||||
bar_state.open_menu = None;
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue