[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 collapsing_header;
pub(crate) mod frame;
pub mod menu;
pub(crate) mod popup;
pub(crate) mod resize;
pub(crate) mod scroll_area;

View file

@ -215,6 +215,32 @@ impl InputState {
|| self.scroll_delta != Vec2::zero()
|| !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 {

View file

@ -33,6 +33,7 @@ mod layers;
mod layout;
pub mod math;
mod memory;
pub mod menu;
mod movement_tracker;
pub mod paint;
mod painter;

View file

@ -1,9 +1,8 @@
use std::collections::{HashMap, HashSet};
use crate::{
containers::{area, collapsing_header, menu, resize, scroll_area, window},
widgets::text_edit,
Id, Layer, Pos2, Rect,
area, collapsing_header, menu, resize, scroll_area, widgets::text_edit, window, Id, Layer,
Pos2, Rect,
};
/// 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)]
#[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) {
ui.inner_layout(Layout::horizontal(Align::Center), |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;
ui.set_desired_height(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 menu_id = bar_id.with(&title);
let mut bar_state = ui
.memory()
.menu_bar
.get(&bar_id)
.cloned()
.unwrap_or_default();
let mut bar_state = BarState::load(ui.ctx(), &bar_id);
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(
@ -138,17 +178,4 @@ fn interact_with_menu_button(
if button_interact.hovered && bar_state.open_menu.is_some() {
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;
}
}