Skip to content

Commit

Permalink
Move overall LTN navigation into the top bar. This also introduces the
Browse files Browse the repository at this point in the history
concept of the "currently edited area". #951
  • Loading branch information
dabreegster committed Sep 6, 2022
1 parent 2dc4fd0 commit 2712d89
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 115 deletions.
5 changes: 5 additions & 0 deletions apps/ltn/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ pub struct PerMap {
pub partitioning: Partitioning,
pub edits: Edits,

// The last edited neighbourhood
pub current_neighbourhood: Option<NeighbourhoodID>,

// These capture modal filters that exist in the map already. Whenever we pathfind in this app
// in the "before changes" case, we have to use these. Do NOT use the map's built-in
// pathfinder. (https://github.com/a-b-street/abstreet/issues/852 would make this more clear)
Expand Down Expand Up @@ -76,6 +79,8 @@ impl PerMap {
partitioning: Partitioning::empty(),
edits: Edits::default(),

current_neighbourhood: None,

routing_params_before_changes: RoutingParams::default(),
alt_proposals: crate::save::AltProposals::new(),
impact: crate::impact::Impact::empty(ctx),
Expand Down
42 changes: 2 additions & 40 deletions apps/ltn/src/browse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use abstutil::Counter;
use map_gui::tools::{ColorNetwork, DrawSimpleRoadLabels};
use widgetry::mapspace::{World, WorldOutcome};
use widgetry::{
Choice, Color, DrawBaselayer, Drawable, EventCtx, GeomBatch, GfxCtx, Key, Line, Outcome, Panel,
Choice, Color, DrawBaselayer, Drawable, EventCtx, GeomBatch, GfxCtx, Line, Outcome, Panel,
State, TextExt, Toggle, Widget,
};

Expand Down Expand Up @@ -43,13 +43,12 @@ impl BrowseNeighbourhoods {
(make_world(ctx, app), draw_over_roads(ctx, app))
});

let top_panel = crate::components::TopPanel::panel(ctx, app);
let top_panel = crate::components::TopPanel::panel(ctx, app, Mode::BrowseNeighbourhoods);
let left_panel = crate::components::LeftPanel::builder(
ctx,
&top_panel,
Widget::col(vec![
app.per_map.alt_proposals.to_widget(ctx, app),
crate::route_planner::RoutePlanner::button(ctx),
Toggle::checkbox(ctx, "Advanced features", None, app.opts.dev),
advanced_panel(ctx, app),
]),
Expand All @@ -64,14 +63,6 @@ impl BrowseNeighbourhoods {
draw_boundary_roads: draw_boundary_roads(ctx, app),
})
}

pub fn button(ctx: &EventCtx, app: &App) -> Widget {
ctx.style()
.btn_back("Browse neighbourhoods")
.hotkey(Key::Escape)
.build_def(ctx)
.hide(app.per_map.consultation.is_some())
}
}

impl State<App> for BrowseNeighbourhoods {
Expand All @@ -88,14 +79,6 @@ impl State<App> for BrowseNeighbourhoods {
}
match self.left_panel.event(ctx) {
Outcome::Clicked(x) => match x.as_ref() {
"Calculate" | "Show impact" => {
return Transition::Push(crate::impact::ShowResults::new_state(ctx, app));
}
"Plan a route" => {
return Transition::Push(crate::route_planner::RoutePlanner::new_state(
ctx, app,
));
}
"Automatically place filters" => {
ctx.loading_screen("automatically filter all neighbourhoods", |ctx, timer| {
timer.start_iter(
Expand Down Expand Up @@ -299,22 +282,6 @@ pub enum Style {
Shortcuts,
}

fn impact_widget(ctx: &EventCtx, app: &App) -> Widget {
if &app.per_map.impact.map == app.per_map.map.get_name()
&& app.per_map.impact.change_key == app.per_map.edits.get_change_key()
{
// Nothing to calculate!
return ctx.style().btn_outline.text("Show impact").build_def(ctx);
}

Widget::col(vec![
Line("The app may freeze while calculating this.")
.small()
.into_widget(ctx),
ctx.style().btn_outline.text("Calculate").build_def(ctx),
])
}

fn help() -> Vec<&'static str> {
vec![
"Basic map navigation: click and drag to pan, swipe or scroll to zoom",
Expand Down Expand Up @@ -344,11 +311,6 @@ fn advanced_panel(ctx: &EventCtx, app: &App) -> Widget {
),
])])
.section(ctx),
Widget::col(vec![
"Predict proposal impact".text_widget(ctx),
impact_widget(ctx, app),
])
.section(ctx),
Widget::col(vec![
ctx.style()
.btn_outline
Expand Down
10 changes: 1 addition & 9 deletions apps/ltn/src/components/layers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use widgetry::{
Widget,
};

use crate::components::Mode;
use crate::{colors, App, FilterType, Transition};

// Partly copied from ungap/layers.s
Expand Down Expand Up @@ -181,15 +182,6 @@ fn zoom_enabled_cache_key(ctx: &EventCtx) -> (bool, bool) {
(ctx.canvas.is_max_zoom(), ctx.canvas.is_min_zoom())
}

#[derive(PartialEq)]
pub enum Mode {
BrowseNeighbourhoods,
ModifyNeighbourhood,
SelectBoundary,
RoutePlanner,
Impact,
}

impl Mode {
fn legend(&self, ctx: &mut EventCtx, cs: &ColorScheme) -> Widget {
// TODO Light/dark buildings? Traffic signals?
Expand Down
11 changes: 10 additions & 1 deletion apps/ltn/src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ mod layers;
mod left_panel;
mod top_panel;

pub use layers::{Layers, Mode};
pub use layers::Layers;
pub use left_panel::LeftPanel;
pub use top_panel::TopPanel;

#[derive(PartialEq)]
pub enum Mode {
BrowseNeighbourhoods,
ModifyNeighbourhood,
SelectBoundary,
RoutePlanner,
Impact,
}
98 changes: 94 additions & 4 deletions apps/ltn/src/components/top_panel.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,73 @@
use geom::CornerRadii;
use widgetry::tools::ChooseSomething;
use widgetry::tools::PopupMsg;
use widgetry::{
lctrl, CornerRounding, EventCtx, HorizontalAlignment, Key, Line, Outcome, Panel, PanelDims,
VerticalAlignment, Widget,
lctrl, Choice, Color, CornerRounding, EventCtx, HorizontalAlignment, Key, Line, Outcome, Panel,
PanelDims, VerticalAlignment, Widget,
};

use crate::components::Mode;
use crate::{App, BrowseNeighbourhoods, Transition};

pub struct TopPanel;

impl TopPanel {
pub fn panel(ctx: &mut EventCtx, app: &App) -> Panel {
pub fn panel(ctx: &mut EventCtx, app: &App, mode: Mode) -> Panel {
let consultation = app.per_map.consultation.is_some();

// While we're adjusting a boundary, it's weird to navigate away without explicitly
// confirming or reverting the edits. Just remove the nav bar entirely.
let navbar = if mode != Mode::SelectBoundary {
Widget::row(vec![
ctx.style()
.btn_outline
.text("Pick area")
.disabled(
mode == Mode::BrowseNeighbourhoods || app.per_map.consultation.is_some(),
)
.maybe_disabled_tooltip(if mode == Mode::BrowseNeighbourhoods {
None
} else {
Some("This consultation is only about the current area")
})
.build_def(ctx),
ctx.style()
.btn_outline
.text("Design LTN")
.disabled(
mode == Mode::ModifyNeighbourhood
|| app.per_map.current_neighbourhood.is_none(),
)
.maybe_disabled_tooltip(if mode == Mode::ModifyNeighbourhood {
None
} else {
Some("Pick an area first")
})
.build_def(ctx),
ctx.style()
.btn_outline
.text("Plan route")
.hotkey(Key::R)
.disabled(mode == Mode::RoutePlanner)
.build_def(ctx),
ctx.style()
.btn_outline
.text("Predict impact")
.disabled(mode == Mode::Impact || app.per_map.consultation.is_some())
.maybe_disabled_tooltip(if mode == Mode::Impact {
None
} else {
Some("Not supported here yet")
})
.build_def(ctx),
])
.centered_vert()
.padding(16)
.outline((5.0, Color::BLACK))
} else {
Widget::nothing()
};

Panel::new_builder(
Widget::row(vec![
map_gui::tools::home_btn(ctx),
Expand All @@ -33,6 +88,7 @@ impl TopPanel {
map_gui::tools::change_map_btn(ctx, app)
.centered_vert()
.hide(consultation),
navbar,
Widget::row(vec![
ctx.style()
.btn_plain
Expand Down Expand Up @@ -68,7 +124,7 @@ impl TopPanel {

pub fn event<F: Fn() -> Vec<&'static str>>(
ctx: &mut EventCtx,
app: &App,
app: &mut App,
panel: &mut Panel,
help: F,
) -> Option<Transition> {
Expand Down Expand Up @@ -113,10 +169,44 @@ impl TopPanel {
}
}))
}
"Pick area" => Some(Transition::Replace(BrowseNeighbourhoods::new_state(
ctx, app,
))),
"Design LTN" => Some(Transition::Replace(crate::connectivity::Viewer::new_state(
ctx,
app,
app.per_map.current_neighbourhood.unwrap(),
))),
"Plan route" => Some(Transition::Replace(
crate::route_planner::RoutePlanner::new_state(ctx, app),
)),
"Predict impact" => Some(launch_impact(ctx, app)),
_ => unreachable!(),
}
} else {
None
}
}
}

fn launch_impact(ctx: &mut EventCtx, app: &mut App) -> Transition {
if &app.per_map.impact.map == app.per_map.map.get_name()
&& app.per_map.impact.change_key == app.per_map.edits.get_change_key()
{
return Transition::Replace(crate::impact::ShowResults::new_state(ctx, app));
}

Transition::Push(ChooseSomething::new_state(ctx,
"Impact prediction is experimental. You have to interpret the results carefully. The app may also freeze while calculating this.",
Choice::strings(vec!["Never mind", "I understand the warnings. Predict impact!"]),
Box::new(|choice, ctx, app| {
if choice == "Never mind" {
Transition::Pop
} else {
Transition::Multi(vec![
Transition::Pop,
Transition::Replace(crate::impact::ShowResults::new_state(ctx, app)),
])
}
})))
}
10 changes: 8 additions & 2 deletions apps/ltn/src/connectivity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,17 @@ pub struct Viewer {
}

impl Viewer {
pub fn new_state(ctx: &mut EventCtx, app: &App, id: NeighbourhoodID) -> Box<dyn State<App>> {
pub fn new_state(
ctx: &mut EventCtx,
app: &mut App,
id: NeighbourhoodID,
) -> Box<dyn State<App>> {
app.per_map.current_neighbourhood = Some(id);

let neighbourhood = Neighbourhood::new(ctx, app, id);

let mut viewer = Viewer {
top_panel: crate::components::TopPanel::panel(ctx, app),
top_panel: crate::components::TopPanel::panel(ctx, app, Mode::ModifyNeighbourhood),
left_panel: Panel::empty(ctx),
neighbourhood,
draw_top_layer: Drawable::empty(ctx),
Expand Down
36 changes: 10 additions & 26 deletions apps/ltn/src/edit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ use widgetry::{
};

use crate::{
after_edit, colors, is_private, App, BrowseNeighbourhoods, FilterType, Neighbourhood,
RoadFilter, Transition,
after_edit, colors, is_private, App, FilterType, Neighbourhood, RoadFilter, Transition,
};

pub enum EditMode {
Expand Down Expand Up @@ -87,24 +86,18 @@ impl EditNeighbourhood {
) -> PanelBuilder {
let contents = Widget::col(vec![
app.per_map.alt_proposals.to_widget(ctx, app),
BrowseNeighbourhoods::button(ctx, app),
{
let mut row = Vec::new();
if app.per_map.consultation.is_none() {
row.push(
ctx.style()
.btn_outline
.text("Adjust boundary")
.hotkey(Key::B)
.build_def(ctx),
);
}
row.push(crate::route_planner::RoutePlanner::button(ctx));
Widget::row(row)
},
Line("Editing neighbourhood")
.small_heading()
.into_widget(ctx),
if app.per_map.consultation.is_none() {
ctx.style()
.btn_outline
.text("Adjust boundary")
.hotkey(Key::B)
.build_def(ctx)
} else {
Widget::nothing()
},
Widget::col(vec![
edit_mode(ctx, app),
match app.session.edit_mode {
Expand Down Expand Up @@ -170,12 +163,6 @@ impl EditNeighbourhood {
) -> EditOutcome {
let id = neighbourhood.id;
match action {
"Browse neighbourhoods" => {
// Recalculate the state to redraw any changed filters
EditOutcome::Transition(Transition::Replace(BrowseNeighbourhoods::new_state(
ctx, app,
)))
}
"Adjust boundary" => EditOutcome::Transition(Transition::Replace(
crate::select_boundary::SelectBoundary::new_state(ctx, app, id),
)),
Expand All @@ -190,9 +177,6 @@ impl EditNeighbourhood {
}
EditOutcome::Transition(Transition::Recreate)
}
"Plan a route" => EditOutcome::Transition(Transition::Push(
crate::route_planner::RoutePlanner::new_state(ctx, app),
)),
"Modal filter - no entry" => {
app.session.filter_type = FilterType::NoEntry;
app.session.edit_mode = EditMode::Filters;
Expand Down
Loading

0 comments on commit 2712d89

Please sign in to comment.