mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 23:43:25 +03:00
Implement Yuwen's split jump to time/delay UI [rebuild]
This commit is contained in:
parent
8b7cb7a601
commit
ec28132286
@ -34,8 +34,8 @@ pub struct DebugMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DebugMode {
|
impl DebugMode {
|
||||||
pub fn new(ctx: &mut EventCtx) -> DebugMode {
|
pub fn new(ctx: &mut EventCtx) -> Box<dyn State> {
|
||||||
DebugMode {
|
Box::new(DebugMode {
|
||||||
panel: Panel::new(Widget::col(vec![
|
panel: Panel::new(Widget::col(vec![
|
||||||
Widget::row(vec![
|
Widget::row(vec![
|
||||||
Line("Debug Mode").small_heading().draw(ctx),
|
Line("Debug Mode").small_heading().draw(ctx),
|
||||||
@ -86,7 +86,7 @@ impl DebugMode {
|
|||||||
search_results: None,
|
search_results: None,
|
||||||
all_routes: None,
|
all_routes: None,
|
||||||
highlighted_agents: None,
|
highlighted_agents: None,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset_info(&mut self, ctx: &mut EventCtx) {
|
fn reset_info(&mut self, ctx: &mut EventCtx) {
|
||||||
|
@ -103,9 +103,7 @@ impl State for DevToolsMode {
|
|||||||
abstutil::path_scenario(app.primary.map.get_name(), &s),
|
abstutil::path_scenario(app.primary.map.get_name(), &s),
|
||||||
&mut Timer::throwaway(),
|
&mut Timer::throwaway(),
|
||||||
);
|
);
|
||||||
Transition::Replace(Box::new(scenario::ScenarioManager::new(
|
Transition::Replace(scenario::ScenarioManager::new(scenario, ctx, app))
|
||||||
scenario, ctx, app,
|
|
||||||
)))
|
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ pub struct ScenarioManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ScenarioManager {
|
impl ScenarioManager {
|
||||||
pub fn new(scenario: Scenario, ctx: &mut EventCtx, app: &App) -> ScenarioManager {
|
pub fn new(scenario: Scenario, ctx: &mut EventCtx, app: &App) -> Box<dyn State> {
|
||||||
let mut colorer = ColorDiscrete::new(
|
let mut colorer = ColorDiscrete::new(
|
||||||
app,
|
app,
|
||||||
vec![
|
vec![
|
||||||
@ -45,7 +45,7 @@ impl ScenarioManager {
|
|||||||
assert!(filled_spots.is_empty());
|
assert!(filled_spots.is_empty());
|
||||||
|
|
||||||
let (unzoomed, zoomed, legend) = colorer.build(ctx);
|
let (unzoomed, zoomed, legend) = colorer.build(ctx);
|
||||||
ScenarioManager {
|
Box::new(ScenarioManager {
|
||||||
panel: Panel::new(Widget::col(vec![
|
panel: Panel::new(Widget::col(vec![
|
||||||
Widget::row(vec![
|
Widget::row(vec![
|
||||||
Line(format!("Scenario {}", scenario.scenario_name))
|
Line(format!("Scenario {}", scenario.scenario_name))
|
||||||
@ -80,7 +80,7 @@ impl ScenarioManager {
|
|||||||
unzoomed,
|
unzoomed,
|
||||||
zoomed,
|
zoomed,
|
||||||
scenario,
|
scenario,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ impl State for EditMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if app.opts.dev && ctx.input.pressed(lctrl(Key::D)) {
|
if app.opts.dev && ctx.input.pressed(lctrl(Key::D)) {
|
||||||
return Transition::Push(Box::new(DebugMode::new(ctx)));
|
return Transition::Push(DebugMode::new(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.top_center.event(ctx) {
|
match self.top_center.event(ctx) {
|
||||||
|
@ -19,8 +19,8 @@ struct PreviewTrafficSignal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PreviewTrafficSignal {
|
impl PreviewTrafficSignal {
|
||||||
fn new(ctx: &mut EventCtx, app: &App) -> PreviewTrafficSignal {
|
fn new(ctx: &mut EventCtx, app: &App) -> Box<dyn State> {
|
||||||
PreviewTrafficSignal {
|
Box::new(PreviewTrafficSignal {
|
||||||
panel: Panel::new(Widget::col(vec![
|
panel: Panel::new(Widget::col(vec![
|
||||||
"Previewing traffic signal".draw_text(ctx),
|
"Previewing traffic signal".draw_text(ctx),
|
||||||
Btn::text_fg("back to editing").build_def(ctx, hotkey(Key::Escape)),
|
Btn::text_fg("back to editing").build_def(ctx, hotkey(Key::Escape)),
|
||||||
@ -29,7 +29,7 @@ impl PreviewTrafficSignal {
|
|||||||
.build(ctx),
|
.build(ctx),
|
||||||
speed: SpeedControls::new(ctx, app),
|
speed: SpeedControls::new(ctx, app),
|
||||||
time_panel: TimePanel::new(ctx, app),
|
time_panel: TimePanel::new(ctx, app),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ pub fn make_previewer(
|
|||||||
.sim
|
.sim
|
||||||
.handle_live_edited_traffic_signals(&app.primary.map);
|
.handle_live_edited_traffic_signals(&app.primary.map);
|
||||||
}
|
}
|
||||||
Transition::Replace(Box::new(PreviewTrafficSignal::new(ctx, app)))
|
Transition::Replace(PreviewTrafficSignal::new(ctx, app))
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ pub struct Options {
|
|||||||
|
|
||||||
pub time_increment: Duration,
|
pub time_increment: Duration,
|
||||||
pub dont_draw_time_warp: bool,
|
pub dont_draw_time_warp: bool,
|
||||||
pub time_warp_halt_limit: Duration,
|
pub jump_to_delay: Duration,
|
||||||
|
|
||||||
pub language: Option<String>,
|
pub language: Option<String>,
|
||||||
}
|
}
|
||||||
@ -43,7 +43,7 @@ impl Options {
|
|||||||
|
|
||||||
time_increment: Duration::minutes(10),
|
time_increment: Duration::minutes(10),
|
||||||
dont_draw_time_warp: false,
|
dont_draw_time_warp: false,
|
||||||
time_warp_halt_limit: Duration::minutes(5),
|
jump_to_delay: Duration::minutes(5),
|
||||||
|
|
||||||
language: None,
|
language: None,
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ impl State for SandboxMode {
|
|||||||
|
|
||||||
// Order here is pretty arbitrary
|
// Order here is pretty arbitrary
|
||||||
if app.opts.dev && ctx.input.pressed(lctrl(Key::D)) {
|
if app.opts.dev && ctx.input.pressed(lctrl(Key::D)) {
|
||||||
return Transition::Push(Box::new(DebugMode::new(ctx)));
|
return Transition::Push(DebugMode::new(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref mut m) = self.controls.minimap {
|
if let Some(ref mut m) = self.controls.minimap {
|
||||||
|
@ -186,11 +186,11 @@ impl SpeedControls {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"jump to specific time" => {
|
"jump to specific time" => {
|
||||||
return Some(Transition::Push(Box::new(JumpToTime::new(
|
return Some(Transition::Push(JumpToTime::new(
|
||||||
ctx,
|
ctx,
|
||||||
app,
|
app,
|
||||||
maybe_mode.cloned(),
|
maybe_mode.cloned(),
|
||||||
))));
|
)));
|
||||||
}
|
}
|
||||||
"step forwards" => {
|
"step forwards" => {
|
||||||
let dt = self.panel.persistent_split_value("step forwards");
|
let dt = self.panel.persistent_split_value("step forwards");
|
||||||
|
@ -9,42 +9,33 @@ use geom::{Duration, Polygon, Pt2D, Ring, Time};
|
|||||||
use instant::Instant;
|
use instant::Instant;
|
||||||
use widgetry::{
|
use widgetry::{
|
||||||
hotkey, AreaSlider, Btn, Checkbox, Choice, Color, EventCtx, GeomBatch, GfxCtx, Key, Line,
|
hotkey, AreaSlider, Btn, Checkbox, Choice, Color, EventCtx, GeomBatch, GfxCtx, Key, Line,
|
||||||
Outcome, Panel, PersistentSplit, Text, UpdateType, Widget,
|
Outcome, Panel, Text, UpdateType, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO Text entry would be great
|
// TODO Text entry would be great
|
||||||
pub struct JumpToTime {
|
pub struct JumpToTime {
|
||||||
panel: Panel,
|
panel: Panel,
|
||||||
target: Time,
|
target: Time,
|
||||||
halt_limit: Duration,
|
|
||||||
maybe_mode: Option<GameplayMode>,
|
maybe_mode: Option<GameplayMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JumpToTime {
|
impl JumpToTime {
|
||||||
pub fn new(ctx: &mut EventCtx, app: &App, maybe_mode: Option<GameplayMode>) -> JumpToTime {
|
pub fn new(ctx: &mut EventCtx, app: &App, maybe_mode: Option<GameplayMode>) -> Box<dyn State> {
|
||||||
let target = app.primary.sim.time();
|
let target = app.primary.sim.time();
|
||||||
let end_of_day = app.primary.sim.get_end_of_day();
|
let end_of_day = app.primary.sim.get_end_of_day();
|
||||||
let halt_limit = app.opts.time_warp_halt_limit;
|
Box::new(JumpToTime {
|
||||||
JumpToTime {
|
|
||||||
target,
|
target,
|
||||||
halt_limit,
|
|
||||||
maybe_mode,
|
maybe_mode,
|
||||||
panel: Panel::new(Widget::col(vec![
|
panel: Panel::new(Widget::col(vec![
|
||||||
Widget::row(vec![
|
|
||||||
Line("Jump to what time?").small_heading().draw(ctx),
|
|
||||||
Btn::plaintext("X")
|
Btn::plaintext("X")
|
||||||
.build(ctx, "close", hotkey(Key::Escape))
|
.build(ctx, "close", hotkey(Key::Escape))
|
||||||
.align_right(),
|
.align_right(),
|
||||||
]),
|
Widget::custom_row(vec![
|
||||||
Checkbox::checkbox(
|
Btn::text_bg2("Jump to time").inactive(ctx),
|
||||||
ctx,
|
Btn::text_bg2("Jump to delay").build_def(ctx, None),
|
||||||
"skip drawing (for faster simulations)",
|
])
|
||||||
None,
|
.bg(Color::WHITE),
|
||||||
app.opts.dont_draw_time_warp,
|
Line("Jump to what time?").small_heading().draw(ctx),
|
||||||
)
|
|
||||||
.margin_above(30)
|
|
||||||
.named("don't draw"),
|
|
||||||
Widget::horiz_separator(ctx, 0.25).margin_above(10),
|
|
||||||
if app.has_prebaked().is_some() {
|
if app.has_prebaked().is_some() {
|
||||||
Widget::draw_batch(
|
Widget::draw_batch(
|
||||||
ctx,
|
ctx,
|
||||||
@ -67,19 +58,20 @@ impl JumpToTime {
|
|||||||
0.25 * ctx.canvas.window_width,
|
0.25 * ctx.canvas.window_width,
|
||||||
target.to_percent(end_of_day).min(1.0),
|
target.to_percent(end_of_day).min(1.0),
|
||||||
)
|
)
|
||||||
.named("time slider")
|
.named("time slider"),
|
||||||
.centered_horiz()
|
Checkbox::checkbox(
|
||||||
// EZGUI FIXME: margin_below having no effect here, so instead we add a margin_top
|
ctx,
|
||||||
// to the subsequent element
|
"skip drawing (for faster simulations)",
|
||||||
//.margin_above(16).margin_below(16),
|
None,
|
||||||
.margin_above(16),
|
app.opts.dont_draw_time_warp,
|
||||||
build_jump_to_time_btn(target, ctx),
|
)
|
||||||
Widget::horiz_separator(ctx, 0.25).margin_above(16),
|
.margin_above(30)
|
||||||
build_jump_to_delay_picker(halt_limit, ctx).margin_above(16),
|
.named("don't draw"),
|
||||||
build_jump_to_delay_button(halt_limit, ctx),
|
build_jump_to_time_btn(ctx, target),
|
||||||
]))
|
]))
|
||||||
|
.exact_size_percent(50, 50)
|
||||||
.build(ctx),
|
.build(ctx),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,16 +99,8 @@ impl State for JumpToTime {
|
|||||||
}
|
}
|
||||||
return Transition::Replace(TimeWarpScreen::new(ctx, app, self.target, None));
|
return Transition::Replace(TimeWarpScreen::new(ctx, app, self.target, None));
|
||||||
}
|
}
|
||||||
"choose delay" => return Transition::Keep,
|
"Jump to delay" => {
|
||||||
"jump to delay" => {
|
return Transition::Replace(JumpToDelay::new(ctx, app, self.maybe_mode.take()));
|
||||||
let halt_limit = self.panel.persistent_split_value("choose delay");
|
|
||||||
app.opts.time_warp_halt_limit = halt_limit;
|
|
||||||
return Transition::Replace(TimeWarpScreen::new(
|
|
||||||
ctx,
|
|
||||||
app,
|
|
||||||
app.primary.sim.get_end_of_day(),
|
|
||||||
Some(halt_limit),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
@ -134,18 +118,102 @@ impl State for JumpToTime {
|
|||||||
if target != self.target {
|
if target != self.target {
|
||||||
self.target = target;
|
self.target = target;
|
||||||
self.panel
|
self.panel
|
||||||
.replace(ctx, "jump to time", build_jump_to_time_btn(target, ctx));
|
.replace(ctx, "jump to time", build_jump_to_time_btn(ctx, target));
|
||||||
}
|
}
|
||||||
|
|
||||||
let halt_limit = self.panel.persistent_split_value("choose delay");
|
if self.panel.clicked_outside(ctx) {
|
||||||
if halt_limit != self.halt_limit {
|
return Transition::Pop;
|
||||||
self.halt_limit = halt_limit;
|
}
|
||||||
|
|
||||||
|
Transition::Keep
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&self, g: &mut GfxCtx, app: &App) {
|
||||||
|
State::grey_out_map(g, app);
|
||||||
|
self.panel.draw(g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct JumpToDelay {
|
||||||
|
panel: Panel,
|
||||||
|
maybe_mode: Option<GameplayMode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JumpToDelay {
|
||||||
|
pub fn new(ctx: &mut EventCtx, app: &App, maybe_mode: Option<GameplayMode>) -> Box<dyn State> {
|
||||||
|
Box::new(JumpToDelay {
|
||||||
|
maybe_mode,
|
||||||
|
panel: Panel::new(Widget::col(vec![
|
||||||
|
Btn::plaintext("X")
|
||||||
|
.build(ctx, "close", hotkey(Key::Escape))
|
||||||
|
.align_right(),
|
||||||
|
Widget::custom_row(vec![
|
||||||
|
Btn::text_bg2("Jump to time").build_def(ctx, None),
|
||||||
|
Btn::text_bg2("Jump to delay").inactive(ctx),
|
||||||
|
])
|
||||||
|
.bg(Color::WHITE),
|
||||||
|
Widget::row(vec![
|
||||||
|
Line("Jump to next").small_heading().draw(ctx),
|
||||||
|
Widget::dropdown(
|
||||||
|
ctx,
|
||||||
|
"delay",
|
||||||
|
app.opts.jump_to_delay,
|
||||||
|
vec![
|
||||||
|
Choice::new("1", Duration::minutes(1)),
|
||||||
|
Choice::new("2", Duration::minutes(2)),
|
||||||
|
Choice::new("5", Duration::minutes(5)),
|
||||||
|
Choice::new("10", Duration::minutes(10)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Line("minute delay").small_heading().draw(ctx),
|
||||||
|
]),
|
||||||
|
Checkbox::checkbox(
|
||||||
|
ctx,
|
||||||
|
"skip drawing (for faster simulations)",
|
||||||
|
None,
|
||||||
|
app.opts.dont_draw_time_warp,
|
||||||
|
)
|
||||||
|
.margin_above(30)
|
||||||
|
.named("don't draw"),
|
||||||
|
build_jump_to_delay_button(ctx, app.opts.jump_to_delay),
|
||||||
|
]))
|
||||||
|
.exact_size_percent(50, 50)
|
||||||
|
.build(ctx),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State for JumpToDelay {
|
||||||
|
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
||||||
|
match self.panel.event(ctx) {
|
||||||
|
Outcome::Clicked(x) => match x.as_ref() {
|
||||||
|
"close" => {
|
||||||
|
return Transition::Pop;
|
||||||
|
}
|
||||||
|
"jump to delay" => {
|
||||||
|
let delay = self.panel.dropdown_value("delay");
|
||||||
|
app.opts.jump_to_delay = delay;
|
||||||
|
return Transition::Replace(TimeWarpScreen::new(
|
||||||
|
ctx,
|
||||||
|
app,
|
||||||
|
app.primary.sim.get_end_of_day(),
|
||||||
|
Some(delay),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
"Jump to time" => {
|
||||||
|
return Transition::Replace(JumpToTime::new(ctx, app, self.maybe_mode.take()));
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
Outcome::Changed => {
|
||||||
self.panel.replace(
|
self.panel.replace(
|
||||||
ctx,
|
ctx,
|
||||||
"jump to delay",
|
"jump to delay",
|
||||||
build_jump_to_delay_button(halt_limit, ctx),
|
build_jump_to_delay_button(ctx, self.panel.dropdown_value("delay")),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
if self.panel.clicked_outside(ctx) {
|
if self.panel.clicked_outside(ctx) {
|
||||||
return Transition::Pop;
|
return Transition::Pop;
|
||||||
@ -293,7 +361,9 @@ impl State for TimeWarpScreen {
|
|||||||
|
|
||||||
self.panel.replace(ctx, "text", txt.draw(ctx).named("text"));
|
self.panel.replace(ctx, "text", txt.draw(ctx).named("text"));
|
||||||
}
|
}
|
||||||
if app.primary.sim.time() == self.target {
|
// >= because of the case of resetting to midnight. GameplayMode::initialize takes a tiny
|
||||||
|
// step past midnight after spawning things, so that agents initially appear on the map.
|
||||||
|
if app.primary.sim.time() >= self.target {
|
||||||
return Transition::Pop;
|
return Transition::Pop;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,39 +447,16 @@ fn compare_count(after: usize, before: usize) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_jump_to_time_btn(target: Time, ctx: &EventCtx) -> Widget {
|
fn build_jump_to_time_btn(ctx: &EventCtx, target: Time) -> Widget {
|
||||||
Btn::text_bg2(format!("Jump to {}", target.ampm_tostring()))
|
Btn::text_bg2(format!("Jump to {}", target.ampm_tostring()))
|
||||||
.build(ctx, "jump to time", hotkey(Key::Enter))
|
.build(ctx, "jump to time", hotkey(Key::Enter))
|
||||||
.named("jump to time")
|
|
||||||
.centered_horiz()
|
.centered_horiz()
|
||||||
.margin_above(16)
|
.margin_above(16)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_jump_to_delay_button(halt_limit: Duration, ctx: &EventCtx) -> Widget {
|
fn build_jump_to_delay_button(ctx: &EventCtx, delay: Duration) -> Widget {
|
||||||
Btn::text_bg2(format!("Jump to next {} delay", halt_limit))
|
Btn::text_bg2(format!("Jump to next {} delay", delay))
|
||||||
.build(ctx, "jump to delay", hotkey(Key::D))
|
.build(ctx, "jump to delay", hotkey(Key::D))
|
||||||
.named("jump to delay")
|
|
||||||
.centered_horiz()
|
.centered_horiz()
|
||||||
.margin_above(16)
|
.margin_above(16)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_jump_to_delay_picker(halt_limit: Duration, ctx: &EventCtx) -> Widget {
|
|
||||||
// EZGUI TODO: it'd be nice if we could style the fg color for persistent splits but this needs
|
|
||||||
// to be passed into the button builder in init. so either we'd need to make a required
|
|
||||||
// argument, or introduce a persistentsplitbuilder, or re-work splitbuilder to allow mutating
|
|
||||||
// the color after the fact which requires holding more state to re-invoke the btnbuilder
|
|
||||||
PersistentSplit::new(
|
|
||||||
ctx,
|
|
||||||
"choose delay",
|
|
||||||
halt_limit,
|
|
||||||
None,
|
|
||||||
vec![
|
|
||||||
Choice::new("1 minute delay", Duration::minutes(1)),
|
|
||||||
Choice::new("2 minute delay", Duration::minutes(2)),
|
|
||||||
Choice::new("5 minute delay", Duration::minutes(5)),
|
|
||||||
Choice::new("10 minute delay", Duration::minutes(10)),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.outline(2.0, Color::WHITE)
|
|
||||||
.centered_horiz()
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user