mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 01:15:12 +03:00
Create a dummy widget to stash generic state in a Panel, and use it to plumb around the rectangular regions to the trip table filters. #574
The filter still doesn't make use of the regions yet.
This commit is contained in:
parent
dff923b3e6
commit
c89e918fec
@ -1,3 +1,6 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use geom::{Polygon, Pt2D};
|
||||
use widgetry::{
|
||||
Color, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, State, TextExt,
|
||||
@ -9,12 +12,12 @@ use crate::app::{App, Transition};
|
||||
// TODO Lift to widgetry
|
||||
pub struct RectangularSelector {
|
||||
panel: Panel,
|
||||
region: Option<Polygon>,
|
||||
region: Rc<RefCell<Option<Polygon>>>,
|
||||
corners: Option<(Pt2D, Pt2D, bool)>,
|
||||
}
|
||||
|
||||
impl RectangularSelector {
|
||||
pub fn new(ctx: &mut EventCtx, region: Option<Polygon>) -> Box<dyn State<App>> {
|
||||
pub fn new(ctx: &mut EventCtx, region: Rc<RefCell<Option<Polygon>>>) -> Box<dyn State<App>> {
|
||||
Box::new(RectangularSelector {
|
||||
panel: Panel::new(Widget::col(vec![
|
||||
Widget::row(vec![
|
||||
@ -59,6 +62,14 @@ impl State<App> for RectangularSelector {
|
||||
match self.panel.event(ctx) {
|
||||
Outcome::Clicked(x) => match x.as_ref() {
|
||||
"close" => {
|
||||
// TODO Apply button?
|
||||
// TODO Some way to clear it
|
||||
if let Some(rect) = self
|
||||
.corners
|
||||
.and_then(|(pt1, pt2, _)| Polygon::rectangle_two_corners(pt1, pt2))
|
||||
{
|
||||
self.region.replace(Some(rect));
|
||||
}
|
||||
return Transition::Pop;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
@ -71,7 +82,7 @@ impl State<App> for RectangularSelector {
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, _: &App) {
|
||||
self.panel.draw(g);
|
||||
if let Some(p) = self.region.clone() {
|
||||
if let Some(p) = self.region.borrow().clone() {
|
||||
g.draw_polygon(Color::BLUE.alpha(0.5), p);
|
||||
}
|
||||
if let Some((pt1, pt2, _)) = self.corners {
|
||||
|
@ -1,11 +1,12 @@
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
|
||||
use abstutil::prettyprint_usize;
|
||||
use geom::{Duration, Time};
|
||||
use geom::{Duration, Polygon, Time};
|
||||
use sim::{TripEndpoint, TripID, TripMode};
|
||||
use widgetry::table::{Col, Filter, Table};
|
||||
use widgetry::{
|
||||
EventCtx, Filler, GfxCtx, Line, Outcome, Panel, State, TabController, Text, Toggle, Widget,
|
||||
EventCtx, Filler, GfxCtx, Line, Outcome, Panel, Stash, State, TabController, Text, Toggle,
|
||||
Widget,
|
||||
};
|
||||
|
||||
use super::generic_trip_table::{open_trip_transition, preview_trip};
|
||||
@ -138,9 +139,15 @@ impl State<App> for TripTable {
|
||||
} 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));
|
||||
return Transition::Push(RectangularSelector::new(
|
||||
ctx,
|
||||
self.panel.stash("starts_in"),
|
||||
));
|
||||
} else if x == "filter ends" {
|
||||
return Transition::Push(RectangularSelector::new(ctx, None));
|
||||
return Transition::Push(RectangularSelector::new(
|
||||
ctx,
|
||||
self.panel.stash("ends_in"),
|
||||
));
|
||||
} else {
|
||||
unreachable!("unhandled action: {}", x)
|
||||
}
|
||||
@ -217,6 +224,8 @@ struct Filters {
|
||||
modes: BTreeSet<TripMode>,
|
||||
off_map_starts: bool,
|
||||
off_map_ends: bool,
|
||||
starts_in: Option<Polygon>,
|
||||
ends_in: Option<Polygon>,
|
||||
unmodified_trips: bool,
|
||||
modified_trips: bool,
|
||||
uncapped_trips: bool,
|
||||
@ -307,6 +316,8 @@ fn make_table_finished_trips(app: &App) -> Table<App, FinishedTrip, Filters> {
|
||||
modes: TripMode::all().into_iter().collect(),
|
||||
off_map_starts: true,
|
||||
off_map_ends: true,
|
||||
starts_in: None,
|
||||
ends_in: None,
|
||||
unmodified_trips: true,
|
||||
modified_trips: true,
|
||||
uncapped_trips: true,
|
||||
@ -320,6 +331,8 @@ fn make_table_finished_trips(app: &App) -> Table<App, FinishedTrip, Filters> {
|
||||
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),
|
||||
Stash::new("starts_in", state.starts_in.clone()),
|
||||
Stash::new("ends_in", state.ends_in.clone()),
|
||||
if app.primary.has_modified_trips {
|
||||
Toggle::switch(
|
||||
ctx,
|
||||
@ -374,6 +387,8 @@ fn make_table_finished_trips(app: &App) -> Table<App, FinishedTrip, Filters> {
|
||||
modes,
|
||||
off_map_starts: panel.is_checked("starting off-map"),
|
||||
off_map_ends: panel.is_checked("ending off-map"),
|
||||
starts_in: panel.clone_stashed("starts_in"),
|
||||
ends_in: panel.clone_stashed("ends_in"),
|
||||
unmodified_trips: panel
|
||||
.maybe_is_checked("trips unmodified by experiment")
|
||||
.unwrap_or(true),
|
||||
@ -525,6 +540,8 @@ fn make_table_cancelled_trips(app: &App) -> Table<App, CancelledTrip, Filters> {
|
||||
modes: TripMode::all().into_iter().collect(),
|
||||
off_map_starts: true,
|
||||
off_map_ends: true,
|
||||
starts_in: None,
|
||||
ends_in: None,
|
||||
unmodified_trips: true,
|
||||
modified_trips: true,
|
||||
uncapped_trips: true,
|
||||
@ -550,6 +567,8 @@ fn make_table_cancelled_trips(app: &App) -> Table<App, CancelledTrip, Filters> {
|
||||
modes,
|
||||
off_map_starts: panel.is_checked("starting off-map"),
|
||||
off_map_ends: panel.is_checked("ending off-map"),
|
||||
starts_in: panel.clone_stashed("starts_in"),
|
||||
ends_in: panel.clone_stashed("ends_in"),
|
||||
unmodified_trips: true,
|
||||
modified_trips: true,
|
||||
uncapped_trips: true,
|
||||
@ -640,6 +659,8 @@ fn make_table_unfinished_trips(app: &App) -> Table<App, UnfinishedTrip, Filters>
|
||||
modes: TripMode::all().into_iter().collect(),
|
||||
off_map_starts: true,
|
||||
off_map_ends: true,
|
||||
starts_in: None,
|
||||
ends_in: None,
|
||||
unmodified_trips: true,
|
||||
modified_trips: true,
|
||||
uncapped_trips: true,
|
||||
@ -657,6 +678,8 @@ fn make_table_unfinished_trips(app: &App) -> Table<App, UnfinishedTrip, Filters>
|
||||
modes,
|
||||
off_map_starts: true,
|
||||
off_map_ends: true,
|
||||
starts_in: panel.clone_stashed("starts_in"),
|
||||
ends_in: panel.clone_stashed("ends_in"),
|
||||
unmodified_trips: true,
|
||||
modified_trips: true,
|
||||
uncapped_trips: true,
|
||||
|
@ -63,6 +63,7 @@ pub use crate::widgets::plots::{PlotOptions, Series};
|
||||
pub use crate::widgets::scatter_plot::ScatterPlot;
|
||||
pub use crate::widgets::slider::Slider;
|
||||
pub use crate::widgets::spinner::Spinner;
|
||||
pub use crate::widgets::stash::Stash;
|
||||
pub use crate::widgets::table;
|
||||
pub use crate::widgets::tabs::TabController;
|
||||
pub(crate) use crate::widgets::text_box::TextBox;
|
||||
|
@ -33,6 +33,7 @@ pub mod plots;
|
||||
pub mod scatter_plot;
|
||||
pub mod slider;
|
||||
pub mod spinner;
|
||||
pub mod stash;
|
||||
pub mod table;
|
||||
pub mod tabs;
|
||||
pub mod text_box;
|
||||
|
@ -1,4 +1,6 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashSet;
|
||||
use std::rc::Rc;
|
||||
|
||||
use stretch::geometry::Size;
|
||||
use stretch::node::Stretch;
|
||||
@ -11,8 +13,8 @@ use crate::widgets::slider;
|
||||
use crate::widgets::Container;
|
||||
use crate::{
|
||||
Autocomplete, Button, Color, Dropdown, EventCtx, GfxCtx, HorizontalAlignment, Menu, Outcome,
|
||||
PersistentSplit, ScreenDims, ScreenPt, ScreenRectangle, Slider, Spinner, TextBox, Toggle,
|
||||
VerticalAlignment, Widget, WidgetImpl, WidgetOutput,
|
||||
PersistentSplit, ScreenDims, ScreenPt, ScreenRectangle, Slider, Spinner, Stash, TextBox,
|
||||
Toggle, VerticalAlignment, Widget, WidgetImpl, WidgetOutput,
|
||||
};
|
||||
|
||||
pub struct Panel {
|
||||
@ -406,6 +408,16 @@ impl Panel {
|
||||
self.find::<Autocomplete<T>>(name).final_value()
|
||||
}
|
||||
|
||||
/// Grab a stashed value, with the ability to pass it around and modify it.
|
||||
pub fn stash<T: 'static>(&self, name: &str) -> Rc<RefCell<T>> {
|
||||
self.find::<Stash<T>>(name).get_value()
|
||||
}
|
||||
|
||||
/// Grab a stashed value and clone it.
|
||||
pub fn clone_stashed<T: 'static + Clone>(&self, name: &str) -> T {
|
||||
self.find::<Stash<T>>(name).get_value().borrow().clone()
|
||||
}
|
||||
|
||||
pub fn is_button_enabled(&self, name: &str) -> bool {
|
||||
self.find::<Button>(name).is_enabled()
|
||||
}
|
||||
|
34
widgetry/src/widgets/stash.rs
Normal file
34
widgetry/src/widgets/stash.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::{EventCtx, GfxCtx, ScreenDims, ScreenPt, Widget, WidgetImpl, WidgetOutput};
|
||||
|
||||
/// An invisible widget that stores some arbitrary data on the Panel. Users of the panel can read
|
||||
/// and write the value. This is one method for "returning" data when a State completes.
|
||||
pub struct Stash<T> {
|
||||
value: Rc<RefCell<T>>,
|
||||
}
|
||||
|
||||
impl<T: 'static> Stash<T> {
|
||||
pub fn new(name: &str, value: T) -> Widget {
|
||||
Widget::new(Box::new(Stash {
|
||||
value: Rc::new(RefCell::new(value)),
|
||||
}))
|
||||
.named(name)
|
||||
}
|
||||
|
||||
pub(crate) fn get_value(&self) -> Rc<RefCell<T>> {
|
||||
self.value.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> WidgetImpl for Stash<T> {
|
||||
fn get_dims(&self) -> ScreenDims {
|
||||
ScreenDims::square(0.0)
|
||||
}
|
||||
|
||||
fn set_pos(&mut self, _: ScreenPt) {}
|
||||
|
||||
fn event(&mut self, _: &mut EventCtx, _: &mut WidgetOutput) {}
|
||||
fn draw(&self, _: &mut GfxCtx) {}
|
||||
}
|
Loading…
Reference in New Issue
Block a user