[menu] click outside a menu to close it

This commit is contained in:
Emil Ernerfeldt 2020-08-05 13:32:40 +02:00
parent 3962fae76e
commit 2861bc956a
5 changed files with 79 additions and 27 deletions

View file

@ -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;

View file

@ -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 {

View file

@ -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;

View file

@ -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.

View file

@ -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;
}
} }