mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-27 15:03:20 +03:00
Now make the browse shortcut controls appear.
It works, mvp. Lots of code cleanup / performance / edge cases needing cleanup though.
This commit is contained in:
parent
dd99afddc6
commit
8e94eeeb17
@ -1,6 +1,6 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use abstutil::{Counter, Timer};
|
||||
use abstutil::Counter;
|
||||
use geom::Distance;
|
||||
use map_gui::tools::{ColorNetwork, DrawRoadLabels};
|
||||
use synthpop::Scenario;
|
||||
@ -123,7 +123,7 @@ impl State<App> for BrowseNeighbourhoods {
|
||||
} else if x == "style" {
|
||||
app.session.draw_neighbourhood_style = self.left_panel.dropdown_value("style");
|
||||
|
||||
ctx.loading_screen("change style", |ctx, timer| {
|
||||
ctx.loading_screen("change style", |ctx, _| {
|
||||
self.world = make_world(ctx, app);
|
||||
self.draw_over_roads = draw_over_roads(ctx, app);
|
||||
});
|
||||
|
@ -87,7 +87,6 @@ impl Viewer {
|
||||
app,
|
||||
Tab::Connectivity,
|
||||
&self.top_panel,
|
||||
&self.neighbourhood,
|
||||
Widget::col(vec![
|
||||
format!(
|
||||
"Neighbourhood area: {}",
|
||||
@ -189,7 +188,7 @@ impl State<App> for Viewer {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match self.edit.event(ctx, app) {
|
||||
match self.edit.event(ctx, app, &self.neighbourhood) {
|
||||
EditOutcome::Nothing => {}
|
||||
EditOutcome::Recalculate => {
|
||||
self.neighbourhood = Neighbourhood::new(ctx, app, self.neighbourhood.id);
|
||||
|
@ -62,12 +62,11 @@ impl Tab {
|
||||
}
|
||||
|
||||
// TODO This will replace Tab soon
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum EditMode {
|
||||
Filters,
|
||||
Oneways,
|
||||
// Is a road clicked on right now?
|
||||
Shortcuts(Option<RoadID>),
|
||||
Shortcuts(Option<shortcuts::FocusedRoad>),
|
||||
}
|
||||
|
||||
pub struct EditNeighbourhood {
|
||||
@ -108,7 +107,7 @@ impl EditNeighbourhood {
|
||||
|
||||
pub fn new(ctx: &mut EventCtx, app: &App, neighbourhood: &Neighbourhood) -> Self {
|
||||
Self {
|
||||
world: match app.session.edit_mode {
|
||||
world: match &app.session.edit_mode {
|
||||
EditMode::Filters => filters::make_world(ctx, app, neighbourhood),
|
||||
EditMode::Oneways => one_ways::make_world(ctx, app, neighbourhood),
|
||||
EditMode::Shortcuts(focus) => shortcuts::make_world(ctx, app, neighbourhood, focus),
|
||||
@ -122,7 +121,6 @@ impl EditNeighbourhood {
|
||||
app: &App,
|
||||
tab: Tab,
|
||||
top_panel: &Panel,
|
||||
neighbourhood: &Neighbourhood,
|
||||
per_tab_contents: Widget,
|
||||
) -> PanelBuilder {
|
||||
let contents = Widget::col(vec![
|
||||
@ -131,11 +129,11 @@ impl EditNeighbourhood {
|
||||
Line("Editing neighbourhood")
|
||||
.small_heading()
|
||||
.into_widget(ctx),
|
||||
edit_mode(ctx, app.session.edit_mode),
|
||||
edit_mode(ctx, &app.session.edit_mode),
|
||||
match app.session.edit_mode {
|
||||
EditMode::Filters => filters::widget(ctx, app),
|
||||
EditMode::Oneways => one_ways::widget(ctx),
|
||||
EditMode::Shortcuts(focus) => shortcuts::widget(ctx, app, neighbourhood, focus),
|
||||
EditMode::Shortcuts(ref focus) => shortcuts::widget(ctx, app, focus.as_ref()),
|
||||
}
|
||||
.section(ctx),
|
||||
tab.make_buttons(ctx, app),
|
||||
@ -145,12 +143,17 @@ impl EditNeighbourhood {
|
||||
crate::components::LeftPanel::builder(ctx, top_panel, contents)
|
||||
}
|
||||
|
||||
pub fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> EditOutcome {
|
||||
pub fn event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
app: &mut App,
|
||||
neighbourhood: &Neighbourhood,
|
||||
) -> EditOutcome {
|
||||
let outcome = self.world.event(ctx);
|
||||
let outcome = match app.session.edit_mode {
|
||||
EditMode::Filters => filters::handle_world_outcome(ctx, app, outcome),
|
||||
EditMode::Oneways => one_ways::handle_world_outcome(ctx, app, outcome),
|
||||
EditMode::Shortcuts(_) => shortcuts::handle_world_outcome(ctx, app, outcome),
|
||||
EditMode::Shortcuts(_) => shortcuts::handle_world_outcome(app, outcome, neighbourhood),
|
||||
};
|
||||
if matches!(outcome, EditOutcome::Transition(_)) {
|
||||
self.world.hack_unset_hovering();
|
||||
@ -213,16 +216,28 @@ impl EditNeighbourhood {
|
||||
app.session.edit_mode = EditMode::Shortcuts(None);
|
||||
Some(Transition::Recreate)
|
||||
}
|
||||
"previous shortcut" => {
|
||||
if let EditMode::Shortcuts(Some(ref mut focus)) = app.session.edit_mode {
|
||||
focus.current_idx -= 1;
|
||||
}
|
||||
Some(Transition::Recreate)
|
||||
}
|
||||
"next shortcut" => {
|
||||
if let EditMode::Shortcuts(Some(ref mut focus)) = app.session.edit_mode {
|
||||
focus.current_idx += 1;
|
||||
}
|
||||
Some(Transition::Recreate)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn edit_mode(ctx: &mut EventCtx, edit_mode: EditMode) -> Widget {
|
||||
fn edit_mode(ctx: &mut EventCtx, edit_mode: &EditMode) -> Widget {
|
||||
let mut row = Vec::new();
|
||||
for (label, is_current) in [
|
||||
("Filters", edit_mode == EditMode::Filters),
|
||||
("One-ways", edit_mode == EditMode::Oneways),
|
||||
("Filters", matches!(edit_mode, EditMode::Filters)),
|
||||
("One-ways", matches!(edit_mode, EditMode::Oneways)),
|
||||
("Shortcuts", matches!(edit_mode, EditMode::Shortcuts(_))),
|
||||
] {
|
||||
row.push(
|
||||
|
@ -1,24 +1,44 @@
|
||||
use geom::Distance;
|
||||
use map_model::RoadID;
|
||||
use widgetry::mapspace::{World, WorldOutcome};
|
||||
use widgetry::{Color, EventCtx, Text, TextExt, Widget};
|
||||
use map_model::{Path, RoadID, NORMAL_LANE_THICKNESS};
|
||||
use widgetry::mapspace::{ToggleZoomed, World, WorldOutcome};
|
||||
use widgetry::{Color, EventCtx, Key, Line, Text, TextExt, Widget};
|
||||
|
||||
use super::{EditMode, EditOutcome, Obj};
|
||||
use crate::{colors, App, Neighbourhood};
|
||||
|
||||
pub fn widget(
|
||||
ctx: &mut EventCtx,
|
||||
app: &App,
|
||||
neighbourhood: &Neighbourhood,
|
||||
focus: Option<RoadID>,
|
||||
) -> Widget {
|
||||
pub struct FocusedRoad {
|
||||
pub r: RoadID,
|
||||
pub paths: Vec<Path>,
|
||||
pub current_idx: usize,
|
||||
}
|
||||
|
||||
pub fn widget(ctx: &mut EventCtx, app: &App, focus: Option<&FocusedRoad>) -> Widget {
|
||||
match focus {
|
||||
Some(r) => Widget::col(vec![format!(
|
||||
"{} possible shortcuts cross {}",
|
||||
neighbourhood.shortcuts.count_per_road.get(r),
|
||||
app.map.get_r(r).get_name(app.opts.language.as_ref()),
|
||||
)
|
||||
.text_widget(ctx)]),
|
||||
Some(focus) => Widget::col(vec![
|
||||
format!(
|
||||
"{} possible shortcuts cross {}",
|
||||
focus.paths.len(),
|
||||
app.map.get_r(focus.r).get_name(app.opts.language.as_ref()),
|
||||
)
|
||||
.text_widget(ctx),
|
||||
Widget::row(vec![
|
||||
ctx.style()
|
||||
.btn_prev()
|
||||
.disabled(focus.current_idx == 0)
|
||||
.hotkey(Key::LeftArrow)
|
||||
.build_widget(ctx, "previous shortcut"),
|
||||
Text::from(
|
||||
Line(format!("{}/{}", focus.current_idx + 1, focus.paths.len())).secondary(),
|
||||
)
|
||||
.into_widget(ctx)
|
||||
.centered_vert(),
|
||||
ctx.style()
|
||||
.btn_next()
|
||||
.disabled(focus.current_idx == focus.paths.len() - 1)
|
||||
.hotkey(Key::RightArrow)
|
||||
.build_widget(ctx, "next shortcut"),
|
||||
]),
|
||||
]),
|
||||
None => Widget::col(vec![
|
||||
"Click a road to view shortcuts through it".text_widget(ctx)
|
||||
]),
|
||||
@ -29,14 +49,15 @@ pub fn make_world(
|
||||
ctx: &mut EventCtx,
|
||||
app: &App,
|
||||
neighbourhood: &Neighbourhood,
|
||||
focus: Option<RoadID>,
|
||||
focus: &Option<FocusedRoad>,
|
||||
) -> World<Obj> {
|
||||
let map = &app.map;
|
||||
let mut world = World::bounded(map.get_bounds());
|
||||
let focused_road = focus.as_ref().map(|f| f.r);
|
||||
|
||||
for r in &neighbourhood.orig_perimeter.interior {
|
||||
let road = map.get_r(*r);
|
||||
if focus == Some(*r) {
|
||||
if focused_road == Some(*r) {
|
||||
world
|
||||
.add(Obj::InteriorRoad(*r))
|
||||
.hitbox(road.get_thick_polygon())
|
||||
@ -58,20 +79,48 @@ pub fn make_world(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref focus) = focus {
|
||||
let mut draw_path = ToggleZoomed::builder();
|
||||
if let Some(pl) = focus.paths[focus.current_idx].trace(&app.map) {
|
||||
let color = colors::SHORTCUT_PATH;
|
||||
let shape = pl.make_polygons(3.0 * NORMAL_LANE_THICKNESS);
|
||||
draw_path.unzoomed.push(color.alpha(0.8), shape.clone());
|
||||
draw_path.zoomed.push(color.alpha(0.5), shape);
|
||||
|
||||
draw_path
|
||||
.unzoomed
|
||||
.append(map_gui::tools::start_marker(ctx, pl.first_pt(), 2.0));
|
||||
draw_path
|
||||
.zoomed
|
||||
.append(map_gui::tools::start_marker(ctx, pl.first_pt(), 0.5));
|
||||
|
||||
draw_path
|
||||
.unzoomed
|
||||
.append(map_gui::tools::goal_marker(ctx, pl.last_pt(), 2.0));
|
||||
draw_path
|
||||
.zoomed
|
||||
.append(map_gui::tools::goal_marker(ctx, pl.last_pt(), 0.5));
|
||||
}
|
||||
world.draw_master_batch(ctx, draw_path);
|
||||
}
|
||||
|
||||
world.initialize_hover(ctx);
|
||||
world
|
||||
}
|
||||
|
||||
pub fn handle_world_outcome(
|
||||
ctx: &mut EventCtx,
|
||||
app: &mut App,
|
||||
outcome: WorldOutcome<Obj>,
|
||||
neighbourhood: &Neighbourhood,
|
||||
) -> EditOutcome {
|
||||
match outcome {
|
||||
WorldOutcome::ClickedObject(Obj::InteriorRoad(r)) => {
|
||||
app.session.edit_mode = EditMode::Shortcuts(Some(r));
|
||||
// TODO make the scroller thing
|
||||
|
||||
// TODO handle 0 shortcut case
|
||||
app.session.edit_mode = EditMode::Shortcuts(Some(FocusedRoad {
|
||||
r,
|
||||
paths: neighbourhood.shortcuts.subset(r),
|
||||
current_idx: 0,
|
||||
}));
|
||||
EditOutcome::Recalculate
|
||||
}
|
||||
WorldOutcome::ClickedFreeSpace(_) => {
|
||||
|
@ -66,7 +66,6 @@ impl BrowseShortcuts {
|
||||
app,
|
||||
Tab::Shortcuts,
|
||||
&self.top_panel,
|
||||
&self.neighbourhood,
|
||||
percentage_bar(
|
||||
ctx,
|
||||
Text::from(Line(format!(
|
||||
@ -92,7 +91,6 @@ impl BrowseShortcuts {
|
||||
app,
|
||||
Tab::Shortcuts,
|
||||
&self.top_panel,
|
||||
&self.neighbourhood,
|
||||
Widget::col(vec![
|
||||
percentage_bar(
|
||||
ctx,
|
||||
@ -211,7 +209,7 @@ impl State<App> for BrowseShortcuts {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match self.edit.event(ctx, app) {
|
||||
match self.edit.event(ctx, app, &self.neighbourhood) {
|
||||
EditOutcome::Nothing => {}
|
||||
EditOutcome::Recalculate => {
|
||||
// Reset state, but if possible, preserve the current individual shortcut.
|
||||
|
@ -36,6 +36,14 @@ impl Shortcuts {
|
||||
let total_streets = neighbourhood.orig_perimeter.interior.len();
|
||||
(quiet_streets, total_streets)
|
||||
}
|
||||
|
||||
pub fn subset(&self, r: RoadID) -> Vec<Path> {
|
||||
self.paths
|
||||
.iter()
|
||||
.filter(|path| path.crosses_road(r))
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_shortcuts(app: &App, neighbourhood: &Neighbourhood, timer: &mut Timer) -> Shortcuts {
|
||||
|
@ -8,8 +8,8 @@ use abstutil::prettyprint_usize;
|
||||
use geom::{Distance, Duration, PolyLine, Polygon, Ring, Speed, EPSILON_DIST};
|
||||
|
||||
use crate::{
|
||||
BuildingID, DirectedRoadID, LaneID, Map, PathConstraints, Position, Traversable, TurnID,
|
||||
UberTurn,
|
||||
BuildingID, DirectedRoadID, LaneID, Map, PathConstraints, Position, RoadID, Traversable,
|
||||
TurnID, UberTurn,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
@ -558,6 +558,17 @@ impl Path {
|
||||
dist_along
|
||||
);
|
||||
}
|
||||
|
||||
pub fn crosses_road(&self, r: RoadID) -> bool {
|
||||
for step in &self.steps {
|
||||
if let PathStep::Lane(l) | PathStep::ContraflowLane(l) = step {
|
||||
if l.road == r {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||
|
Loading…
Reference in New Issue
Block a user