diff --git a/ezgui/src/drawing.rs b/ezgui/src/drawing.rs
index cdff24899b..0d8d68284c 100644
--- a/ezgui/src/drawing.rs
+++ b/ezgui/src/drawing.rs
@@ -630,4 +630,9 @@ impl DrawBoth {
pub fn get_dims(&self) -> ScreenDims {
self.dims
}
+
+ // TODO Hack
+ pub(crate) fn override_bounds(&mut self, b: Bounds) {
+ self.dims = ScreenDims::new(b.max_x - b.min_x, b.max_y - b.min_y);
+ }
}
diff --git a/ezgui/src/layout.rs b/ezgui/src/layout.rs
index 9cf2846186..5b5a48f133 100644
--- a/ezgui/src/layout.rs
+++ b/ezgui/src/layout.rs
@@ -48,3 +48,13 @@ pub fn stack_vertically(
top_left.y += dims.height;
}
}
+
+pub fn stack_horizontally(top_left: ScreenPt, padding: f64, widgets: Vec<&mut dyn Widget>) {
+ let mut x1 = top_left.x;
+ let y1 = top_left.y;
+
+ for w in widgets {
+ w.set_pos(ScreenPt::new(x1, y1));
+ x1 += w.get_dims().width + padding;
+ }
+}
diff --git a/ezgui/src/widgets/no_op.rs b/ezgui/src/widgets/no_op.rs
index 4e7bd8a171..e34ccac13c 100644
--- a/ezgui/src/widgets/no_op.rs
+++ b/ezgui/src/widgets/no_op.rs
@@ -10,6 +10,13 @@ pub struct JustDraw {
}
impl JustDraw {
+ pub fn wrap(draw: DrawBoth) -> JustDraw {
+ JustDraw {
+ draw,
+ top_left: ScreenPt::new(0.0, 0.0),
+ }
+ }
+
pub fn image(filename: &str, ctx: &EventCtx) -> JustDraw {
let (color, rect) = ctx.canvas.texture_rect(filename);
let batch = GeomBatch::from(vec![(color, rect)]);
@@ -21,9 +28,12 @@ impl JustDraw {
pub fn svg(filename: &str, ctx: &EventCtx) -> JustDraw {
let mut batch = GeomBatch::new();
- svg::add_svg(&mut batch, filename);
+ let bounds = svg::add_svg(&mut batch, filename);
+ let mut draw = DrawBoth::new(ctx, batch, vec![]);
+ // TODO The dims will be wrong; it'll only look at geometry, not the padding in the image.
+ draw.override_bounds(bounds);
JustDraw {
- draw: DrawBoth::new(ctx, batch, vec![]),
+ draw,
top_left: ScreenPt::new(0.0, 0.0),
}
}
diff --git a/game/assets/meters/bike.svg b/game/assets/meters/bike.svg
new file mode 100644
index 0000000000..a70fa1667a
--- /dev/null
+++ b/game/assets/meters/bike.svg
@@ -0,0 +1,3 @@
+
diff --git a/game/assets/meters/bus.svg b/game/assets/meters/bus.svg
new file mode 100644
index 0000000000..fc7016121d
--- /dev/null
+++ b/game/assets/meters/bus.svg
@@ -0,0 +1,3 @@
+
diff --git a/game/assets/meters/car.svg b/game/assets/meters/car.svg
new file mode 100644
index 0000000000..d7206ea7fe
--- /dev/null
+++ b/game/assets/meters/car.svg
@@ -0,0 +1,3 @@
+
diff --git a/game/assets/meters/pedestrian.svg b/game/assets/meters/pedestrian.svg
new file mode 100644
index 0000000000..1e7928508b
--- /dev/null
+++ b/game/assets/meters/pedestrian.svg
@@ -0,0 +1,3 @@
+
diff --git a/game/src/sandbox/mod.rs b/game/src/sandbox/mod.rs
index b96eebb782..ebd1368f41 100644
--- a/game/src/sandbox/mod.rs
+++ b/game/src/sandbox/mod.rs
@@ -16,17 +16,18 @@ use crate::pregame::main_menu;
use crate::ui::{ShowEverything, UI};
use abstutil::Timer;
use ezgui::{
- hotkey, layout, lctrl, Choice, EventCtx, EventLoopMode, GfxCtx, Key, Line, MenuUnderButton,
- ModalMenu, Text,
+ hotkey, layout, lctrl, Choice, Color, DrawBoth, EventCtx, EventLoopMode, GeomBatch, GfxCtx,
+ JustDraw, Key, Line, MenuUnderButton, ModalMenu, ScreenDims, ScreenPt, ScreenRectangle, Text,
};
pub use gameplay::spawner::spawn_agents_around;
pub use gameplay::GameplayMode;
-use geom::Duration;
+use geom::{Distance, Duration, Polygon, Time};
use map_model::MapEdits;
use sim::TripMode;
pub struct SandboxMode {
speed: speed::SpeedControls,
+ agent_meter: AgentMeter,
info_tools: MenuUnderButton,
general_tools: MenuUnderButton,
agent_tools: AgentTools,
@@ -41,6 +42,7 @@ impl SandboxMode {
pub fn new(ctx: &mut EventCtx, ui: &mut UI, mode: GameplayMode) -> SandboxMode {
SandboxMode {
speed: speed::SpeedControls::new(ctx, ui.opts.dev),
+ agent_meter: AgentMeter::new(ctx, ui),
general_tools: MenuUnderButton::new(
"assets/ui/hamburger.png",
"General",
@@ -88,16 +90,6 @@ impl State for SandboxMode {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
{
let mut txt = Text::new();
- let (active, unfinished, by_mode) = ui.primary.sim.num_trips();
- txt.add(Line(format!("Active trips: {}", active)));
- txt.add(Line(format!("Unfinished trips: {}", unfinished)));
- txt.add(Line(format!(
- "Peds {}, Bikes {}, Cars {}, Buses {}",
- by_mode[&TripMode::Walk],
- by_mode[&TripMode::Bike],
- by_mode[&TripMode::Drive],
- by_mode[&TripMode::Transit]
- )));
txt.add(Line(""));
{
let edits = ui.primary.map.get_edits();
@@ -108,6 +100,7 @@ impl State for SandboxMode {
}
self.menu.set_info(ctx, txt);
}
+ self.agent_meter.event(ctx, ui);
if let Some(t) = self.gameplay.event(ctx, ui, &mut self.overlay) {
return t;
}
@@ -315,6 +308,7 @@ impl State for SandboxMode {
self.info_tools.draw(g);
self.general_tools.draw(g);
self.gameplay.draw(g, ui);
+ self.agent_meter.draw(g);
if let Some(ref m) = self.minimap {
m.draw(g, ui);
}
@@ -324,3 +318,81 @@ impl State for SandboxMode {
self.speed.pause();
}
}
+
+// TODO Some kind of composite thing...
+struct AgentMeter {
+ time: Time,
+ widgets: Vec,
+ rect: ScreenRectangle,
+}
+
+impl AgentMeter {
+ pub fn new(ctx: &EventCtx, ui: &UI) -> AgentMeter {
+ let (active, unfinished, by_mode) = ui.primary.sim.num_trips();
+
+ let mut row1_txt = Text::new().no_bg();
+ row1_txt.add(Line(format!("Active trips: {}", active)));
+ row1_txt.add(Line(format!("Unfinished trips: {}", unfinished)));
+
+ // TODO Hardcoding guessed dims
+ let rect_bg = GeomBatch::from(vec![(
+ Color::grey(0.4),
+ Polygon::rounded_rectangle(
+ Distance::meters(290.0),
+ Distance::meters(100.0),
+ Distance::meters(5.0),
+ ),
+ )]);
+
+ // TODO Rectangle behind everything
+ let mut widgets = vec![
+ JustDraw::wrap(DrawBoth::new(ctx, rect_bg, Vec::new())),
+ JustDraw::text(row1_txt, ctx),
+ JustDraw::svg("assets/meters/pedestrian.svg", ctx),
+ JustDraw::text(Text::from(Line(&by_mode[&TripMode::Walk])).no_bg(), ctx),
+ JustDraw::svg("assets/meters/bike.svg", ctx),
+ JustDraw::text(Text::from(Line(&by_mode[&TripMode::Bike])).no_bg(), ctx),
+ JustDraw::svg("assets/meters/car.svg", ctx),
+ JustDraw::text(Text::from(Line(&by_mode[&TripMode::Drive])).no_bg(), ctx),
+ JustDraw::svg("assets/meters/bus.svg", ctx),
+ JustDraw::text(Text::from(Line(&by_mode[&TripMode::Transit])).no_bg(), ctx),
+ ];
+
+ // TODO A horrible experiment in manual layouting
+ use layout::Widget;
+
+ let top_left = ScreenPt::new(ctx.canvas.window_width - 300.0, 350.0);
+ widgets[0].set_pos(top_left);
+ widgets[1].set_pos(top_left);
+ let top_left = ScreenPt::new(top_left.x, top_left.y + widgets[1].get_dims().height);
+ layout::stack_horizontally(
+ top_left,
+ // TODO Padding is wrong, want to alternate the amount
+ 5.0,
+ widgets
+ .iter_mut()
+ .skip(2)
+ .map(|w| w as &mut dyn Widget)
+ .collect(),
+ );
+ AgentMeter {
+ widgets,
+ time: ui.primary.sim.time(),
+ rect: ScreenRectangle::top_left(top_left, ScreenDims::new(290.0, 100.0)),
+ }
+ }
+
+ pub fn event(&mut self, ctx: &EventCtx, ui: &UI) {
+ // TODO Or window size changed...
+ if self.time != ui.primary.sim.time() {
+ *self = AgentMeter::new(ctx, ui);
+ }
+ }
+
+ pub fn draw(&self, g: &mut GfxCtx) {
+ for w in &self.widgets {
+ w.draw(g);
+ }
+ g.canvas.mark_covered_area(self.rect.clone());
+ }
+}