dont show info when modalmenu hidden, just title. simplify setting info

from outside.
This commit is contained in:
Dustin Carlino 2019-10-11 20:10:12 -07:00
parent 0ea138aa02
commit f1cae9bd37
22 changed files with 131 additions and 121 deletions

View File

@ -7,13 +7,15 @@ use crate::{
// TODO No separators
pub struct ModalMenu {
prompt: Text,
title: String,
info: Text,
chosen_action: Option<String>,
choices: Vec<Choice>,
// This can be inactive entries too.
hovering_idx: Option<usize>,
show_hide_btn: Button,
// TODO Actually, 3 states: full, no controls, just title
visible: bool,
top_left: ScreenPt,
@ -26,10 +28,9 @@ struct Choice {
active: bool,
}
// TODO Keep this API for now, but reconsider lots of things with it ;)
impl ModalMenu {
pub fn new(
prompt_line: &str,
pub fn new<S: Into<String>>(
title: S,
raw_choice_groups: Vec<Vec<(Option<MultiKey>, &str)>>,
ctx: &EventCtx,
) -> ModalMenu {
@ -43,10 +44,10 @@ impl ModalMenu {
});
}
}
let prompt = Text::prompt(prompt_line);
let mut m = ModalMenu {
prompt,
title: title.into(),
info: Text::new(),
chosen_action: None,
choices,
hovering_idx: None,
@ -69,14 +70,12 @@ impl ModalMenu {
m
}
pub fn set_prompt(mut self, ctx: &EventCtx, prompt: Text) -> ModalMenu {
self.prompt = prompt;
pub fn set_info(&mut self, ctx: &EventCtx, info: Text) {
self.info = info;
self.recalculate_dims(ctx);
self
}
// TODO Rename event, get rid of new_prompt
pub fn handle_event(&mut self, ctx: &mut EventCtx, new_prompt: Option<Text>) {
pub fn event(&mut self, ctx: &mut EventCtx) {
if let Some(ref action) = self.chosen_action {
panic!("Caller didn't consume modal action '{}'", action);
}
@ -86,7 +85,7 @@ impl ModalMenu {
let cursor = ctx.canvas.get_cursor_in_screen_space();
self.hovering_idx = None;
let mut top_left = self.top_left;
top_left.y += ctx.canvas.text_dims(&self.prompt).1;
top_left.y += ctx.canvas.line_height + ctx.canvas.text_dims(&self.info).1;
for idx in 0..self.choices.len() {
let rect = ScreenRectangle {
x1: top_left.x,
@ -107,8 +106,6 @@ impl ModalMenu {
}
}
// TODO See what happens with escaping out of context menu
// Handle hotkeys
for choice in &self.choices {
if !choice.active {
@ -145,11 +142,6 @@ impl ModalMenu {
for choice in self.choices.iter_mut() {
choice.active = false;
}
if let Some(txt) = new_prompt {
self.prompt = txt;
self.recalculate_dims(ctx);
}
}
pub fn push_action(&mut self, hotkey: Option<MultiKey>, label: &str, ctx: &EventCtx) {
@ -224,10 +216,11 @@ impl ModalMenu {
}
fn calculate_txt(&self) -> Text {
let mut txt = self.prompt.clone();
let mut txt = Text::prompt(&self.title);
if !self.visible {
return txt;
}
txt.extend(&self.info);
for (idx, choice) in self.choices.iter().enumerate() {
if choice.active {

View File

@ -285,7 +285,8 @@ impl<T> ItemSlider<T> {
abstutil::prettyprint_usize(self.items.len())
)));
txt.extend(&self.items[idx].1);
self.menu.handle_event(ctx, Some(txt));
self.menu.set_info(ctx, txt);
self.menu.event(ctx);
}
stack_vertically(
ContainerOrientation::TopRight,

View File

@ -73,29 +73,32 @@ impl ABTestMode {
impl State for ABTestMode {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
let mut txt = Text::prompt("A/B Test Mode");
if self.flipped {
txt.add(Line("B").fg(Color::CYAN));
} else {
txt.add(Line("A").fg(Color::RED));
}
txt.append(Line(format!(
" - {}",
ui.primary.map.get_edits().edits_name
)));
if let Some(ref diff) = self.diff_trip {
txt.add(Line(format!("Showing diff for {}", diff.trip)));
} else if let Some(ref diff) = self.diff_all {
txt.add(Line(format!(
"Showing diffs for all. {} trips same, {} differ",
diff.same_trips,
diff.lines.len()
{
let mut txt = Text::new();
if self.flipped {
txt.add(Line("B").fg(Color::CYAN));
} else {
txt.add(Line("A").fg(Color::RED));
}
txt.append(Line(format!(
" - {}",
ui.primary.map.get_edits().edits_name
)));
if let Some(ref diff) = self.diff_trip {
txt.add(Line(format!("Showing diff for {}", diff.trip)));
} else if let Some(ref diff) = self.diff_all {
txt.add(Line(format!(
"Showing diffs for all. {} trips same, {} differ",
diff.same_trips,
diff.lines.len()
)));
}
let (active, unfinished) = ui.primary.sim.num_trips();
txt.add(Line(format!("{} active", active)));
txt.add(Line(format!("{} unfinished", unfinished)));
self.menu.set_info(ctx, txt);
}
let (active, unfinished) = ui.primary.sim.num_trips();
txt.add(Line(format!("{} active", active)));
txt.add(Line(format!("{} unfinished", unfinished)));
self.menu.handle_event(ctx, Some(txt));
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);
if ctx.redo_mouseover() {

View File

@ -104,7 +104,7 @@ impl Scoreboard {
impl State for Scoreboard {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
self.menu.event(ctx);
if self.menu.action("quit") {
return Transition::Pop;
}

View File

@ -59,25 +59,23 @@ fn pick_ab_test(wiz: &mut Wizard, ctx: &mut EventCtx, ui: &mut UI) -> Option<Tra
t
};
let mut txt = Text::prompt("A/B Test Editor");
let mut menu = ModalMenu::new(
"A/B Test Editor",
vec![vec![
(hotkey(Key::Escape), "quit"),
(hotkey(Key::R), "run A/B test"),
(hotkey(Key::L), "load savestate"),
]],
ctx,
);
let mut txt = Text::new();
txt.add(Line(&ab_test.test_name));
for line in ab_test.describe() {
txt.add(Line(line));
}
menu.set_info(ctx, txt);
Some(Transition::Replace(Box::new(ABTestSetup {
menu: ModalMenu::new(
"A/B Test Editor",
vec![vec![
(hotkey(Key::Escape), "quit"),
(hotkey(Key::R), "run A/B test"),
(hotkey(Key::L), "load savestate"),
]],
ctx,
)
.set_prompt(ctx, txt),
ab_test,
})))
Some(Transition::Replace(Box::new(ABTestSetup { menu, ab_test })))
}
struct ABTestSetup {
@ -87,7 +85,7 @@ struct ABTestSetup {
impl State for ABTestSetup {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);
if self.menu.action("quit") {

View File

@ -52,24 +52,29 @@ impl SpeedControls {
// Returns the amount of simulation time to step, if running.
pub fn event(&mut self, ctx: &mut EventCtx, current_sim_time: Duration) -> Option<Duration> {
let mut txt = Text::prompt("Speed");
if let State::Running {
ref speed_description,
..
} = self.state
{
txt.add(Line(format!(
"{} / desired {:.2}x",
speed_description,
self.desired_speed()
)));
self.menu.set_info(
ctx,
Text::from(Line(format!(
"{} / desired {:.2}x",
speed_description,
self.desired_speed()
))),
);
} else {
txt.add(Line(format!(
"paused / desired {:.2}x",
self.desired_speed()
)));
self.menu.set_info(
ctx,
Text::from(Line(format!(
"paused / desired {:.2}x",
self.desired_speed()
))),
);
}
self.menu.handle_event(ctx, Some(txt));
self.menu.event(ctx);
layout::stack_vertically(
layout::ContainerOrientation::TopLeft,
ctx.canvas,

View File

@ -128,7 +128,7 @@ struct ShowTrafficSignal {
impl State for ShowTrafficSignal {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);
if self.menu.action("quit") {
return Transition::Pop;

View File

@ -41,7 +41,7 @@ struct ColorChanger {
impl State for ColorChanger {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
self.menu.event(ctx);
if self.menu.action("revert") {
ui.cs.reset_modified(&self.name, self.original);
return Transition::Pop;

View File

@ -15,8 +15,7 @@ pub struct Floodfiller {
impl Floodfiller {
pub fn new(ctx: &mut EventCtx, ui: &UI, parent_menu: &mut ModalMenu) -> Option<Box<dyn State>> {
let map = &ui.primary.map;
let (reachable_lanes, mut prompt) = if let Some(ID::Lane(l)) = ui.primary.current_selection
{
let (reachable_lanes, title) = if let Some(ID::Lane(l)) = ui.primary.current_selection {
if map.get_l(l).is_driving()
&& ctx
.input
@ -24,7 +23,7 @@ impl Floodfiller {
{
(
find_reachable_from(l, map),
Text::prompt(format!("Floodfiller from {}", l).as_str()),
format!("Floodfiller from {}", l),
)
} else {
return None;
@ -44,7 +43,7 @@ impl Floodfiller {
.unwrap()
.into_iter()
.collect(),
Text::prompt("Strongy-connected component"),
"Strongy-connected component".to_string(),
)
} else {
return None;
@ -77,15 +76,15 @@ impl Floodfiller {
map,
);
}
prompt.add(Line(format!("{} unreachable lanes", num_unreachable)));
let mut menu = ModalMenu::new(title, vec![vec![(hotkey(Key::Escape), "quit")]], ctx);
menu.set_info(
ctx,
Text::from(Line(format!("{} unreachable lanes", num_unreachable))),
);
Some(Box::new(Floodfiller {
menu: ModalMenu::new(
"Floodfiller",
vec![vec![(hotkey(Key::Escape), "quit")]],
ctx,
)
.set_prompt(ctx, prompt),
menu,
colorer: colorer.build(ctx, map),
}))
}
@ -98,7 +97,7 @@ impl State for Floodfiller {
}
ctx.canvas.handle_event(ctx.input);
self.menu.handle_event(ctx, None);
self.menu.event(ctx);
if self.menu.action("quit") {
return Transition::Pop;
}

View File

@ -90,21 +90,24 @@ impl State for DebugMode {
ui.calculate_current_selection(ctx, &ui.primary.sim, self, true);
}
let mut txt = Text::prompt("Debug Mode");
if !self.hidden.is_empty() {
txt.add(Line(format!("Hiding {} things", self.hidden.len())));
{
let mut txt = Text::new();
if !self.hidden.is_empty() {
txt.add(Line(format!("Hiding {} things", self.hidden.len())));
}
if let Some(ref results) = self.search_results {
txt.add(Line(format!(
"Search for {} has {} results",
results.query,
results.ids.len()
)));
}
if let routes::AllRoutesViewer::Active(_, ref traces) = self.all_routes {
txt.add(Line(format!("Showing {} routes", traces.len())));
}
self.menu.set_info(ctx, txt);
}
if let Some(ref results) = self.search_results {
txt.add(Line(format!(
"Search for {} has {} results",
results.query,
results.ids.len()
)));
}
if let routes::AllRoutesViewer::Active(_, ref traces) = self.all_routes {
txt.add(Line(format!("Showing {} routes", traces.len())));
}
self.menu.handle_event(ctx, Some(txt));
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);
if let Some(t) = self.common.event(ctx, ui, &mut self.menu) {

View File

@ -58,8 +58,8 @@ impl State for EditMode {
// The .clone() is probably not that expensive, and it makes later code a bit
// easier to read. :)
let orig_edits = ui.primary.map.get_edits().clone();
let mut txt = Text::prompt("Map Edit Mode");
{
let mut txt = Text::new();
txt.add(Line(&orig_edits.edits_name));
txt.add(Line(format!("{} lanes", orig_edits.lane_overrides.len())));
txt.add(Line(format!(
@ -71,8 +71,9 @@ impl State for EditMode {
orig_edits.traffic_signal_overrides.len()
)));
txt.add(Line("Right-click a lane or intersection to start editing"));
self.menu.set_info(ctx, txt);
}
self.menu.handle_event(ctx, Some(txt));
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);

View File

@ -51,7 +51,7 @@ impl StopSignEditor {
impl State for StopSignEditor {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);
if ctx.redo_mouseover() {

View File

@ -56,7 +56,7 @@ impl TrafficSignalEditor {
impl State for TrafficSignalEditor {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);
self.diagram.event(ctx, &mut self.menu);

View File

@ -96,13 +96,16 @@ impl State for TripsVisualizer {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
let time = self.current_time();
let mut txt = Text::prompt("Trips Visualizer");
txt.add(Line(format!("At {}", time)));
txt.add(Line(format!(
"{} active trips",
prettyprint_usize(self.active_trips.len())
)));
self.menu.handle_event(ctx, Some(txt));
{
let mut txt = Text::new();
txt.add(Line(format!("At {}", time)));
txt.add(Line(format!(
"{} active trips",
prettyprint_usize(self.active_trips.len())
)));
self.menu.set_info(ctx, txt);
}
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);
layout::stack_vertically(
layout::ContainerOrientation::TopRight,

View File

@ -84,7 +84,7 @@ impl State for DataVisualizer {
prettyprint_usize(tract.total_owned_cars)
)));
}
self.menu.handle_event(ctx, Some(txt));
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);
// TODO Remember which dataset we're showing and don't allow reseting to the same.

View File

@ -49,7 +49,7 @@ impl MissionEditMode {
impl State for MissionEditMode {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);
if self.menu.action("quit") {

View File

@ -73,7 +73,7 @@ impl State for NeighborhoodEditor {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
let gps_bounds = ui.primary.map.get_gps_bounds();
self.menu.handle_event(ctx, None);
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);
if self.moving_pt {

View File

@ -173,7 +173,7 @@ impl State for ScenarioManager {
// TODO Calculate this once? Except when we modify it, nice to automatically pick up
// changes...
{
let mut txt = Text::prompt("Scenario Editor");
let mut txt = Text::new();
txt.add(Line(&self.scenario.scenario_name));
for line in self.scenario.describe() {
txt.add(Line(line));
@ -183,8 +183,9 @@ impl State for ScenarioManager {
self.total_cars_needed,
prettyprint_usize(self.total_parking_spots),
)));
self.menu.handle_event(ctx, Some(txt));
self.menu.set_info(ctx, txt);
}
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);
if ctx.redo_mouseover() {
ui.recalculate_current_selection(ctx);

View File

@ -84,13 +84,14 @@ impl State for SandboxMode {
self.thruput_stats.record(ui);
{
let mut txt = Text::prompt("Sandbox Mode");
let mut txt = Text::new();
txt.add(Line(ui.primary.sim.time().to_string()));
let (active, unfinished) = ui.primary.sim.num_trips();
txt.add(Line(format!("{} active", active)));
txt.add(Line(format!("{} unfinished", unfinished)));
self.menu.handle_event(ctx, Some(txt));
self.menu.set_info(ctx, txt);
}
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);
if ctx.redo_mouseover() {

View File

@ -63,7 +63,7 @@ impl Scoreboard {
impl State for Scoreboard {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
self.menu.event(ctx);
if self.menu.action("quit") {
return Transition::Pop;
}

View File

@ -120,7 +120,7 @@ impl AgentSpawner {
impl State for AgentSpawner {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
// TODO Instructions to select target building/lane
self.menu.handle_event(ctx, None);
self.menu.event(ctx);
if self.menu.action("quit") {
return Transition::Pop;
}

View File

@ -22,7 +22,7 @@ impl TutorialMode {
impl State for TutorialMode {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> Transition {
let mut txt = Text::prompt("Tutorial");
let mut txt = Text::new();
txt.add(Line("Click and drag to pan around"));
// TODO Zooming also changes this. :(
@ -40,7 +40,8 @@ impl State for TutorialMode {
}));
}
}
self.menu.handle_event(ctx, Some(txt));
self.menu.set_info(ctx, txt);
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);
if self.menu.action("quit") {
@ -66,7 +67,7 @@ struct Part2 {
impl State for Part2 {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> Transition {
let mut txt = Text::prompt("Tutorial");
let mut txt = Text::new();
txt.add(Line("Use your mouse wheel or touchpad to zoom in and out"));
if ctx.canvas.cam_zoom != self.orig_cam_zoom {
@ -76,7 +77,8 @@ impl State for Part2 {
return Transition::Pop;
}
}
self.menu.handle_event(ctx, Some(txt));
self.menu.set_info(ctx, txt);
self.menu.event(ctx);
ctx.canvas.handle_event(ctx.input);
if self.menu.action("quit") {