ModalMenus can be mostly hidden

This commit is contained in:
Dustin Carlino 2019-05-01 10:50:16 -07:00
parent 6e2689f68c
commit b42bba799d
8 changed files with 114 additions and 86 deletions

View File

@ -33,7 +33,7 @@ impl TurnCyclerState {
self.state = State::ShowLane(id);
} else if ctx
.input
.key_pressed(Key::Tab, "cycle through this lane's turns")
.key_pressed(Key::Z, "cycle through this lane's turns")
{
self.state = State::CycleTurns(id, idx + 1);
}
@ -42,7 +42,7 @@ impl TurnCyclerState {
if !ui.primary.map.get_turns_from_lane(id).is_empty()
&& ctx
.input
.key_pressed(Key::Tab, "cycle through this lane's turns")
.key_pressed(Key::Z, "cycle through this lane's turns")
{
self.state = State::CycleTurns(id, 0);
}

View File

@ -44,7 +44,7 @@ impl TrafficSignalEditor {
false,
);
ctx.input.set_mode_with_prompt(
self.diagram_top_left = ctx.input.set_mode_with_prompt(
"Traffic Signal Editor",
format!("Traffic Signal Editor for {}", self.i),
&ctx.canvas,

View File

@ -8,8 +8,8 @@ use crate::tutorial::TutorialMode;
use crate::ui::{EditorState, Flags, ShowEverything, UI};
use abstutil::elapsed_seconds;
use ezgui::{
Canvas, EventCtx, EventLoopMode, GfxCtx, Key, LogScroller, ModalMenu, Prerender, TopMenu,
UserInput, Wizard, GUI,
Canvas, EventCtx, EventLoopMode, GfxCtx, Key, LogScroller, ModalMenu, Prerender, UserInput,
Wizard, GUI,
};
use geom::{Duration, Line, Pt2D, Speed};
use map_model::Map;
@ -69,10 +69,6 @@ impl GameState {
}
impl GUI for GameState {
fn top_menu(&self, _: &Canvas) -> Option<TopMenu> {
None
}
fn modal_menus(&self) -> Vec<ModalMenu> {
vec![
ModalMenu::new(

View File

@ -182,7 +182,7 @@ impl SandboxMode {
if ctx.input.modal_action("speed up sim") {
mode.desired_speed += ADJUST_SPEED;
}
if ctx.input.modal_action("reset sim") {
if !state.ui.primary.sim.is_empty() && ctx.input.modal_action("reset sim") {
// TODO savestate_every gets lost
state.ui.primary.sim = Sim::new(
&state.ui.primary.map,

View File

@ -48,6 +48,7 @@ impl ContextMenu {
.map(|(hotkey, action)| (Some(hotkey), action, hotkey))
.collect(),
false,
false,
Position::TopLeftAt(origin),
canvas,
))
@ -254,7 +255,7 @@ impl UserInput {
if let Some(ref mut menu) = self.modal_state.mut_active_mode(mode) {
menu.mark_all_inactive();
menu.change_prompt(prompt);
menu.get_bottom_left()
menu.get_bottom_left(canvas)
} else {
if let Some(ref m) = self.modal_state.modes.get(mode) {
let mut menu = Menu::new(
@ -264,11 +265,12 @@ impl UserInput {
.map(|(key, action)| (Some(*key), action.to_string(), *key))
.collect(),
false,
true,
Position::TopRightOfScreen(extra_width),
canvas,
);
menu.mark_all_inactive();
let corner = menu.get_bottom_left();
let corner = menu.get_bottom_left(canvas);
self.modal_state.active.push((mode.to_string(), menu));
corner
} else {

View File

@ -9,11 +9,14 @@ pub struct Menu<T: Clone> {
current_idx: Option<usize>,
mouse_in_bounds: bool,
keys_enabled: bool,
hideable: bool,
hidden: bool,
pos: Position,
row_height: f64,
top_left: ScreenPt,
first_choice_row: ScreenRectangle,
// TODO Could store this in hidden and non-hidden modes, maybe simpler that way.
total_height: f64,
}
@ -30,6 +33,7 @@ impl<T: Clone> Menu<T> {
prompt: Option<Text>,
choices: Vec<(Option<Key>, String, T)>,
keys_enabled: bool,
hideable: bool,
pos: Position,
canvas: &Canvas,
) -> Menu<T> {
@ -81,6 +85,8 @@ impl<T: Clone> Menu<T> {
// TODO Bit of a hack, but eh.
mouse_in_bounds: !keys_enabled,
pos,
hideable,
hidden: false,
row_height,
top_left,
@ -95,59 +101,72 @@ impl<T: Clone> Menu<T> {
}
pub fn event(&mut self, ev: Event, canvas: &Canvas) -> InputResult<T> {
// Handle the mouse
if ev == Event::LeftMouseButtonDown {
if let Some(i) = self.current_idx {
let (_, choice, active, data) = self.choices[i].clone();
if active && self.mouse_in_bounds {
return InputResult::Done(choice, data);
} else {
return InputResult::StillActive;
}
} else {
return InputResult::Canceled;
}
} else if ev == Event::RightMouseButtonDown {
return InputResult::Canceled;
} else if let Event::MouseMovedTo(pt) = ev {
if !canvas.is_dragging() {
for i in 0..self.choices.len() {
if self.choices[i].2
&& self
.first_choice_row
.translate(0.0, (i as f64) * self.row_height)
.contains(pt)
{
self.current_idx = Some(i);
self.mouse_in_bounds = true;
if !self.hidden {
// Handle the mouse
if ev == Event::LeftMouseButtonDown {
if let Some(i) = self.current_idx {
let (_, choice, active, data) = self.choices[i].clone();
if active && self.mouse_in_bounds {
return InputResult::Done(choice, data);
} else {
return InputResult::StillActive;
}
} else {
return InputResult::Canceled;
}
self.mouse_in_bounds = false;
if !self.keys_enabled {
self.current_idx = None;
} else if ev == Event::RightMouseButtonDown {
return InputResult::Canceled;
} else if let Event::MouseMovedTo(pt) = ev {
if !canvas.is_dragging() {
for i in 0..self.choices.len() {
if self.choices[i].2
&& self
.first_choice_row
.translate(0.0, (i as f64) * self.row_height)
.contains(pt)
{
self.current_idx = Some(i);
self.mouse_in_bounds = true;
return InputResult::StillActive;
}
}
self.mouse_in_bounds = false;
if !self.keys_enabled {
self.current_idx = None;
}
return InputResult::StillActive;
}
}
// Handle keys
if self.keys_enabled {
let idx = self.current_idx.unwrap();
if ev == Event::KeyPress(Key::Enter) {
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);
}
} else if ev == Event::KeyPress(Key::DownArrow) {
if idx < self.choices.len() - 1 {
self.current_idx = Some(idx + 1);
}
}
return InputResult::StillActive;
}
}
// Handle keys
if self.keys_enabled {
let idx = self.current_idx.unwrap();
if ev == Event::KeyPress(Key::Enter) {
let (_, name, active, data) = self.choices[idx].clone();
if active {
return InputResult::Done(name, data);
if self.hideable {
if ev == Event::KeyPress(Key::Tab) {
if self.hidden {
self.hidden = false;
} else {
return InputResult::StillActive;
}
} else if ev == Event::KeyPress(Key::UpArrow) {
if idx > 0 {
self.current_idx = Some(idx - 1);
}
} else if ev == Event::KeyPress(Key::DownArrow) {
if idx < self.choices.len() - 1 {
self.current_idx = Some(idx + 1);
self.hidden = true;
self.current_idx = None;
}
}
}
@ -174,6 +193,7 @@ impl<T: Clone> Menu<T> {
.map(|(key, choice, _, data)| (*key, choice.to_string(), data.clone()))
.collect(),
self.keys_enabled,
self.hideable,
self.pos.clone(),
canvas,
);
@ -187,42 +207,45 @@ impl<T: Clone> Menu<T> {
pub fn draw(&self, g: &mut GfxCtx) {
let mut txt = self.prompt.clone().unwrap_or_else(Text::new);
for (idx, (hotkey, choice, active, _)) in self.choices.iter().enumerate() {
let bg = if Some(idx) == self.current_idx {
Some(text::SELECTED_COLOR)
} else {
None
};
if *active {
if let Some(key) = hotkey {
txt.add_styled_line(key.describe(), Some(text::HOTKEY_COLOR), bg, None);
txt.append(format!(" - {}", choice), None);
if !self.hidden {
for (idx, (hotkey, choice, active, _)) in self.choices.iter().enumerate() {
let bg = if Some(idx) == self.current_idx {
Some(text::SELECTED_COLOR)
} else {
txt.add_styled_line(choice.to_string(), None, bg, None);
}
} else {
if let Some(key) = hotkey {
txt.add_styled_line(
format!("{} - {}", key.describe(), choice),
Some(text::INACTIVE_CHOICE_COLOR),
bg,
None,
);
None
};
if *active {
if let Some(key) = hotkey {
txt.add_styled_line(key.describe(), Some(text::HOTKEY_COLOR), bg, None);
txt.append(format!(" - {}", choice), None);
} else {
txt.add_styled_line(choice.to_string(), None, bg, None);
}
} else {
txt.add_styled_line(
choice.to_string(),
Some(text::INACTIVE_CHOICE_COLOR),
bg,
None,
);
if let Some(key) = hotkey {
txt.add_styled_line(
format!("{} - {}", key.describe(), choice),
Some(text::INACTIVE_CHOICE_COLOR),
bg,
None,
);
} else {
txt.add_styled_line(
choice.to_string(),
Some(text::INACTIVE_CHOICE_COLOR),
bg,
None,
);
}
}
}
}
let (_, total_height) = g.canvas.text_dims(&txt);
g.canvas.mark_covered_area(ScreenRectangle {
x1: self.top_left.x,
y1: self.top_left.y,
x2: self.first_choice_row.x2,
y2: self.top_left.y + self.total_height,
y2: self.top_left.y + total_height,
});
g.draw_text_at_screenspace_topleft(&txt, self.top_left);
}
@ -258,7 +281,12 @@ impl<T: Clone> Menu<T> {
// TODO Actually just recalculate geometry when this happens...
}
pub fn get_bottom_left(&self) -> ScreenPt {
ScreenPt::new(self.top_left.x, self.top_left.y + self.total_height)
pub fn get_bottom_left(&self, canvas: &Canvas) -> ScreenPt {
let total_height = if self.hidden {
canvas.text_dims(&self.prompt.as_ref().unwrap()).1
} else {
self.total_height
};
ScreenPt::new(self.top_left.x, self.top_left.y + total_height)
}
}

View File

@ -86,6 +86,7 @@ impl TopMenu {
.map(|(maybe_key, action)| (*maybe_key, action.to_string(), ()))
.collect(),
false,
false,
Position::TopLeftAt(ScreenPt::new(f.rectangle.x1, f.rectangle.y2)),
canvas,
);

View File

@ -220,6 +220,7 @@ impl<'a> WrappedWizard<'a> {
)),
boxed_choices,
true,
false,
Position::ScreenCenter,
self.canvas,
));