mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 07:25:47 +03:00
Merge view/edit mode
This commit is contained in:
parent
b59419ea84
commit
a393f4f66c
@ -1,222 +0,0 @@
|
|||||||
use geom::Distance;
|
|
||||||
use map_gui::ID;
|
|
||||||
use map_model::{EditCmd, LaneType};
|
|
||||||
use widgetry::{
|
|
||||||
lctrl, Drawable, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, State,
|
|
||||||
TextExt, VerticalAlignment, Widget,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::app::{App, Transition};
|
|
||||||
use crate::common::Warping;
|
|
||||||
use crate::edit::{LoadEdits, RoadEditor, SaveEdits};
|
|
||||||
use crate::sandbox::gameplay::GameplayMode;
|
|
||||||
use crate::ungap::magnifying::MagnifyingGlass;
|
|
||||||
|
|
||||||
pub struct QuickEdit {
|
|
||||||
top_panel: Panel,
|
|
||||||
network_layer: Drawable,
|
|
||||||
edits_layer: Drawable,
|
|
||||||
magnifying_glass: MagnifyingGlass,
|
|
||||||
|
|
||||||
// edits name, number of commands
|
|
||||||
// TODO Brittle -- could undo and add a new command. Add a proper edit counter to map. Refactor
|
|
||||||
// with EditMode. Use Cached.
|
|
||||||
changelist_key: (String, usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl QuickEdit {
|
|
||||||
pub fn new_state(ctx: &mut EventCtx, app: &mut App) -> Box<dyn State<App>> {
|
|
||||||
let edits = app.primary.map.get_edits();
|
|
||||||
Box::new(QuickEdit {
|
|
||||||
top_panel: make_top_panel(ctx, app),
|
|
||||||
magnifying_glass: MagnifyingGlass::new(ctx, false),
|
|
||||||
network_layer: crate::ungap::layers::render_network_layer(ctx, app),
|
|
||||||
edits_layer: crate::ungap::layers::render_edits(ctx, app),
|
|
||||||
|
|
||||||
changelist_key: (edits.edits_name.clone(), edits.commands.len()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State<App> for QuickEdit {
|
|
||||||
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
|
||||||
{
|
|
||||||
let edits = app.primary.map.get_edits();
|
|
||||||
let changelist_key = (edits.edits_name.clone(), edits.commands.len());
|
|
||||||
if self.changelist_key != changelist_key {
|
|
||||||
self.changelist_key = changelist_key;
|
|
||||||
self.network_layer = crate::ungap::render_network_layer(ctx, app);
|
|
||||||
self.edits_layer = crate::ungap::layers::render_edits(ctx, app);
|
|
||||||
self.top_panel = make_top_panel(ctx, app);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.canvas_movement();
|
|
||||||
self.magnifying_glass.event(ctx, app);
|
|
||||||
|
|
||||||
match self.top_panel.event(ctx) {
|
|
||||||
Outcome::Clicked(x) => match x.as_ref() {
|
|
||||||
"close" => {
|
|
||||||
return Transition::Pop;
|
|
||||||
}
|
|
||||||
"Open a proposal" => {
|
|
||||||
// Dummy mode, just to allow all edits
|
|
||||||
// TODO Actually, should we make one to express that only road edits are
|
|
||||||
// relevant?
|
|
||||||
let mode = GameplayMode::Freeform(app.primary.map.get_name().clone());
|
|
||||||
|
|
||||||
// TODO Do we want to do SaveEdits first if unsaved_edits()? We have
|
|
||||||
// auto-saving... and after loading an old "untitled proposal", it looks
|
|
||||||
// unsaved.
|
|
||||||
return Transition::Push(LoadEdits::new_state(ctx, app, mode));
|
|
||||||
}
|
|
||||||
"Save this proposal" => {
|
|
||||||
return Transition::Push(SaveEdits::new_state(
|
|
||||||
ctx,
|
|
||||||
app,
|
|
||||||
format!("Save \"{}\" as", app.primary.map.get_edits().edits_name),
|
|
||||||
false,
|
|
||||||
Some(Transition::Pop),
|
|
||||||
Box::new(|_, _| {}),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
"Sketch a route" => {
|
|
||||||
app.primary.current_selection = None;
|
|
||||||
return Transition::Push(crate::ungap::quick_sketch::QuickSketch::new_state(
|
|
||||||
ctx, app,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Click to edit a road in detail
|
|
||||||
if ctx.redo_mouseover() {
|
|
||||||
app.primary.current_selection =
|
|
||||||
match app.mouseover_unzoomed_roads_and_intersections(ctx) {
|
|
||||||
Some(ID::Road(r)) => Some(r),
|
|
||||||
Some(ID::Lane(l)) => Some(app.primary.map.get_l(l).parent),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
.and_then(|r| {
|
|
||||||
if app.primary.map.get_r(r).is_light_rail() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(ID::Road(r))
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if let Some(ID::Road(r)) = app.primary.current_selection {
|
|
||||||
if ctx.normal_left_click() {
|
|
||||||
return Transition::Multi(vec![
|
|
||||||
Transition::Push(RoadEditor::new_state_without_lane(ctx, app, r)),
|
|
||||||
Transition::Push(Warping::new_state(
|
|
||||||
ctx,
|
|
||||||
ctx.canvas.get_cursor_in_map_space().unwrap(),
|
|
||||||
Some(10.0),
|
|
||||||
None,
|
|
||||||
&mut app.primary,
|
|
||||||
)),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Transition::Keep
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw(&self, g: &mut GfxCtx, app: &App) {
|
|
||||||
self.top_panel.draw(g);
|
|
||||||
if g.canvas.cam_zoom < app.opts.min_zoom_for_detail {
|
|
||||||
g.redraw(&self.network_layer);
|
|
||||||
self.magnifying_glass.draw(g, app);
|
|
||||||
}
|
|
||||||
g.redraw(&self.edits_layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_top_panel(ctx: &mut EventCtx, app: &App) -> Panel {
|
|
||||||
let mut file_management = Vec::new();
|
|
||||||
let edits = app.primary.map.get_edits();
|
|
||||||
|
|
||||||
let total_mileage = {
|
|
||||||
// Look for the new lanes...
|
|
||||||
let mut total = Distance::ZERO;
|
|
||||||
// TODO We're assuming the edits have been compressed.
|
|
||||||
for cmd in &edits.commands {
|
|
||||||
if let EditCmd::ChangeRoad { r, old, new } = cmd {
|
|
||||||
let num_before = old
|
|
||||||
.lanes_ltr
|
|
||||||
.iter()
|
|
||||||
.filter(|spec| spec.lt == LaneType::Biking)
|
|
||||||
.count();
|
|
||||||
let num_after = new
|
|
||||||
.lanes_ltr
|
|
||||||
.iter()
|
|
||||||
.filter(|spec| spec.lt == LaneType::Biking)
|
|
||||||
.count();
|
|
||||||
if num_before != num_after {
|
|
||||||
let multiplier = (num_after as f64) - (num_before) as f64;
|
|
||||||
total += multiplier * app.primary.map.get_r(*r).center_pts.length();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
total
|
|
||||||
};
|
|
||||||
if edits.commands.is_empty() {
|
|
||||||
file_management.push("Today's network".text_widget(ctx));
|
|
||||||
} else {
|
|
||||||
file_management.push(Line(&edits.edits_name).into_widget(ctx));
|
|
||||||
}
|
|
||||||
file_management.push(
|
|
||||||
Line(format!(
|
|
||||||
"{:.1} miles of new bike lanes",
|
|
||||||
total_mileage.to_miles()
|
|
||||||
))
|
|
||||||
.secondary()
|
|
||||||
.into_widget(ctx),
|
|
||||||
);
|
|
||||||
file_management.push(crate::ungap::legend(
|
|
||||||
ctx,
|
|
||||||
*crate::ungap::layers::EDITED_COLOR,
|
|
||||||
"changed road",
|
|
||||||
));
|
|
||||||
file_management.push(Widget::row(vec![
|
|
||||||
ctx.style()
|
|
||||||
.btn_outline
|
|
||||||
.text("Open a proposal")
|
|
||||||
.hotkey(lctrl(Key::O))
|
|
||||||
.build_def(ctx),
|
|
||||||
ctx.style()
|
|
||||||
.btn_outline
|
|
||||||
.text("Save this proposal")
|
|
||||||
.hotkey(lctrl(Key::S))
|
|
||||||
.disabled(edits.commands.is_empty())
|
|
||||||
.build_def(ctx),
|
|
||||||
]));
|
|
||||||
// TODO Should undo/redo, save, share functionality also live here?
|
|
||||||
|
|
||||||
Panel::new_builder(Widget::col(vec![
|
|
||||||
Widget::row(vec![
|
|
||||||
Line("Draw your ideal bike network")
|
|
||||||
.small_heading()
|
|
||||||
.into_widget(ctx),
|
|
||||||
// TODO Or maybe this is misleading; we should keep the tab style
|
|
||||||
ctx.style().btn_close_widget(ctx),
|
|
||||||
]),
|
|
||||||
Widget::col(file_management).bg(ctx.style().section_bg),
|
|
||||||
Widget::row(vec![
|
|
||||||
"Click a road to edit in detail"
|
|
||||||
.text_widget(ctx)
|
|
||||||
.centered_vert(),
|
|
||||||
ctx.style()
|
|
||||||
.btn_solid_primary
|
|
||||||
.text("Sketch a route")
|
|
||||||
.hotkey(Key::S)
|
|
||||||
.build_def(ctx),
|
|
||||||
])
|
|
||||||
.evenly_spaced(),
|
|
||||||
]))
|
|
||||||
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
|
|
||||||
.build(ctx)
|
|
||||||
}
|
|
@ -12,11 +12,10 @@ use crate::app::App;
|
|||||||
|
|
||||||
pub struct MagnifyingGlass {
|
pub struct MagnifyingGlass {
|
||||||
panel: Panel,
|
panel: Panel,
|
||||||
click_for_details: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MagnifyingGlass {
|
impl MagnifyingGlass {
|
||||||
pub fn new(ctx: &mut EventCtx, click_for_details: bool) -> MagnifyingGlass {
|
pub fn new(ctx: &mut EventCtx) -> MagnifyingGlass {
|
||||||
MagnifyingGlass {
|
MagnifyingGlass {
|
||||||
panel: Panel::new_builder(
|
panel: Panel::new_builder(
|
||||||
Widget::col(vec![
|
Widget::col(vec![
|
||||||
@ -28,7 +27,6 @@ impl MagnifyingGlass {
|
|||||||
)
|
)
|
||||||
.aligned(HorizontalAlignment::LeftInset, VerticalAlignment::TopInset)
|
.aligned(HorizontalAlignment::LeftInset, VerticalAlignment::TopInset)
|
||||||
.build(ctx),
|
.build(ctx),
|
||||||
click_for_details,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,9 +44,6 @@ impl MagnifyingGlass {
|
|||||||
} else {
|
} else {
|
||||||
// TODO Jittery panel
|
// TODO Jittery panel
|
||||||
}
|
}
|
||||||
if self.click_for_details {
|
|
||||||
label.add_line(Line("Click for details").secondary());
|
|
||||||
}
|
|
||||||
let label = label.into_widget(ctx);
|
let label = label.into_widget(ctx);
|
||||||
self.panel.replace(ctx, "label", label);
|
self.panel.replace(ctx, "label", label);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
mod edit;
|
|
||||||
mod layers;
|
mod layers;
|
||||||
mod magnifying;
|
mod magnifying;
|
||||||
mod nearby;
|
mod nearby;
|
||||||
@ -7,26 +6,34 @@ mod quick_sketch;
|
|||||||
use abstutil::prettyprint_usize;
|
use abstutil::prettyprint_usize;
|
||||||
use geom::Distance;
|
use geom::Distance;
|
||||||
use map_gui::tools::{nice_map_name, CityPicker, PopupMsg};
|
use map_gui::tools::{nice_map_name, CityPicker, PopupMsg};
|
||||||
|
use map_gui::ID;
|
||||||
|
use map_model::{EditCmd, LaneType};
|
||||||
use widgetry::{
|
use widgetry::{
|
||||||
lctrl, Drawable, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, State, Text,
|
lctrl, Drawable, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, State, Text,
|
||||||
Toggle, VerticalAlignment, Widget,
|
TextExt, Toggle, VerticalAlignment, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::layers::{legend, render_network_layer};
|
use self::layers::{legend, render_edits, render_network_layer};
|
||||||
use self::magnifying::MagnifyingGlass;
|
use self::magnifying::MagnifyingGlass;
|
||||||
use self::nearby::Nearby;
|
use self::nearby::Nearby;
|
||||||
use crate::app::{App, Transition};
|
use crate::app::{App, Transition};
|
||||||
use crate::common::Warping;
|
use crate::common::Warping;
|
||||||
|
use crate::edit::{LoadEdits, RoadEditor, SaveEdits};
|
||||||
|
use crate::sandbox::gameplay::GameplayMode;
|
||||||
|
|
||||||
pub struct ExploreMap {
|
pub struct ExploreMap {
|
||||||
top_panel: Panel,
|
top_panel: Panel,
|
||||||
legend: Panel,
|
legend: Panel,
|
||||||
magnifying_glass: MagnifyingGlass,
|
magnifying_glass: MagnifyingGlass,
|
||||||
network_layer: Drawable,
|
network_layer: Drawable,
|
||||||
|
edits_layer: Drawable,
|
||||||
elevation: bool,
|
elevation: bool,
|
||||||
// TODO Also cache Nearby, but recalculate it after edits
|
// TODO Also cache Nearby, but recalculate it after edits
|
||||||
nearby: Option<Nearby>,
|
nearby: Option<Nearby>,
|
||||||
|
|
||||||
|
// edits name, number of commands
|
||||||
|
// TODO Brittle -- could undo and add a new command. Add a proper edit counter to map. Refactor
|
||||||
|
// with EditMode. Use Cached.
|
||||||
changelist_key: (String, usize),
|
changelist_key: (String, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,10 +43,11 @@ impl ExploreMap {
|
|||||||
let edits = app.primary.map.get_edits();
|
let edits = app.primary.map.get_edits();
|
||||||
|
|
||||||
Box::new(ExploreMap {
|
Box::new(ExploreMap {
|
||||||
top_panel: make_top_panel(ctx),
|
top_panel: make_top_panel(ctx, app),
|
||||||
legend: make_legend(ctx, app, false, false),
|
legend: make_legend(ctx, app, false, false),
|
||||||
magnifying_glass: MagnifyingGlass::new(ctx, true),
|
magnifying_glass: MagnifyingGlass::new(ctx),
|
||||||
network_layer: render_network_layer(ctx, app),
|
network_layer: render_network_layer(ctx, app),
|
||||||
|
edits_layer: render_edits(ctx, app),
|
||||||
elevation: false,
|
elevation: false,
|
||||||
nearby: None,
|
nearby: None,
|
||||||
|
|
||||||
@ -55,7 +63,9 @@ impl State<App> for ExploreMap {
|
|||||||
let changelist_key = (edits.edits_name.clone(), edits.commands.len());
|
let changelist_key = (edits.edits_name.clone(), edits.commands.len());
|
||||||
if self.changelist_key != changelist_key {
|
if self.changelist_key != changelist_key {
|
||||||
self.changelist_key = changelist_key;
|
self.changelist_key = changelist_key;
|
||||||
self.network_layer = crate::ungap::render_network_layer(ctx, app);
|
self.network_layer = render_network_layer(ctx, app);
|
||||||
|
self.edits_layer = render_edits(ctx, app);
|
||||||
|
self.top_panel = make_top_panel(ctx, app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,6 +94,38 @@ impl State<App> for ExploreMap {
|
|||||||
self.legend.replace(ctx, "current elevation", label);
|
self.legend.replace(ctx, "current elevation", label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Click to edit a road in detail
|
||||||
|
if ctx.redo_mouseover() {
|
||||||
|
app.primary.current_selection =
|
||||||
|
match app.mouseover_unzoomed_roads_and_intersections(ctx) {
|
||||||
|
Some(ID::Road(r)) => Some(r),
|
||||||
|
Some(ID::Lane(l)) => Some(app.primary.map.get_l(l).parent),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
.and_then(|r| {
|
||||||
|
if app.primary.map.get_r(r).is_light_rail() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(ID::Road(r))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(ID::Road(r)) = app.primary.current_selection {
|
||||||
|
if ctx.normal_left_click() {
|
||||||
|
return Transition::Multi(vec![
|
||||||
|
Transition::Push(RoadEditor::new_state_without_lane(ctx, app, r)),
|
||||||
|
Transition::Push(Warping::new_state(
|
||||||
|
ctx,
|
||||||
|
ctx.canvas.get_cursor_in_map_space().unwrap(),
|
||||||
|
Some(10.0),
|
||||||
|
None,
|
||||||
|
&mut app.primary,
|
||||||
|
)),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click to zoom in somewhere
|
||||||
if let Some(pt) = ctx.canvas.get_cursor_in_map_space() {
|
if let Some(pt) = ctx.canvas.get_cursor_in_map_space() {
|
||||||
if ctx.canvas.cam_zoom < app.opts.min_zoom_for_detail && ctx.normal_left_click() {
|
if ctx.canvas.cam_zoom < app.opts.min_zoom_for_detail && ctx.normal_left_click() {
|
||||||
return Transition::Push(Warping::new_state(
|
return Transition::Push(Warping::new_state(
|
||||||
@ -101,11 +143,32 @@ impl State<App> for ExploreMap {
|
|||||||
"about A/B Street" => {
|
"about A/B Street" => {
|
||||||
return Transition::Push(PopupMsg::new_state(ctx, "TODO", vec!["TODO"]));
|
return Transition::Push(PopupMsg::new_state(ctx, "TODO", vec!["TODO"]));
|
||||||
}
|
}
|
||||||
"Bike Master Plan" => {
|
"Open a proposal" => {
|
||||||
return Transition::Push(PopupMsg::new_state(ctx, "TODO", vec!["TODO"]));
|
// Dummy mode, just to allow all edits
|
||||||
|
// TODO Actually, should we make one to express that only road edits are
|
||||||
|
// relevant?
|
||||||
|
let mode = GameplayMode::Freeform(app.primary.map.get_name().clone());
|
||||||
|
|
||||||
|
// TODO Do we want to do SaveEdits first if unsaved_edits()? We have
|
||||||
|
// auto-saving... and after loading an old "untitled proposal", it looks
|
||||||
|
// unsaved.
|
||||||
|
return Transition::Push(LoadEdits::new_state(ctx, app, mode));
|
||||||
}
|
}
|
||||||
"Edit network" => {
|
"Save this proposal" => {
|
||||||
return Transition::Push(edit::QuickEdit::new_state(ctx, app));
|
return Transition::Push(SaveEdits::new_state(
|
||||||
|
ctx,
|
||||||
|
app,
|
||||||
|
format!("Save \"{}\" as", app.primary.map.get_edits().edits_name),
|
||||||
|
false,
|
||||||
|
Some(Transition::Pop),
|
||||||
|
Box::new(|_, _| {}),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
"Sketch a route" => {
|
||||||
|
app.primary.current_selection = None;
|
||||||
|
return Transition::Push(crate::ungap::quick_sketch::QuickSketch::new_state(
|
||||||
|
ctx, app,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@ -198,35 +261,96 @@ impl State<App> for ExploreMap {
|
|||||||
|
|
||||||
self.magnifying_glass.draw(g, app);
|
self.magnifying_glass.draw(g, app);
|
||||||
}
|
}
|
||||||
|
g.redraw(&self.edits_layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_top_panel(ctx: &mut EventCtx) -> Panel {
|
fn make_top_panel(ctx: &mut EventCtx, app: &App) -> Panel {
|
||||||
Panel::new_builder(Widget::row(vec![
|
let mut file_management = Vec::new();
|
||||||
|
let edits = app.primary.map.get_edits();
|
||||||
|
|
||||||
|
let total_mileage = {
|
||||||
|
// Look for the new lanes...
|
||||||
|
let mut total = Distance::ZERO;
|
||||||
|
// TODO We're assuming the edits have been compressed.
|
||||||
|
for cmd in &edits.commands {
|
||||||
|
if let EditCmd::ChangeRoad { r, old, new } = cmd {
|
||||||
|
let num_before = old
|
||||||
|
.lanes_ltr
|
||||||
|
.iter()
|
||||||
|
.filter(|spec| spec.lt == LaneType::Biking)
|
||||||
|
.count();
|
||||||
|
let num_after = new
|
||||||
|
.lanes_ltr
|
||||||
|
.iter()
|
||||||
|
.filter(|spec| spec.lt == LaneType::Biking)
|
||||||
|
.count();
|
||||||
|
if num_before != num_after {
|
||||||
|
let multiplier = (num_after as f64) - (num_before) as f64;
|
||||||
|
total += multiplier * app.primary.map.get_r(*r).center_pts.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
total
|
||||||
|
};
|
||||||
|
if edits.commands.is_empty() {
|
||||||
|
file_management.push("Today's network".text_widget(ctx));
|
||||||
|
} else {
|
||||||
|
file_management.push(Line(&edits.edits_name).into_widget(ctx));
|
||||||
|
}
|
||||||
|
file_management.push(
|
||||||
|
Line(format!(
|
||||||
|
"{:.1} miles of new bike lanes",
|
||||||
|
total_mileage.to_miles()
|
||||||
|
))
|
||||||
|
.secondary()
|
||||||
|
.into_widget(ctx),
|
||||||
|
);
|
||||||
|
file_management.push(legend(
|
||||||
|
ctx,
|
||||||
|
*crate::ungap::layers::EDITED_COLOR,
|
||||||
|
"changed road",
|
||||||
|
));
|
||||||
|
file_management.push(Widget::row(vec![
|
||||||
|
ctx.style()
|
||||||
|
.btn_outline
|
||||||
|
.text("Open a proposal")
|
||||||
|
.hotkey(lctrl(Key::O))
|
||||||
|
.build_def(ctx),
|
||||||
|
ctx.style()
|
||||||
|
.btn_outline
|
||||||
|
.text("Save this proposal")
|
||||||
|
.hotkey(lctrl(Key::S))
|
||||||
|
.disabled(edits.commands.is_empty())
|
||||||
|
.build_def(ctx),
|
||||||
|
]));
|
||||||
|
// TODO Should undo/redo, save, share functionality also live here?
|
||||||
|
|
||||||
|
Panel::new_builder(Widget::col(vec![
|
||||||
|
Widget::row(vec![
|
||||||
ctx.style()
|
ctx.style()
|
||||||
.btn_plain
|
.btn_plain
|
||||||
.btn()
|
.btn()
|
||||||
.image_path("system/assets/pregame/logo.svg")
|
.image_path("system/assets/pregame/logo.svg")
|
||||||
.image_dims(50.0)
|
.image_dims(50.0)
|
||||||
.build_widget(ctx, "about A/B Street"),
|
.build_widget(ctx, "about A/B Street"),
|
||||||
// TODO Tab style?
|
Line("Draw your ideal bike network")
|
||||||
ctx.style()
|
.small_heading()
|
||||||
.btn_solid_primary
|
.into_widget(ctx)
|
||||||
.text("Today")
|
.centered_vert(),
|
||||||
.disabled(true)
|
]),
|
||||||
.build_def(ctx)
|
Widget::col(file_management).bg(ctx.style().section_bg),
|
||||||
|
Widget::row(vec![
|
||||||
|
"Click a road to edit in detail"
|
||||||
|
.text_widget(ctx)
|
||||||
.centered_vert(),
|
.centered_vert(),
|
||||||
ctx.style()
|
ctx.style()
|
||||||
.btn_solid_primary
|
.btn_solid_primary
|
||||||
.text("Bike Master Plan")
|
.text("Sketch a route")
|
||||||
.build_def(ctx)
|
.hotkey(Key::S)
|
||||||
.centered_vert(),
|
.build_def(ctx),
|
||||||
ctx.style()
|
])
|
||||||
.btn_solid_primary
|
.evenly_spaced(),
|
||||||
.icon_text("system/assets/tools/pencil.svg", "Edit network")
|
|
||||||
.hotkey(lctrl(Key::E))
|
|
||||||
.build_def(ctx)
|
|
||||||
.centered_vert(),
|
|
||||||
]))
|
]))
|
||||||
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
|
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
|
||||||
.build(ctx)
|
.build(ctx)
|
||||||
|
@ -24,7 +24,7 @@ impl QuickSketch {
|
|||||||
pub fn new_state(ctx: &mut EventCtx, app: &mut App) -> Box<dyn State<App>> {
|
pub fn new_state(ctx: &mut EventCtx, app: &mut App) -> Box<dyn State<App>> {
|
||||||
let mut qs = QuickSketch {
|
let mut qs = QuickSketch {
|
||||||
top_panel: Panel::empty(ctx),
|
top_panel: Panel::empty(ctx),
|
||||||
magnifying_glass: MagnifyingGlass::new(ctx, false),
|
magnifying_glass: MagnifyingGlass::new(ctx),
|
||||||
network_layer: crate::ungap::render_network_layer(ctx, app),
|
network_layer: crate::ungap::render_network_layer(ctx, app),
|
||||||
edits_layer: render_edits(ctx, app),
|
edits_layer: render_edits(ctx, app),
|
||||||
route_sketcher: RouteSketcher::new(ctx, app),
|
route_sketcher: RouteSketcher::new(ctx, app),
|
||||||
|
Loading…
Reference in New Issue
Block a user