From 119e887425d02a545193081f17a77a2378b4b933 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Thu, 24 Sep 2020 10:40:18 -0700 Subject: [PATCH] New dashboard picker. #331 --- .../sandbox/dashboards/generic_trip_table.rs | 15 ++- game/src/sandbox/dashboards/misc.rs | 21 ++++- game/src/sandbox/dashboards/mod.rs | 92 +++++++++---------- game/src/sandbox/dashboards/summaries.rs | 9 +- game/src/sandbox/dashboards/trip_table.rs | 18 +++- 5 files changed, 96 insertions(+), 59 deletions(-) diff --git a/game/src/sandbox/dashboards/generic_trip_table.rs b/game/src/sandbox/dashboards/generic_trip_table.rs index b0ec85da90..b8525e49e5 100644 --- a/game/src/sandbox/dashboards/generic_trip_table.rs +++ b/game/src/sandbox/dashboards/generic_trip_table.rs @@ -3,6 +3,7 @@ use crate::game::{DrawBaselayer, State, Transition}; use crate::helpers::color_for_trip_phase; use crate::info::{OpenTrip, Tab}; use crate::sandbox::dashboards::table::Table; +use crate::sandbox::dashboards::trip_table; use crate::sandbox::dashboards::DashTab; use crate::sandbox::SandboxMode; use geom::{Distance, Pt2D}; @@ -66,11 +67,23 @@ impl) ); })), ]); + } else if x == "close" { + return Transition::Pop; + } else if x == "finished trips" { + return Transition::Replace(trip_table::FinishedTripTable::new(ctx, app)); + } else if x == "cancelled trips" { + return Transition::Replace(trip_table::CancelledTripTable::new(ctx, app)); + } else if x == "unfinished trips" { + return Transition::Replace(trip_table::UnfinishedTripTable::new(ctx, app)); } else { - return self.tab.transition(ctx, app, &x); + unreachable!() } } Outcome::Changed => { + if let Some(t) = self.tab.transition(ctx, app, &self.panel) { + return t; + } + self.table.panel_changed(&self.panel); self.recalc(ctx, app); } diff --git a/game/src/sandbox/dashboards/misc.rs b/game/src/sandbox/dashboards/misc.rs index f678096cee..cd3c53fb90 100644 --- a/game/src/sandbox/dashboards/misc.rs +++ b/game/src/sandbox/dashboards/misc.rs @@ -56,7 +56,13 @@ impl ActiveTraffic { impl State for ActiveTraffic { fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition { match self.panel.event(ctx) { - Outcome::Clicked(x) => DashTab::TripSummaries.transition(ctx, app, &x), + Outcome::Clicked(x) => match x.as_ref() { + "close" => Transition::Pop, + _ => unreachable!(), + }, + Outcome::Changed => DashTab::ActiveTraffic + .transition(ctx, app, &self.panel) + .unwrap(), _ => Transition::Keep, } } @@ -194,11 +200,20 @@ impl State for TransitRoutes { Outcome::Clicked(x) => { if let Some(x) = x.strip_prefix("BusRoute #") { BusRouteID(x.parse::().unwrap()) + } else if x == "close" { + return Transition::Pop; } else { - return DashTab::TransitRoutes.transition(ctx, app, &x); + unreachable!() } } - _ => { + Outcome::Changed => { + if let Some(t) = DashTab::TransitRoutes.transition(ctx, app, &self.panel) { + return t; + } else { + return Transition::Keep; + } + } + Outcome::Nothing => { if let Some(routes) = self.panel.autocomplete_done("search") { if !routes.is_empty() { routes[0] diff --git a/game/src/sandbox/dashboards/mod.rs b/game/src/sandbox/dashboards/mod.rs index 89f522e5d7..0472bab7bc 100644 --- a/game/src/sandbox/dashboards/mod.rs +++ b/game/src/sandbox/dashboards/mod.rs @@ -12,10 +12,10 @@ use crate::game::Transition; pub use commuter::CommuterPatterns; pub use traffic_signals::TrafficSignalDemand; pub use trip_table::FinishedTripTable; -use widgetry::{Btn, Color, EventCtx, Key, Widget}; +use widgetry::{Btn, Choice, EventCtx, Key, Panel, TextExt, Widget}; // Oh the dashboards melted, but we still had the radio -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Debug)] pub enum DashTab { FinishedTripTable, CancelledTripTable, @@ -30,60 +30,52 @@ pub enum DashTab { impl DashTab { pub fn picker(self, ctx: &EventCtx, app: &App) -> Widget { - let mut row = Vec::new(); - for (name, tab) in vec![ - ("trip table", DashTab::FinishedTripTable), - ("trip summaries", DashTab::TripSummaries), - ("parking overhead", DashTab::ParkingOverhead), - ("active traffic", DashTab::ActiveTraffic), - ("transit routes", DashTab::TransitRoutes), - ("commuter patterns", DashTab::CommuterPatterns), - ("traffic signal demand", DashTab::TrafficSignals), - ] { - if tab == DashTab::TripSummaries && app.has_prebaked().is_none() { - continue; - } - if self == tab { - row.push(Btn::text_bg2(name).inactive(ctx)); - } else { - row.push(Btn::text_bg2(name).build_def(ctx, None)); - } - } - Widget::custom_row(vec![ - // TODO Centered, but actually, we need to set the padding of each button to divide the - // available space evenly. Fancy fill rules... hmmm. - Widget::custom_row(row).bg(Color::WHITE).margin_vert(16), + Widget::row(vec![ + Widget::draw_svg(ctx, "system/assets/meters/trip_histogram.svg"), + Widget::dropdown( + ctx, + "tab", + self, + vec![ + Choice::new("Trip Table", DashTab::FinishedTripTable), + Choice::new("Trip Summaries", DashTab::TripSummaries), + Choice::new("Parking Overhead", DashTab::ParkingOverhead), + Choice::new("Active Traffic", DashTab::ActiveTraffic), + Choice::new("Transit Routes", DashTab::TransitRoutes), + Choice::new("Commuter Patterns", DashTab::CommuterPatterns), + Choice::new("Traffic Signal Demand", DashTab::TrafficSignals), + ], + ), + format!("By {}", app.primary.sim.time()) + .draw_text(ctx) + .centered_vert(), Btn::plaintext("X") .build(ctx, "close", Key::Escape) .align_right(), ]) } - pub fn transition(self, ctx: &mut EventCtx, app: &mut App, action: &str) -> Transition { - match action { - "close" => Transition::Pop, - "trip table" => Transition::Replace(FinishedTripTable::new(ctx, app)), - "trip summaries" => Transition::Replace(summaries::TripSummaries::new( - ctx, - app, - summaries::Filter::new(), - )), - "parking overhead" => { - Transition::Replace(parking_overhead::ParkingOverhead::new(ctx, app)) - } - "active traffic" => Transition::Replace(misc::ActiveTraffic::new(ctx, app)), - "transit routes" => Transition::Replace(misc::TransitRoutes::new(ctx, app)), - "commuter patterns" => Transition::Replace(CommuterPatterns::new(ctx, app)), - "traffic signal demand" => Transition::Replace(TrafficSignalDemand::new(ctx, app)), - - // TODO Misleading. These doesn't show up under the DashTab, but we're hijacking this - // for some of the sub-tabs. - "finished trips" => Transition::Replace(FinishedTripTable::new(ctx, app)), - "cancelled trips" => Transition::Replace(trip_table::CancelledTripTable::new(ctx, app)), - "unfinished trips" => { - Transition::Replace(trip_table::UnfinishedTripTable::new(ctx, app)) - } - _ => unreachable!(), + pub fn transition( + self, + ctx: &mut EventCtx, + app: &mut App, + panel: &Panel, + ) -> Option { + let tab = panel.dropdown_value("tab"); + if tab == self { + return None; } + Some(Transition::Replace(match tab { + DashTab::FinishedTripTable => FinishedTripTable::new(ctx, app), + DashTab::TripSummaries => { + summaries::TripSummaries::new(ctx, app, summaries::Filter::new()) + } + DashTab::ParkingOverhead => parking_overhead::ParkingOverhead::new(ctx, app), + DashTab::ActiveTraffic => misc::ActiveTraffic::new(ctx, app), + DashTab::TransitRoutes => misc::TransitRoutes::new(ctx, app), + DashTab::CommuterPatterns => CommuterPatterns::new(ctx, app), + DashTab::TrafficSignals => TrafficSignalDemand::new(ctx, app), + DashTab::CancelledTripTable | DashTab::UnfinishedTripTable => unreachable!(), + })) } } diff --git a/game/src/sandbox/dashboards/summaries.rs b/game/src/sandbox/dashboards/summaries.rs index 77fe245851..98cbd73446 100644 --- a/game/src/sandbox/dashboards/summaries.rs +++ b/game/src/sandbox/dashboards/summaries.rs @@ -66,9 +66,16 @@ impl State for TripSummaries { Err(err) => PopupMsg::new(ctx, "Export failed", vec![err.to_string()]), }); } - x => DashTab::TripSummaries.transition(ctx, app, x), + "close" => { + return Transition::Pop; + } + _ => unreachable!(), }, Outcome::Changed => { + if let Some(t) = DashTab::TripSummaries.transition(ctx, app, &self.panel) { + return t; + } + let mut filter = Filter { changes_pct: self.panel.dropdown_value("filter"), modes: BTreeSet::new(), diff --git a/game/src/sandbox/dashboards/trip_table.rs b/game/src/sandbox/dashboards/trip_table.rs index a72e854752..9b43ad735a 100644 --- a/game/src/sandbox/dashboards/trip_table.rs +++ b/game/src/sandbox/dashboards/trip_table.rs @@ -565,6 +565,7 @@ fn trip_category_selector(ctx: &mut EventCtx, app: &App, tab: DashTab) -> Widget aborted += 1; } } + let total = finished + aborted + unfinished; let btn = |dash, action, label| { if dash == tab { @@ -583,7 +584,11 @@ fn trip_category_selector(ctx: &mut EventCtx, app: &App, tab: DashTab) -> Widget format!( "{} ({:.1}%) Finished Trips", prettyprint_usize(finished), - (finished as f64) / ((finished + aborted + unfinished) as f64) * 100.0 + if total > 0 { + (finished as f64) / (total as f64) * 100.0 + } else { + 0.0 + } ), ) .margin_right(28), @@ -599,7 +604,11 @@ fn trip_category_selector(ctx: &mut EventCtx, app: &App, tab: DashTab) -> Widget format!( "{} ({:.1}%) Unfinished Trips", prettyprint_usize(unfinished), - (unfinished as f64) / ((finished + aborted + unfinished) as f64) * 100.0 + if total > 0 { + (unfinished as f64) / (total as f64) * 100.0 + } else { + 0.0 + } ), ), ]) @@ -622,13 +631,14 @@ fn make_panel_finished_trips( .build(ctx) } +// Always use DashTab::FinishedTripTable, so the dropdown works fn make_panel_cancelled_trips( ctx: &mut EventCtx, app: &App, table: &Table, ) -> Panel { Panel::new(Widget::col(vec![ - DashTab::CancelledTripTable.picker(ctx, app), + DashTab::FinishedTripTable.picker(ctx, app), trip_category_selector(ctx, app, DashTab::CancelledTripTable), table.render(ctx, app), Filler::square_width(ctx, 0.15) @@ -645,7 +655,7 @@ fn make_panel_unfinished_trips( table: &Table, ) -> Panel { Panel::new(Widget::col(vec![ - DashTab::UnfinishedTripTable.picker(ctx, app), + DashTab::FinishedTripTable.picker(ctx, app), trip_category_selector(ctx, app, DashTab::UnfinishedTripTable), table.render(ctx, app), Filler::square_width(ctx, 0.15)