mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-24 15:02:59 +03:00
Yuwen's new changelist UI (except for describing some of the changes in detail)
This commit is contained in:
parent
45876ed66b
commit
fff75fa5ba
@ -15,7 +15,7 @@ pub use self::stop_signs::StopSignEditor;
|
||||
pub use self::traffic_signals::TrafficSignalEditor;
|
||||
pub use self::validate::{check_blackholes, check_sidewalk_connectivity, try_change_lt};
|
||||
use crate::app::{App, ShowEverything};
|
||||
use crate::common::{tool_panel, CommonState, Warping};
|
||||
use crate::common::{tool_panel, ColorLegend, CommonState, Warping};
|
||||
use crate::debug::DebugMode;
|
||||
use crate::game::{ChooseSomething, PopupMsg, State, Transition};
|
||||
use crate::helpers::ID;
|
||||
@ -30,7 +30,7 @@ use sim::DontDrawAgents;
|
||||
use std::collections::BTreeSet;
|
||||
use widgetry::{
|
||||
hotkey, lctrl, Btn, Choice, Color, Drawable, EventCtx, GfxCtx, HorizontalAlignment, Key, Line,
|
||||
Menu, Outcome, Panel, RewriteColor, Text, TextExt, VerticalAlignment, Widget,
|
||||
Menu, Outcome, Panel, Text, TextExt, VerticalAlignment, Widget,
|
||||
};
|
||||
|
||||
pub struct EditMode {
|
||||
@ -219,16 +219,23 @@ impl State for EditMode {
|
||||
Transition::Replace(LoadEdits::new(ctx, app, mode.clone()))
|
||||
}
|
||||
}
|
||||
"create a blank proposal" => Transition::Replace(SaveEdits::new(
|
||||
ctx,
|
||||
app,
|
||||
"Do you want to save your proposal first?",
|
||||
true,
|
||||
Some(Transition::Pop),
|
||||
Box::new(|ctx, app| {
|
||||
"create a blank proposal" => {
|
||||
if app.primary.map.unsaved_edits() {
|
||||
Transition::Replace(SaveEdits::new(
|
||||
ctx,
|
||||
app,
|
||||
"Do you want to save your proposal first?",
|
||||
true,
|
||||
Some(Transition::Pop),
|
||||
Box::new(|ctx, app| {
|
||||
apply_map_edits(ctx, app, app.primary.map.new_edits());
|
||||
}),
|
||||
))
|
||||
} else {
|
||||
apply_map_edits(ctx, app, app.primary.map.new_edits());
|
||||
}),
|
||||
)),
|
||||
Transition::Pop
|
||||
}
|
||||
}
|
||||
"save this proposal as..." => Transition::Replace(SaveEdits::new(
|
||||
ctx,
|
||||
app,
|
||||
@ -268,11 +275,8 @@ impl State for EditMode {
|
||||
}
|
||||
}
|
||||
x => {
|
||||
let idx = x["most recent change #".len()..].parse::<usize>().unwrap();
|
||||
if let Some(id) = cmd_to_id(
|
||||
&app.primary.map.get_edits().commands
|
||||
[app.primary.map.get_edits().commands.len() - idx],
|
||||
) {
|
||||
let idx = x["change #".len()..].parse::<usize>().unwrap();
|
||||
if let Some(id) = cmd_to_id(&app.primary.map.get_edits().commands[idx - 1]) {
|
||||
return Transition::Push(Warping::new(
|
||||
ctx,
|
||||
id.canonical_point(&app.primary).unwrap(),
|
||||
@ -742,38 +746,42 @@ fn make_changelist(ctx: &mut EventCtx, app: &App) -> Panel {
|
||||
.container()
|
||||
.padding(10)
|
||||
.bg(Color::hex("#5D9630")),
|
||||
(if !edits.commands.is_empty() {
|
||||
Btn::svg_def("system/assets/tools/undo.svg").build(ctx, "undo", lctrl(Key::Z))
|
||||
} else {
|
||||
Widget::draw_svg_transform(
|
||||
ctx,
|
||||
"system/assets/tools/undo.svg",
|
||||
RewriteColor::ChangeAll(Color::WHITE.alpha(0.5)),
|
||||
)
|
||||
})
|
||||
.centered_vert(),
|
||||
]),
|
||||
Text::from_multiline(vec![
|
||||
Line(format!("{} roads changed", edits.changed_roads.len())),
|
||||
Line(format!(
|
||||
"{} intersections changed",
|
||||
ColorLegend::row(
|
||||
ctx,
|
||||
app.cs.edits_layer,
|
||||
format!(
|
||||
"{} roads, {} intersections changed",
|
||||
edits.changed_roads.len(),
|
||||
edits.original_intersections.len()
|
||||
)),
|
||||
])
|
||||
.draw(ctx),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
for (idx, cmd) in edits.commands.iter().rev().take(5).enumerate() {
|
||||
col.push(
|
||||
Btn::plaintext(format!("{}) {}", idx + 1, cmd.short_name(&app.primary.map))).build(
|
||||
ctx,
|
||||
format!("most recent change #{}", idx + 1),
|
||||
None,
|
||||
),
|
||||
);
|
||||
}
|
||||
if edits.commands.len() > 5 {
|
||||
col.push(format!("{} more...", edits.commands.len()).draw_text(ctx));
|
||||
col.push(format!("{} more...", edits.commands.len() - 5).draw_text(ctx));
|
||||
}
|
||||
for idx in edits.commands.len().max(5) - 5..edits.commands.len() {
|
||||
let (summary, details) = edits.commands[idx].describe(&app.primary.map);
|
||||
let mut txt = Text::from(Line(format!("{}) {}", idx + 1, summary)));
|
||||
for line in details {
|
||||
txt.add(Line(line).secondary());
|
||||
}
|
||||
let btn = Btn::plaintext_custom(format!("change #{}", idx + 1), txt).build_def(ctx, None);
|
||||
if idx == edits.commands.len() - 1 {
|
||||
col.push(
|
||||
Widget::row(vec![
|
||||
btn,
|
||||
Btn::plaintext("X")
|
||||
.build(ctx, "undo", lctrl(Key::Z))
|
||||
.align_right(),
|
||||
])
|
||||
.padding(16)
|
||||
.outline(2.0, Color::WHITE),
|
||||
);
|
||||
} else {
|
||||
col.push(btn);
|
||||
}
|
||||
}
|
||||
|
||||
Panel::new(Widget::col(col))
|
||||
|
@ -56,6 +56,38 @@ impl EditRoad {
|
||||
access_restrictions: r.access_restrictions_from_osm(),
|
||||
}
|
||||
}
|
||||
|
||||
fn diff(&self, other: &EditRoad) -> Vec<String> {
|
||||
let mut lt = 0;
|
||||
let mut dir = 0;
|
||||
for ((lt1, dir1), (lt2, dir2)) in self.lanes_ltr.iter().zip(other.lanes_ltr.iter()) {
|
||||
if lt1 != lt2 {
|
||||
lt += 1;
|
||||
}
|
||||
if dir1 != dir2 {
|
||||
dir += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut changes = Vec::new();
|
||||
if lt == 1 {
|
||||
changes.push(format!("1 lane type"));
|
||||
} else if lt > 1 {
|
||||
changes.push(format!("{} lane types", lt));
|
||||
}
|
||||
if dir == 1 {
|
||||
changes.push(format!("1 lane reversal"));
|
||||
} else if dir > 1 {
|
||||
changes.push(format!("{} lane reversal", dir));
|
||||
}
|
||||
if self.speed_limit != other.speed_limit {
|
||||
changes.push(format!("speed limit"));
|
||||
}
|
||||
if self.access_restrictions != other.access_restrictions {
|
||||
changes.push(format!("access restrictions"));
|
||||
}
|
||||
changes
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
@ -227,10 +259,15 @@ impl EditEffects {
|
||||
}
|
||||
|
||||
impl EditCmd {
|
||||
pub fn short_name(&self, map: &Map) -> String {
|
||||
match self {
|
||||
// TODO Way more details
|
||||
EditCmd::ChangeRoad { r, .. } => format!("road #{}", r.0),
|
||||
// (summary, details)
|
||||
pub fn describe(&self, map: &Map) -> (String, Vec<String>) {
|
||||
let mut details = Vec::new();
|
||||
let summary = match self {
|
||||
EditCmd::ChangeRoad { r, old, new } => {
|
||||
details = new.diff(old);
|
||||
format!("road #{}", r.0)
|
||||
}
|
||||
// TODO Describe changes
|
||||
EditCmd::ChangeIntersection { i, new, .. } => match new {
|
||||
EditIntersection::StopSign(_) => format!("stop sign #{}", i.0),
|
||||
EditIntersection::TrafficSignal(_) => format!("traffic signal #{}", i.0),
|
||||
@ -239,7 +276,8 @@ impl EditCmd {
|
||||
EditCmd::ChangeRouteSchedule { id, .. } => {
|
||||
format!("reschedule route {}", map.get_br(*id).short_name)
|
||||
}
|
||||
}
|
||||
};
|
||||
(summary, details)
|
||||
}
|
||||
|
||||
// Must be idempotent
|
||||
|
@ -134,6 +134,13 @@ impl Btn {
|
||||
maybe_tooltip: None,
|
||||
}
|
||||
}
|
||||
pub fn plaintext_custom<I: Into<String>>(label: I, txt: Text) -> BtnBuilder {
|
||||
BtnBuilder::PlainText {
|
||||
label: label.into(),
|
||||
txt,
|
||||
maybe_tooltip: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text_fg<I: Into<String>>(label: I) -> BtnBuilder {
|
||||
let label = label.into();
|
||||
|
Loading…
Reference in New Issue
Block a user