diff --git a/game/src/ltn/connectivity.rs b/game/src/ltn/connectivity.rs index 1369c3c5f6..83b23b2e6a 100644 --- a/game/src/ltn/connectivity.rs +++ b/game/src/ltn/connectivity.rs @@ -36,18 +36,20 @@ impl Viewer { app: &App, neighborhood: Neighborhood, ) -> Box> { - let panel = Tab::Connectivity.make_panel( - ctx, - app, - Widget::col(vec![ - Widget::row(vec![ - "Draw traffic cells as".text_widget(ctx).centered_vert(), - Toggle::choice(ctx, "draw cells", "areas", "streets", Key::D, true), + let panel = Tab::Connectivity + .panel_builder( + ctx, + app, + Widget::col(vec![ + Widget::row(vec![ + "Draw traffic cells as".text_widget(ctx).centered_vert(), + Toggle::choice(ctx, "draw cells", "areas", "streets", Key::D, true), + ]), + "Click a road to add or remove a modal filter".text_widget(ctx), + Text::new().into_widget(ctx).named("warnings"), ]), - "Click a road to add or remove a modal filter".text_widget(ctx), - Text::new().into_widget(ctx).named("warnings"), - ]), - ); + ) + .build(ctx); let mut viewer = Viewer { panel, diff --git a/game/src/ltn/per_neighborhood.rs b/game/src/ltn/per_neighborhood.rs index 062b133d36..bf30f08e7f 100644 --- a/game/src/ltn/per_neighborhood.rs +++ b/game/src/ltn/per_neighborhood.rs @@ -1,6 +1,6 @@ use map_gui::tools::CityPicker; use widgetry::{ - EventCtx, HorizontalAlignment, Key, Panel, State, VerticalAlignment, Widget, + EventCtx, HorizontalAlignment, Key, Panel, PanelBuilder, State, VerticalAlignment, Widget, DEFAULT_CORNER_RADIUS, }; @@ -19,7 +19,12 @@ pub trait TakeNeighborhood { } impl Tab { - pub fn make_panel(self, ctx: &mut EventCtx, app: &App, per_tab_contents: Widget) -> Panel { + pub fn panel_builder( + self, + ctx: &mut EventCtx, + app: &App, + per_tab_contents: Widget, + ) -> PanelBuilder { Panel::new_builder(Widget::col(vec![ map_gui::tools::app_header(ctx, app, "Low traffic neighborhoods"), Widget::row(vec![ @@ -38,7 +43,6 @@ impl Tab { per_tab_contents.tab_body(ctx), ])) .aligned(HorizontalAlignment::Left, VerticalAlignment::Top) - .build(ctx) } pub fn must_handle_action>( diff --git a/game/src/ltn/rat_run_viewer.rs b/game/src/ltn/rat_run_viewer.rs index e55b15997d..3477a723e1 100644 --- a/game/src/ltn/rat_run_viewer.rs +++ b/game/src/ltn/rat_run_viewer.rs @@ -67,49 +67,53 @@ impl BrowseRatRuns { fn recalculate(&mut self, ctx: &mut EventCtx, app: &App) { if self.rat_runs.paths.is_empty() { - self.panel = Tab::RatRuns.make_panel(ctx, app, "No rat runs detected".text_widget(ctx)); + self.panel = Tab::RatRuns + .panel_builder(ctx, app, "No rat runs detected".text_widget(ctx)) + .build(ctx); return; } - self.panel = Tab::RatRuns.make_panel( - ctx, - app, - Widget::col(vec![ - Widget::row(vec![ - "Rat runs:".text_widget(ctx).centered_vert(), - ctx.style() - .btn_prev() - .disabled(self.current_idx == 0) - .hotkey(Key::LeftArrow) - .build_widget(ctx, "previous rat run"), - Text::from( - Line(format!( - "{}/{}", - self.current_idx + 1, - self.rat_runs.paths.len() - )) - .secondary(), - ) - .into_widget(ctx) - .centered_vert(), - ctx.style() - .btn_next() - .disabled(self.current_idx == self.rat_runs.paths.len() - 1) - .hotkey(Key::RightArrow) - .build_widget(ctx, "next rat run"), + self.panel = Tab::RatRuns + .panel_builder( + ctx, + app, + Widget::col(vec![ + Widget::row(vec![ + "Rat runs:".text_widget(ctx).centered_vert(), + ctx.style() + .btn_prev() + .disabled(self.current_idx == 0) + .hotkey(Key::LeftArrow) + .build_widget(ctx, "previous rat run"), + Text::from( + Line(format!( + "{}/{}", + self.current_idx + 1, + self.rat_runs.paths.len() + )) + .secondary(), + ) + .into_widget(ctx) + .centered_vert(), + ctx.style() + .btn_next() + .disabled(self.current_idx == self.rat_runs.paths.len() - 1) + .hotkey(Key::RightArrow) + .build_widget(ctx, "next rat run"), + ]), + // TODO This should disable the individual path controls, or maybe even be a different + // state entirely... + Toggle::checkbox( + ctx, + "show heatmap of all rat-runs", + Key::R, + self.panel + .maybe_is_checked("show heatmap of all rat-runs") + .unwrap_or(true), + ), ]), - // TODO This should disable the individual path controls, or maybe even be a different - // state entirely... - Toggle::checkbox( - ctx, - "show heatmap of all rat-runs", - Key::R, - self.panel - .maybe_is_checked("show heatmap of all rat-runs") - .unwrap_or(true), - ), - ]), - ); + ) + .build(ctx); let mut draw_path = ToggleZoomed::builder(); let color = Color::RED; diff --git a/game/src/ltn/route.rs b/game/src/ltn/route.rs index 913ff3d440..a53d5bd079 100644 --- a/game/src/ltn/route.rs +++ b/game/src/ltn/route.rs @@ -3,10 +3,10 @@ use map_model::NORMAL_LANE_THICKNESS; use sim::{TripEndpoint, TripMode}; use widgetry::mapspace::{ObjectID, ToggleZoomed, World}; use widgetry::{ - Color, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, RoundedF64, Spinner, - State, Text, VerticalAlignment, Widget, + Color, EventCtx, GfxCtx, Line, Outcome, Panel, RoundedF64, Spinner, State, Text, Widget, }; +use super::per_neighborhood::{Tab, TakeNeighborhood}; use super::Neighborhood; use crate::app::{App, Transition}; use crate::common::{cmp_dist, cmp_duration, InputWaypoints, WaypointID}; @@ -19,6 +19,12 @@ pub struct RoutePlanner { neighborhood: Neighborhood, } +impl TakeNeighborhood for RoutePlanner { + fn take_neighborhood(self) -> Neighborhood { + self.neighborhood + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] enum ID { RouteAfterFilters, @@ -44,12 +50,7 @@ impl RoutePlanner { } fn update(&mut self, ctx: &mut EventCtx, app: &App) { - let mut panel = Panel::new_builder(Widget::col(vec![ - ctx.style() - .btn_outline - .text("Back to editing modal filters") - .hotkey(Key::Escape) - .build_def(ctx), + let contents = Widget::col(vec![ self.waypoints.get_panel_widget(ctx), Widget::row(vec![ Line("Slow-down factor for main roads:") @@ -63,11 +64,12 @@ impl RoutePlanner { ]) .into_widget(ctx), Text::new().into_widget(ctx).named("note"), - ])) - .aligned(HorizontalAlignment::Left, VerticalAlignment::Top) - // Hovering on waypoint cards - .ignore_initial_events() - .build(ctx); + ]); + let mut panel = Tab::Pathfinding + .panel_builder(ctx, app, contents) + // Hovering on waypoint cards + .ignore_initial_events() + .build(ctx); panel.restore(ctx, &self.panel); self.panel = panel; @@ -229,20 +231,7 @@ impl State for RoutePlanner { let panel_outcome = self.panel.event(ctx); if let Outcome::Clicked(ref x) = panel_outcome { - if x == "Back to editing modal filters" { - // We'll cache a custom pathfinder per set of avoided roads. Avoid leaking memory - // by clearing this out - app.primary.map.clear_custom_pathfinder_cache(); - - return Transition::ConsumeState(Box::new(|state, ctx, app| { - let state = state.downcast::().ok().unwrap(); - vec![super::connectivity::Viewer::new_state( - ctx, - app, - state.neighborhood, - )] - })); - } + return Tab::Pathfinding.must_handle_action::(ctx, app, x); } if let Outcome::Changed(ref x) = panel_outcome { @@ -278,4 +267,10 @@ impl State for RoutePlanner { self.world.draw(g); } + + fn on_destroy(&mut self, _: &mut EventCtx, app: &mut App) { + // We'll cache a custom pathfinder per set of avoided roads. Avoid leaking memory by + // clearing this out + app.primary.map.clear_custom_pathfinder_cache(); + } } diff --git a/widgetry/src/lib.rs b/widgetry/src/lib.rs index f80ffd0f39..df98f2a972 100644 --- a/widgetry/src/lib.rs +++ b/widgetry/src/lib.rs @@ -75,7 +75,8 @@ pub use crate::widgets::text_box::TextBox; pub use crate::widgets::toggle::Toggle; pub use crate::widgets::DEFAULT_CORNER_RADIUS; pub use crate::widgets::{ - ClickOutcome, CornerRounding, EdgeInsets, Outcome, Panel, Widget, WidgetImpl, WidgetOutput, + ClickOutcome, CornerRounding, EdgeInsets, Outcome, Panel, PanelBuilder, Widget, WidgetImpl, + WidgetOutput, }; mod app_state; diff --git a/widgetry/src/widgets/mod.rs b/widgetry/src/widgets/mod.rs index ad8a1ad440..9adc668129 100644 --- a/widgetry/src/widgets/mod.rs +++ b/widgetry/src/widgets/mod.rs @@ -11,7 +11,7 @@ use abstutil::CloneableAny; use geom::{CornerRadii, Distance, Percent, Polygon}; use crate::widgets::containers::{Container, Nothing}; -pub use crate::widgets::panel::Panel; +pub use crate::widgets::panel::{Panel, PanelBuilder}; use crate::{ Button, Choice, Color, DeferDraw, Drawable, Dropdown, EventCtx, GeomBatch, GfxCtx, JustDraw, OutlineStyle, ScreenDims, ScreenPt, ScreenRectangle, Toggle,