mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 07:25:47 +03:00
Start a UI with some sliders for tuning existing params of route cost functions. No effect yet. #494
This commit is contained in:
parent
35f2beaa76
commit
eebe7a098a
@ -2,8 +2,8 @@ use map_gui::ID;
|
||||
use map_model::NORMAL_LANE_THICKNESS;
|
||||
use sim::{TripEndpoint, TripMode};
|
||||
use widgetry::{
|
||||
Choice, Color, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Line, Outcome,
|
||||
Panel, State, StyledButtons, TextExt, VerticalAlignment, Widget,
|
||||
Color, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Line, Outcome, Panel,
|
||||
Spinner, State, StyledButtons, TextExt, VerticalAlignment, Widget,
|
||||
};
|
||||
|
||||
use crate::app::{App, Transition};
|
||||
@ -26,36 +26,41 @@ impl RouteExplorer {
|
||||
Line("Route explorer").small_heading().draw(ctx),
|
||||
ctx.style().btn_close_widget(ctx),
|
||||
]),
|
||||
Widget::row(vec![
|
||||
"Type of trip:".draw_text(ctx),
|
||||
Widget::dropdown(
|
||||
ctx,
|
||||
"mode",
|
||||
TripMode::Drive,
|
||||
TripMode::all()
|
||||
.into_iter()
|
||||
.map(|m| Choice::new(m.ongoing_verb(), m))
|
||||
.collect(),
|
||||
),
|
||||
]),
|
||||
profile_to_controls(ctx, &RoutingProfile::default_biking()).named("profile"),
|
||||
]))
|
||||
.aligned(HorizontalAlignment::Right, VerticalAlignment::Top)
|
||||
.build(ctx),
|
||||
})
|
||||
}
|
||||
|
||||
fn controls_to_profile(&self) -> RoutingProfile {
|
||||
if !self.panel.is_button_enabled("cars") {
|
||||
return RoutingProfile::Driving;
|
||||
}
|
||||
if !self.panel.is_button_enabled("pedestrians") {
|
||||
return RoutingProfile::Walking;
|
||||
}
|
||||
RoutingProfile::Biking {
|
||||
bike_lane_penalty: self.panel.spinner("bike lane penalty") as f64 / 10.0,
|
||||
bus_lane_penalty: self.panel.spinner("bus lane penalty") as f64 / 10.0,
|
||||
driving_lane_penalty: self.panel.spinner("driving lane penalty") as f64 / 10.0,
|
||||
}
|
||||
}
|
||||
|
||||
fn recalc_paths(&mut self, ctx: &mut EventCtx, app: &App) {
|
||||
let mode = match self.controls_to_profile() {
|
||||
RoutingProfile::Driving => TripMode::Drive,
|
||||
RoutingProfile::Walking => TripMode::Walk,
|
||||
RoutingProfile::Biking { .. } => TripMode::Bike,
|
||||
};
|
||||
|
||||
if let Some((ref goal, _, ref mut preview)) = self.goal {
|
||||
*preview = Drawable::empty(ctx);
|
||||
if let Some(polygon) = TripEndpoint::path_req(
|
||||
self.start.clone(),
|
||||
goal.clone(),
|
||||
self.panel.dropdown_value("mode"),
|
||||
&app.primary.map,
|
||||
)
|
||||
.and_then(|req| app.primary.map.pathfind(req).ok())
|
||||
.and_then(|path| path.trace(&app.primary.map))
|
||||
.map(|pl| pl.make_polygons(NORMAL_LANE_THICKNESS))
|
||||
if let Some(polygon) =
|
||||
TripEndpoint::path_req(self.start.clone(), goal.clone(), mode, &app.primary.map)
|
||||
.and_then(|req| app.primary.map.pathfind(req).ok())
|
||||
.and_then(|path| path.trace(&app.primary.map))
|
||||
.map(|pl| pl.make_polygons(NORMAL_LANE_THICKNESS))
|
||||
{
|
||||
*preview = GeomBatch::from(vec![(Color::PURPLE, polygon)]).upload(ctx);
|
||||
}
|
||||
@ -72,10 +77,24 @@ impl State<App> for RouteExplorer {
|
||||
"close" => {
|
||||
return Transition::Pop;
|
||||
}
|
||||
"bikes" => {
|
||||
let controls = profile_to_controls(ctx, &RoutingProfile::default_biking());
|
||||
self.panel.replace(ctx, "profile", controls);
|
||||
self.recalc_paths(ctx, app);
|
||||
}
|
||||
"cars" => {
|
||||
let controls = profile_to_controls(ctx, &RoutingProfile::Driving);
|
||||
self.panel.replace(ctx, "profile", controls);
|
||||
self.recalc_paths(ctx, app);
|
||||
}
|
||||
"pedestrians" => {
|
||||
let controls = profile_to_controls(ctx, &RoutingProfile::Walking);
|
||||
self.panel.replace(ctx, "profile", controls);
|
||||
self.recalc_paths(ctx, app);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Outcome::Changed => {
|
||||
// Mode choice changed
|
||||
self.recalc_paths(ctx, app);
|
||||
}
|
||||
_ => {}
|
||||
@ -158,3 +177,68 @@ impl State<App> for RouteExplorer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Move to map_model
|
||||
// TODO Not sure an enum makes sense, based on how we're still going to be toggling based on
|
||||
// PathConstraints.
|
||||
enum RoutingProfile {
|
||||
Driving,
|
||||
Biking {
|
||||
bike_lane_penalty: f64,
|
||||
bus_lane_penalty: f64,
|
||||
driving_lane_penalty: f64,
|
||||
},
|
||||
Walking,
|
||||
}
|
||||
|
||||
impl RoutingProfile {
|
||||
fn default_biking() -> RoutingProfile {
|
||||
RoutingProfile::Biking {
|
||||
bike_lane_penalty: 1.0,
|
||||
bus_lane_penalty: 1.1,
|
||||
driving_lane_penalty: 1.5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn profile_to_controls(ctx: &mut EventCtx, profile: &RoutingProfile) -> Widget {
|
||||
let mut rows = vec![Widget::custom_row(vec![
|
||||
ctx.style()
|
||||
.btn_plain_light_icon("system/assets/meters/bike.svg")
|
||||
.disabled(matches!(profile, RoutingProfile::Biking { .. }))
|
||||
.build_widget(ctx, "bikes"),
|
||||
ctx.style()
|
||||
.btn_plain_light_icon("system/assets/meters/car.svg")
|
||||
.disabled(matches!(profile, RoutingProfile::Driving))
|
||||
.build_widget(ctx, "cars"),
|
||||
ctx.style()
|
||||
.btn_plain_light_icon("system/assets/meters/pedestrian.svg")
|
||||
.disabled(matches!(profile, RoutingProfile::Walking))
|
||||
.build_widget(ctx, "pedestrians"),
|
||||
])
|
||||
.evenly_spaced()];
|
||||
if let RoutingProfile::Biking {
|
||||
bike_lane_penalty,
|
||||
bus_lane_penalty,
|
||||
driving_lane_penalty,
|
||||
} = profile
|
||||
{
|
||||
// TODO Spinners that natively understand a floating point range with a given precision
|
||||
rows.push(Widget::row(vec![
|
||||
"Bike lane penalty:".draw_text(ctx).margin_right(20),
|
||||
Spinner::new(ctx, (0, 20), (*bike_lane_penalty * 10.0) as isize)
|
||||
.named("bike lane penalty"),
|
||||
]));
|
||||
rows.push(Widget::row(vec![
|
||||
"Bus lane penalty:".draw_text(ctx).margin_right(20),
|
||||
Spinner::new(ctx, (0, 20), (*bus_lane_penalty * 10.0) as isize)
|
||||
.named("bus lane penalty"),
|
||||
]));
|
||||
rows.push(Widget::row(vec![
|
||||
"Driving lane penalty:".draw_text(ctx).margin_right(20),
|
||||
Spinner::new(ctx, (0, 20), (*driving_lane_penalty * 10.0) as isize)
|
||||
.named("driving lane penalty"),
|
||||
]));
|
||||
}
|
||||
Widget::col(rows)
|
||||
}
|
||||
|
@ -64,6 +64,10 @@ impl Button {
|
||||
dims,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
!self.is_disabled
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for Button {
|
||||
|
@ -10,8 +10,8 @@ use geom::{Percent, Polygon};
|
||||
use crate::widgets::slider;
|
||||
use crate::widgets::Container;
|
||||
use crate::{
|
||||
Autocomplete, Checkbox, Color, Dropdown, EventCtx, GfxCtx, HorizontalAlignment, Menu, Outcome,
|
||||
PersistentSplit, ScreenDims, ScreenPt, ScreenRectangle, Slider, Spinner, TextBox,
|
||||
Autocomplete, Button, Checkbox, Color, Dropdown, EventCtx, GfxCtx, HorizontalAlignment, Menu,
|
||||
Outcome, PersistentSplit, ScreenDims, ScreenPt, ScreenRectangle, Slider, Spinner, TextBox,
|
||||
VerticalAlignment, Widget, WidgetImpl, WidgetOutput,
|
||||
};
|
||||
|
||||
@ -403,6 +403,10 @@ impl Panel {
|
||||
self.find::<Autocomplete<T>>(name).final_value()
|
||||
}
|
||||
|
||||
pub fn is_button_enabled(&self, name: &str) -> bool {
|
||||
self.find::<Button>(name).is_enabled()
|
||||
}
|
||||
|
||||
pub fn maybe_find(&self, name: &str) -> Option<&Widget> {
|
||||
self.top_level.find(name)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user