mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 23:43:25 +03:00
configurable "jump to delay"
This commit is contained in:
parent
d8d2877c14
commit
e5620aeb10
@ -99,7 +99,7 @@ impl EditMode {
|
|||||||
Transition::Multi(vec![
|
Transition::Multi(vec![
|
||||||
Transition::Pop,
|
Transition::Pop,
|
||||||
Transition::Replace(SandboxMode::new(ctx, app, self.mode.clone())),
|
Transition::Replace(SandboxMode::new(ctx, app, self.mode.clone())),
|
||||||
Transition::Push(TimeWarpScreen::new(ctx, app, old_sim.time(), false)),
|
Transition::Push(TimeWarpScreen::new(ctx, app, old_sim.time(), None)),
|
||||||
])
|
])
|
||||||
} else {
|
} else {
|
||||||
app.primary.sim = old_sim;
|
app.primary.sim = old_sim;
|
||||||
|
@ -548,7 +548,7 @@ impl InfoPanel {
|
|||||||
&mut actions,
|
&mut actions,
|
||||||
);
|
);
|
||||||
|
|
||||||
vec![sandbox, TimeWarpScreen::new(ctx, app, time, false)]
|
vec![sandbox, TimeWarpScreen::new(ctx, app, time, None)]
|
||||||
},
|
},
|
||||||
))),
|
))),
|
||||||
)
|
)
|
||||||
|
@ -208,7 +208,7 @@ impl SpeedControls {
|
|||||||
ctx,
|
ctx,
|
||||||
app,
|
app,
|
||||||
app.primary.sim.time() + dt,
|
app.primary.sim.time() + dt,
|
||||||
false,
|
None,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
@ -351,6 +351,7 @@ impl SpeedControls {
|
|||||||
struct JumpToTime {
|
struct JumpToTime {
|
||||||
panel: Panel,
|
panel: Panel,
|
||||||
target: Time,
|
target: Time,
|
||||||
|
halt_limit: Duration,
|
||||||
maybe_mode: Option<GameplayMode>,
|
maybe_mode: Option<GameplayMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,8 +359,10 @@ impl JumpToTime {
|
|||||||
fn new(ctx: &mut EventCtx, app: &App, maybe_mode: Option<GameplayMode>) -> JumpToTime {
|
fn new(ctx: &mut EventCtx, app: &App, maybe_mode: Option<GameplayMode>) -> JumpToTime {
|
||||||
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 = Duration::minutes(5);
|
||||||
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![
|
Widget::row(vec![
|
||||||
@ -368,6 +371,15 @@ impl JumpToTime {
|
|||||||
.build(ctx, "close", hotkey(Key::Escape))
|
.build(ctx, "close", hotkey(Key::Escape))
|
||||||
.align_right(),
|
.align_right(),
|
||||||
]),
|
]),
|
||||||
|
Checkbox::checkbox(
|
||||||
|
ctx,
|
||||||
|
"skip drawing (for faster simulations)",
|
||||||
|
None,
|
||||||
|
app.opts.dont_draw_time_warp,
|
||||||
|
)
|
||||||
|
.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,
|
||||||
@ -390,23 +402,16 @@ 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")
|
||||||
Btn::text_bg2(format!("Jump to {}", target.ampm_tostring()))
|
|
||||||
.build(ctx, "jump to time", hotkey(Key::Enter))
|
|
||||||
.centered_horiz()
|
.centered_horiz()
|
||||||
.named("jump to time"),
|
// EZGUI FIXME: margin_below having no effect here, so instead we add a margin_top
|
||||||
Widget::horiz_separator(ctx, 0.25).margin_above(10),
|
// to the subsequent element
|
||||||
Btn::text_bg2("Jump to the next delay over 5 minutes")
|
//.margin_above(16).margin_below(16),
|
||||||
.build_def(ctx, None)
|
.margin_above(16),
|
||||||
.centered_horiz(),
|
build_jump_to_time_btn(target, ctx),
|
||||||
Checkbox::checkbox(
|
Widget::horiz_separator(ctx, 0.25).margin_above(16),
|
||||||
ctx,
|
build_jump_to_delay_picker(halt_limit, ctx).margin_above(16),
|
||||||
"don't draw (for faster simulations)",
|
build_jump_to_delay_button(halt_limit, ctx),
|
||||||
None,
|
|
||||||
app.opts.dont_draw_time_warp,
|
|
||||||
)
|
|
||||||
.margin_above(30)
|
|
||||||
.named("don't draw"),
|
|
||||||
]))
|
]))
|
||||||
.build(ctx),
|
.build(ctx),
|
||||||
}
|
}
|
||||||
@ -425,7 +430,7 @@ impl State for JumpToTime {
|
|||||||
if let Some(mode) = self.maybe_mode.take() {
|
if let Some(mode) = self.maybe_mode.take() {
|
||||||
return Transition::Multi(vec![
|
return Transition::Multi(vec![
|
||||||
Transition::Replace(SandboxMode::new(ctx, app, mode)),
|
Transition::Replace(SandboxMode::new(ctx, app, mode)),
|
||||||
Transition::Push(TimeWarpScreen::new(ctx, app, self.target, false)),
|
Transition::Push(TimeWarpScreen::new(ctx, app, self.target, None)),
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
return Transition::Replace(PopupMsg::new(
|
return Transition::Replace(PopupMsg::new(
|
||||||
@ -435,14 +440,15 @@ impl State for JumpToTime {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Transition::Replace(TimeWarpScreen::new(ctx, app, self.target, false));
|
return Transition::Replace(TimeWarpScreen::new(ctx, app, self.target, None));
|
||||||
}
|
}
|
||||||
"Jump to the next delay over 5 minutes" => {
|
"choose delay" => return Transition::Keep,
|
||||||
|
"jump to delay" => {
|
||||||
return Transition::Replace(TimeWarpScreen::new(
|
return Transition::Replace(TimeWarpScreen::new(
|
||||||
ctx,
|
ctx,
|
||||||
app,
|
app,
|
||||||
app.primary.sim.get_end_of_day(),
|
app.primary.sim.get_end_of_day(),
|
||||||
true,
|
Some(self.panel.persistent_split_value("choose delay")),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
@ -460,15 +466,20 @@ impl State for JumpToTime {
|
|||||||
.round_seconds(600.0);
|
.round_seconds(600.0);
|
||||||
if target != self.target {
|
if target != self.target {
|
||||||
self.target = target;
|
self.target = target;
|
||||||
|
self.panel
|
||||||
|
.replace(ctx, "jump to time", build_jump_to_time_btn(target, ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
let halt_limit = self.panel.persistent_split_value("choose delay");
|
||||||
|
if halt_limit != self.halt_limit {
|
||||||
|
self.halt_limit = halt_limit;
|
||||||
self.panel.replace(
|
self.panel.replace(
|
||||||
ctx,
|
ctx,
|
||||||
"jump to time",
|
"jump to delay",
|
||||||
Btn::text_bg2(format!("Jump to {}", target.ampm_tostring()))
|
build_jump_to_delay_button(halt_limit, ctx),
|
||||||
.build(ctx, "jump to time", hotkey(Key::Enter))
|
|
||||||
.centered_horiz()
|
|
||||||
.named("jump to time"),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.panel.clicked_outside(ctx) {
|
if self.panel.clicked_outside(ctx) {
|
||||||
return Transition::Pop;
|
return Transition::Pop;
|
||||||
}
|
}
|
||||||
@ -486,7 +497,7 @@ impl State for JumpToTime {
|
|||||||
pub struct TimeWarpScreen {
|
pub struct TimeWarpScreen {
|
||||||
target: Time,
|
target: Time,
|
||||||
started: Instant,
|
started: Instant,
|
||||||
traffic_jams: bool,
|
halt_upon_delay: Option<Duration>,
|
||||||
panel: Panel,
|
panel: Panel,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,26 +506,26 @@ impl TimeWarpScreen {
|
|||||||
ctx: &mut EventCtx,
|
ctx: &mut EventCtx,
|
||||||
app: &mut App,
|
app: &mut App,
|
||||||
target: Time,
|
target: Time,
|
||||||
mut traffic_jams: bool,
|
mut halt_upon_delay: Option<Duration>,
|
||||||
) -> Box<dyn State> {
|
) -> Box<dyn State> {
|
||||||
if traffic_jams {
|
if let Some(halt_limit) = halt_upon_delay {
|
||||||
if app.primary.sim_cb.is_none() {
|
if app.primary.sim_cb.is_none() {
|
||||||
app.primary.sim_cb = Some(Box::new(FindDelayedIntersections {
|
app.primary.sim_cb = Some(Box::new(FindDelayedIntersections {
|
||||||
halt_limit: Duration::minutes(5),
|
halt_limit,
|
||||||
report_limit: Duration::minutes(5),
|
report_limit: halt_limit,
|
||||||
currently_delayed: Vec::new(),
|
currently_delayed: Vec::new(),
|
||||||
}));
|
}));
|
||||||
// TODO Can we get away with less frequently? Not sure about all the edge cases
|
// TODO Can we get away with less frequently? Not sure about all the edge cases
|
||||||
app.primary.sim.set_periodic_callback(Duration::minutes(1));
|
app.primary.sim.set_periodic_callback(Duration::minutes(1));
|
||||||
} else {
|
} else {
|
||||||
traffic_jams = false;
|
halt_upon_delay = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Box::new(TimeWarpScreen {
|
Box::new(TimeWarpScreen {
|
||||||
target,
|
target,
|
||||||
started: Instant::now(),
|
started: Instant::now(),
|
||||||
traffic_jams,
|
halt_upon_delay,
|
||||||
panel: Panel::new(Widget::col(vec![
|
panel: Panel::new(Widget::col(vec![
|
||||||
Text::new().draw(ctx).named("text"),
|
Text::new().draw(ctx).named("text"),
|
||||||
Btn::text_bg2("stop now")
|
Btn::text_bg2("stop now")
|
||||||
@ -648,7 +659,7 @@ impl State for TimeWarpScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_destroy(&mut self, _: &mut EventCtx, app: &mut App) {
|
fn on_destroy(&mut self, _: &mut EventCtx, app: &mut App) {
|
||||||
if self.traffic_jams {
|
if self.halt_upon_delay.is_some() {
|
||||||
assert!(app.primary.sim_cb.is_some());
|
assert!(app.primary.sim_cb.is_some());
|
||||||
app.primary.sim_cb = None;
|
app.primary.sim_cb = None;
|
||||||
app.primary.sim.unset_periodic_callback();
|
app.primary.sim.unset_periodic_callback();
|
||||||
@ -761,3 +772,40 @@ fn compare_count(after: usize, before: usize) -> String {
|
|||||||
format!("-{}", prettyprint_usize(before - after))
|
format!("-{}", prettyprint_usize(before - after))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_jump_to_time_btn(target: Time, ctx: &EventCtx) -> Widget {
|
||||||
|
Btn::text_bg2(format!("Jump to {}", target.ampm_tostring()))
|
||||||
|
.build(ctx, "jump to time", hotkey(Key::Enter))
|
||||||
|
.named("jump to time")
|
||||||
|
.centered_horiz()
|
||||||
|
.margin_above(16)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_jump_to_delay_button(halt_limit: Duration, ctx: &EventCtx) -> Widget {
|
||||||
|
Btn::text_bg2(format!("Jump to next {} delay", halt_limit))
|
||||||
|
.build(ctx, "jump to delay", hotkey(Key::D))
|
||||||
|
.named("jump to delay")
|
||||||
|
.centered_horiz()
|
||||||
|
.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()
|
||||||
|
}
|
||||||
|
@ -471,6 +471,8 @@ impl IntersectionSimState {
|
|||||||
std::mem::replace(&mut self.events, Vec::new())
|
std::mem::replace(&mut self.events, Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns intersections with travelers waiting for at least `threshold` since `now`, ordered
|
||||||
|
/// so the longest delayed intersection is first.
|
||||||
pub fn delayed_intersections(
|
pub fn delayed_intersections(
|
||||||
&self,
|
&self,
|
||||||
now: Time,
|
now: Time,
|
||||||
|
Loading…
Reference in New Issue
Block a user