diff --git a/game/src/sandbox/dashboards/mod.rs b/game/src/sandbox/dashboards/mod.rs index a768e227a9..26d16ffdea 100644 --- a/game/src/sandbox/dashboards/mod.rs +++ b/game/src/sandbox/dashboards/mod.rs @@ -11,6 +11,7 @@ mod commuter; mod generic_trip_table; mod misc; mod parking_overhead; +mod selector; mod summaries; mod traffic_signals; mod trip_table; diff --git a/game/src/sandbox/dashboards/selector.rs b/game/src/sandbox/dashboards/selector.rs new file mode 100644 index 0000000000..a7e6cb6cfa --- /dev/null +++ b/game/src/sandbox/dashboards/selector.rs @@ -0,0 +1,83 @@ +use geom::{Polygon, Pt2D}; +use widgetry::{ + Color, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, State, TextExt, + VerticalAlignment, Widget, +}; + +use crate::app::{App, Transition}; + +// TODO Lift to widgetry +pub struct RectangularSelector { + panel: Panel, + region: Option, + corners: Option<(Pt2D, Pt2D, bool)>, +} + +impl RectangularSelector { + pub fn new(ctx: &mut EventCtx, region: Option) -> Box> { + Box::new(RectangularSelector { + panel: Panel::new(Widget::col(vec![ + Widget::row(vec![ + Line("Select a rectangular region") + .small_heading() + .into_widget(ctx), + ctx.style().btn_close_widget(ctx), + ]), + // TODO Key style + "Hold control, then click and drag to draw".text_widget(ctx), + ])) + .aligned(HorizontalAlignment::Right, VerticalAlignment::Top) + .build(ctx), + region, + corners: None, + }) + } +} + +impl State for RectangularSelector { + fn event(&mut self, ctx: &mut EventCtx, _: &mut App) -> Transition { + if ctx.is_key_down(Key::LeftControl) { + if ctx.input.left_mouse_button_released() { + if let Some((_, _, ref mut dragging)) = self.corners { + *dragging = false; + } + } + if let Some(pt) = ctx.canvas.get_cursor_in_map_space() { + if ctx.input.left_mouse_button_pressed() { + self.corners = Some((pt, pt, true)); + } + if let Some((_, ref mut pt2, dragging)) = self.corners { + if dragging { + *pt2 = pt; + } + } + } + } else { + ctx.canvas_movement(); + } + + match self.panel.event(ctx) { + Outcome::Clicked(x) => match x.as_ref() { + "close" => { + return Transition::Pop; + } + _ => unreachable!(), + }, + _ => {} + } + + Transition::Keep + } + + fn draw(&self, g: &mut GfxCtx, _: &App) { + self.panel.draw(g); + if let Some(p) = self.region.clone() { + g.draw_polygon(Color::BLUE.alpha(0.5), p); + } + if let Some((pt1, pt2, _)) = self.corners { + if let Some(p) = Polygon::rectangle_two_corners(pt1, pt2) { + g.draw_polygon(Color::RED.alpha(0.5), p); + } + } + } +} diff --git a/game/src/sandbox/dashboards/trip_table.rs b/game/src/sandbox/dashboards/trip_table.rs index e5a47e8cac..86efb6db29 100644 --- a/game/src/sandbox/dashboards/trip_table.rs +++ b/game/src/sandbox/dashboards/trip_table.rs @@ -9,9 +9,10 @@ use widgetry::{ }; use super::generic_trip_table::{open_trip_transition, preview_trip}; +use super::selector::RectangularSelector; +use super::DashTab; use crate::app::{App, Transition}; use crate::common::{checkbox_per_mode, cmp_duration_shorter, color_for_mode}; -use crate::sandbox::dashboards::DashTab; pub struct TripTable { tab: DashTab, @@ -136,6 +137,10 @@ impl State for TripTable { return Transition::Pop; } else if self.table_tabs.handle_action(ctx, &x, &mut self.panel) { // if true, tabs handled the action + } else if x == "filter starts" { + return Transition::Push(RectangularSelector::new(ctx, None)); + } else if x == "filter ends" { + return Transition::Push(RectangularSelector::new(ctx, None)); } else { unreachable!("unhandled action: {}", x) } @@ -313,6 +318,8 @@ fn make_table_finished_trips(app: &App) -> Table { Widget::row(vec![ Toggle::switch(ctx, "starting off-map", None, state.off_map_starts), Toggle::switch(ctx, "ending off-map", None, state.off_map_ends), + ctx.style().btn_plain.text("filter starts").build_def(ctx), + ctx.style().btn_plain.text("filter ends").build_def(ctx), if app.primary.has_modified_trips { Toggle::switch( ctx,