grey out irrelevant top menu items

This commit is contained in:
Dustin Carlino 2018-12-17 11:51:51 -08:00
parent 875edddc7a
commit 2194ea38a5
4 changed files with 60 additions and 24 deletions

View File

@ -41,7 +41,7 @@ impl ContextMenu {
None,
actions
.into_iter()
.map(|(hotkey, action)| (Some(hotkey), action, hotkey))
.map(|(hotkey, action)| (Some(hotkey), action, true, hotkey))
.collect(),
false,
Position::TopLeft(origin),
@ -114,6 +114,7 @@ impl UserInput {
input.chosen_action = Some(action);
}
}
menu.valid_actions.clear();
}
input.top_menu = top_menu;
@ -250,9 +251,10 @@ impl UserInput {
return true;
}
if let Some(ref menu) = self.top_menu {
if let Some(key) = menu.actions.get(action) {
self.unimportant_key_pressed(*key, action)
if let Some(ref mut menu) = self.top_menu {
if let Some(key) = menu.actions.get(action).cloned() {
menu.valid_actions.insert(action.to_string());
self.unimportant_key_pressed(key, action)
} else {
panic!(
"action_chosen(\"{}\") doesn't match actions in the TopMenu!",

View File

@ -4,7 +4,8 @@ use geom::{Polygon, Pt2D};
// Stores some associated data with each choice
pub struct Menu<T: Clone> {
prompt: Option<String>,
choices: Vec<(Option<Key>, String, T)>,
// The bool is whether this choice is active or not
choices: Vec<(Option<Key>, String, bool, T)>,
current_idx: Option<usize>,
top_left: Pt2D,
@ -20,7 +21,7 @@ pub enum Position {
impl<T: Clone> Menu<T> {
pub fn new(
prompt: Option<String>,
choices: Vec<(Option<Key>, String, T)>,
choices: Vec<(Option<Key>, String, bool, T)>,
select_first: bool,
pos: Position,
canvas: &Canvas,
@ -34,7 +35,7 @@ impl<T: Clone> Menu<T> {
if let Some(ref line) = prompt {
txt.add_line(line.to_string());
}
for (hotkey, choice, _) in &choices {
for (hotkey, choice, _, _) in &choices {
if let Some(key) = hotkey {
txt.add_line(format!("{} - {}", key.describe(), choice));
} else {
@ -73,8 +74,12 @@ impl<T: Clone> Menu<T> {
// Handle the mouse
if ev == Event::LeftMouseButtonDown {
if let Some(i) = self.current_idx {
let (_, choice, data) = self.choices[i].clone();
return InputResult::Done(choice, data);
let (_, choice, active, data) = self.choices[i].clone();
if active {
return InputResult::Done(choice, data);
} else {
return InputResult::StillActive;
}
} else {
return InputResult::Canceled;
}
@ -84,10 +89,11 @@ impl<T: Clone> Menu<T> {
let cursor_pt = canvas.screen_to_map((x, y));
let mut matched = false;
for i in 0..self.choices.len() {
if self
.first_choice_row
.translate(0.0, (i as f64) * self.row_height)
.contains_pt(cursor_pt)
if self.choices[i].2
&& self
.first_choice_row
.translate(0.0, (i as f64) * self.row_height)
.contains_pt(cursor_pt)
{
self.current_idx = Some(i);
matched = true;
@ -108,8 +114,12 @@ impl<T: Clone> Menu<T> {
// TODO Disable arrow keys in context menus and the top menu?
if let Some(idx) = self.current_idx {
if ev == Event::KeyPress(Key::Enter) {
let (_, name, data) = self.choices[idx].clone();
return InputResult::Done(name, data);
let (_, name, active, data) = self.choices[idx].clone();
if active {
return InputResult::Done(name, data);
} else {
return InputResult::StillActive;
}
} else if ev == Event::KeyPress(Key::UpArrow) {
if idx > 0 {
self.current_idx = Some(idx - 1);
@ -133,17 +143,29 @@ impl<T: Clone> Menu<T> {
Some(text::TEXT_QUERY_COLOR),
);
}
for (idx, (hotkey, choice, _)) in self.choices.iter().enumerate() {
for (idx, (hotkey, choice, active, _)) in self.choices.iter().enumerate() {
let bg = if Some(idx) == self.current_idx {
Some(Color::WHITE)
} else {
None
};
if let Some(key) = hotkey {
txt.add_styled_line(key.describe(), Color::BLUE, bg);
txt.append(format!(" - {}", choice), text::TEXT_FG_COLOR, bg);
if *active {
if let Some(key) = hotkey {
txt.add_styled_line(key.describe(), Color::BLUE, bg);
txt.append(format!(" - {}", choice), text::TEXT_FG_COLOR, bg);
} else {
txt.add_styled_line(choice.to_string(), text::TEXT_FG_COLOR, bg);
}
} else {
txt.add_styled_line(choice.to_string(), text::TEXT_FG_COLOR, bg);
if let Some(key) = hotkey {
txt.add_styled_line(
format!("{} - {}", key.describe(), choice),
Color::grey(0.8),
bg,
);
} else {
txt.add_styled_line(format!("{}", choice), Color::grey(0.8), bg);
}
}
}
canvas.draw_text_at_topleft(g, txt, self.top_left);
@ -151,6 +173,6 @@ impl<T: Clone> Menu<T> {
pub fn current_choice(&self) -> Option<&T> {
let idx = self.current_idx?;
Some(&self.choices[idx].2)
Some(&self.choices[idx].3)
}
}

View File

@ -12,6 +12,8 @@ pub struct TopMenu {
highlighted: Option<usize>,
submenu: Option<(usize, Menu<Key>)>,
// Reset every round
pub(crate) valid_actions: HashSet<String>,
}
impl TopMenu {
@ -57,6 +59,7 @@ impl TopMenu {
txt,
highlighted: None,
submenu: None,
valid_actions: HashSet::new(),
}
}
@ -80,13 +83,22 @@ impl TopMenu {
.unwrap_or(false)
{
let f = &self.folders[idx];
// valid_actions can't change once this submenu is created, so determine what
// actions are valid right now.
self.submenu = Some((
idx,
Menu::new(
None,
f.actions
.iter()
.map(|(key, action)| (Some(*key), action.to_string(), *key))
.map(|(key, action)| {
(
Some(*key),
action.to_string(),
self.valid_actions.contains(action),
*key,
)
})
.collect(),
false,
Position::TopLeft(canvas.screen_to_map((f.rectangle.x1, f.rectangle.y2))),

View File

@ -208,9 +208,9 @@ impl<'a> WrappedWizard<'a> {
)]));
return None;
}
let boxed_choices: Vec<(Option<Key>, String, Box<Cloneable>)> = choices
let boxed_choices: Vec<(Option<Key>, String, bool, Box<Cloneable>)> = choices
.iter()
.map(|(s, item)| (None, s.to_string(), item.clone_box()))
.map(|(s, item)| (None, s.to_string(), true, item.clone_box()))
.collect();
self.wizard.menu = Some(Menu::new(
Some(query.to_string()),