[menu] simplify menu interactions, fixing an annoying bug

This commit is contained in:
Emil Ernerfeldt 2020-09-25 15:31:27 +02:00
parent 22fffc1793
commit d8021843f8
2 changed files with 17 additions and 67 deletions

View file

@ -25,6 +25,7 @@ pub struct Memory {
// states of various types of widgets
pub(crate) collapsing_headers: HashMap<Id, collapsing_header::State>,
#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) menu_bar: HashMap<Id, menu::BarState>,
pub(crate) resize: HashMap<Id, resize::State>,
pub(crate) scroll_areas: HashMap<Id, scroll_area::State>,

View file

@ -18,23 +18,9 @@
use crate::{color::TRANSPARENT, paint::Stroke, widgets::*, *};
/// What is saved between frames.
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Copy, Debug, Default)]
pub(crate) struct BarState {
#[cfg_attr(feature = "serde", serde(skip))]
open_menu: Option<Id>,
#[cfg_attr(feature = "serde", serde(skip))]
/// When did we open a menu?
open_time: f64,
}
impl Default for BarState {
fn default() -> Self {
Self {
open_menu: None,
open_time: f64::NEG_INFINITY,
}
}
}
impl BarState {
@ -49,12 +35,6 @@ impl BarState {
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) {
@ -75,16 +55,7 @@ pub fn bar<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Rect)
ui.set_desired_height(height);
ui.expand_to_size(vec2(ui.available().width(), height));
let ret = add_contents(ui);
let clicked_outside = !ui.hovered(ui.rect()) && ui.input().mouse.click;
if clicked_outside || ui.input().key_pressed(Key::Escape) {
// TODO: this prevents sub-menus in menus. We should fix that.
let bar_id = ui.id();
BarState::close_menus(ui.ctx(), bar_id);
}
ret
add_contents(ui)
})
})
}
@ -112,8 +83,16 @@ fn menu_impl<'c>(
}
let button_response = ui.add(button);
interact_with_menu_button(&mut bar_state, ui.input(), menu_id, &button_response);
if button_response.clicked {
// Toggle
if bar_state.open_menu == Some(menu_id) {
bar_state.open_menu = None;
} else {
bar_state.open_menu = Some(menu_id);
}
} else if button_response.hovered && bar_state.open_menu.is_some() {
bar_state.open_menu = Some(menu_id);
}
if bar_state.open_menu == Some(menu_id) {
let area = Area::new(menu_id)
@ -121,7 +100,7 @@ fn menu_impl<'c>(
.fixed_pos(button_response.rect.left_bottom());
let frame = Frame::menu(ui.style());
let menu_response = area.show(ui.ctx(), |ui| {
area.show(ui.ctx(), |ui| {
frame.show(ui, |ui| {
let mut style = ui.style().clone();
style.spacing.button_padding = vec2(2.0, 0.0);
@ -137,42 +116,12 @@ fn menu_impl<'c>(
})
});
if menu_response.hovered && ui.input().mouse.released {
// TODO: this prevents sub-menus in menus. We should fix that.
if ui.input().key_pressed(Key::Escape) || ui.input().mouse.click && !button_response.clicked
{
bar_state.open_menu = None;
}
}
bar_state.save(ui.ctx(), bar_id);
}
fn interact_with_menu_button(
bar_state: &mut BarState,
input: &InputState,
menu_id: Id,
button_response: &Response,
) {
if button_response.hovered && input.mouse.pressed {
if bar_state.open_menu.is_some() {
bar_state.open_menu = None;
} else {
bar_state.open_menu = Some(menu_id);
bar_state.open_time = input.time;
}
}
if button_response.hovered && input.mouse.released && bar_state.open_menu.is_some() {
let time_since_open = input.time - bar_state.open_time;
if time_since_open < 0.4 {
// A quick click
bar_state.open_menu = Some(menu_id);
bar_state.open_time = input.time;
} else {
// A long hold, then release
bar_state.open_menu = None;
}
}
if button_response.hovered && bar_state.open_menu.is_some() {
bar_state.open_menu = Some(menu_id);
}
}