mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 17:37:22 +03:00
working on a new traffic signal scroller. disabled. decent start.
This commit is contained in:
parent
f82000cff4
commit
430b1245c4
@ -19,18 +19,16 @@
|
||||
## General ezgui stuff
|
||||
|
||||
- optionally limit canvas scrolling/zooming to some map bounds
|
||||
- when dragging, dont give mouse movement to UI elements
|
||||
- start context menu when left click releases and we're not dragging
|
||||
- can we change labels in modal or top menu? show/hide
|
||||
- distinguish hints from status of modal menus, for hiding purposes
|
||||
- move context menus out of ezgui
|
||||
- simplify/remove UserInput.
|
||||
- maybe separate impls for context, wizard, modal menu make sense.
|
||||
- arbitrary viewports?!
|
||||
- tiling wm
|
||||
|
||||
## New features
|
||||
|
||||
- swap direction of one-way
|
||||
- convert between one- and two-way if there's enough space
|
||||
- collapse smaller roads/neighborhoods and just show aggregate stats about them (in/out flow, moving/blocked within)
|
||||
- undo support for edits
|
||||
|
||||
|
@ -344,14 +344,22 @@ impl GeomBatch {
|
||||
self.list.extend(other.list.clone());
|
||||
}
|
||||
|
||||
pub fn consume(self) -> Vec<(Color, Polygon)> {
|
||||
self.list
|
||||
}
|
||||
|
||||
pub fn draw(self, g: &mut GfxCtx) {
|
||||
let refs = self.list.iter().map(|(color, p)| (*color, p)).collect();
|
||||
let obj = g.prerender.upload_temporary(refs);
|
||||
g.redraw(&obj);
|
||||
}
|
||||
|
||||
pub(crate) fn members(&self) -> &Vec<(Color, Polygon)> {
|
||||
&self.list
|
||||
pub(crate) fn get_dims(&self) -> ScreenDims {
|
||||
let mut bounds = Bounds::new();
|
||||
for (_, poly) in &self.list {
|
||||
bounds.union(poly.get_bounds());
|
||||
}
|
||||
ScreenDims::new(bounds.max_x - bounds.min_x, bounds.max_y - bounds.min_y)
|
||||
}
|
||||
}
|
||||
|
||||
@ -469,7 +477,7 @@ impl<'a> Prerender<'a> {
|
||||
}
|
||||
|
||||
pub struct MultiText {
|
||||
list: Vec<(Text, ScreenPt)>,
|
||||
pub(crate) list: Vec<(Text, ScreenPt)>,
|
||||
}
|
||||
|
||||
impl MultiText {
|
||||
|
@ -21,8 +21,8 @@ pub use crate::runner::{run, EventLoopMode, Settings, GUI};
|
||||
pub use crate::screen_geom::{ScreenDims, ScreenPt, ScreenRectangle};
|
||||
pub use crate::text::{Line, Text, TextSpan, HOTKEY_COLOR};
|
||||
pub use crate::widgets::{
|
||||
Autocomplete, Choice, ItemSlider, ModalMenu, Scroller, Slider, SliderWithTextBox, Warper,
|
||||
WarpingItemSlider, Wizard, WrappedWizard,
|
||||
Autocomplete, Choice, ItemSlider, ModalMenu, NewScroller, Scroller, Slider, SliderWithTextBox,
|
||||
Warper, WarpingItemSlider, Wizard, WrappedWizard,
|
||||
};
|
||||
|
||||
pub enum InputResult<T: Clone> {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::layout::Widget;
|
||||
use crate::{Color, Drawable, EventCtx, GeomBatch, GfxCtx, ScreenDims, ScreenPt, ScreenRectangle};
|
||||
use geom::{Bounds, Circle, Distance, Polygon, Pt2D};
|
||||
use geom::{Circle, Distance, Polygon, Pt2D};
|
||||
|
||||
// TODO Tooltips?
|
||||
// TODO Hotkeys?
|
||||
@ -17,8 +17,8 @@ pub struct Button {
|
||||
impl Button {
|
||||
// Top-left should be at Pt2D::new(0.0, 0.0). Must have same dimensions.
|
||||
pub fn new(normal: GeomBatch, hovered: GeomBatch, ctx: &EventCtx) -> Button {
|
||||
let dims = geom_to_dims(&normal);
|
||||
assert_eq!(dims, geom_to_dims(&hovered));
|
||||
let dims = normal.get_dims();
|
||||
assert_eq!(dims, hovered.get_dims());
|
||||
Button {
|
||||
draw_normal: ctx.prerender.upload(normal),
|
||||
draw_hovered: ctx.prerender.upload(hovered),
|
||||
@ -80,16 +80,6 @@ impl Widget for Button {
|
||||
}
|
||||
}
|
||||
|
||||
fn geom_to_dims(batch: &GeomBatch) -> ScreenDims {
|
||||
let mut bounds = Bounds::new();
|
||||
for (_, poly) in batch.members() {
|
||||
bounds.union(poly.get_bounds());
|
||||
}
|
||||
assert!(bounds.min_x >= 0.0);
|
||||
assert!(bounds.min_y >= 0.0);
|
||||
ScreenDims::new(bounds.max_x, bounds.max_y)
|
||||
}
|
||||
|
||||
const ICON_BACKGROUND: Color = Color::grey(0.5);
|
||||
const ICON_BACKGROUND_SELECTED: Color = Color::YELLOW;
|
||||
const ICON_SYMBOL: Color = Color::grey(0.8);
|
||||
|
@ -17,7 +17,7 @@ pub(crate) use self::context_menu::ContextMenu;
|
||||
pub use self::modal_menu::ModalMenu;
|
||||
pub(crate) use self::popup_menu::PopupMenu;
|
||||
pub(crate) use self::screenshot::{screenshot_current, screenshot_everything};
|
||||
pub use self::scroller::Scroller;
|
||||
pub use self::scroller::{NewScroller, Scroller};
|
||||
pub use self::slider::{ItemSlider, Slider, SliderWithTextBox, WarpingItemSlider};
|
||||
pub use self::warper::Warper;
|
||||
pub use self::wizard::{Choice, Wizard, WrappedWizard};
|
||||
|
@ -1,4 +1,7 @@
|
||||
use crate::{Canvas, Color, EventCtx, GfxCtx, Line, ScreenDims, ScreenPt, ScreenRectangle, Text};
|
||||
use crate::{
|
||||
text, Canvas, Color, Drawable, EventCtx, GeomBatch, GfxCtx, Line, MultiText, ScreenDims,
|
||||
ScreenPt, ScreenRectangle, Text,
|
||||
};
|
||||
use geom::{Distance, Polygon, Pt2D};
|
||||
use ordered_float::NotNan;
|
||||
|
||||
@ -266,3 +269,86 @@ impl<T: Clone + Copy> Scroller<T> {
|
||||
self.items.len() - 2
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NewScroller {
|
||||
draw: Drawable,
|
||||
multi_txt: MultiText,
|
||||
total_dims: ScreenDims,
|
||||
zoom: f64,
|
||||
|
||||
offset: f64,
|
||||
|
||||
top_left: ScreenPt,
|
||||
dims: ScreenDims,
|
||||
}
|
||||
|
||||
impl NewScroller {
|
||||
// geom and multi_txt should be in screen-space, with the top_left as (0.0, 0.0).
|
||||
pub fn new(geom: GeomBatch, multi_txt: MultiText, zoom: f64, ctx: &EventCtx) -> NewScroller {
|
||||
let mut total_dims = geom.get_dims();
|
||||
for (txt, top_left) in &multi_txt.list {
|
||||
let (mut w, mut h) = ctx.canvas.text_dims(txt);
|
||||
w += top_left.x;
|
||||
h += top_left.y;
|
||||
if w > total_dims.width {
|
||||
total_dims.width = w;
|
||||
}
|
||||
if h > total_dims.height {
|
||||
total_dims.height = h;
|
||||
}
|
||||
}
|
||||
|
||||
NewScroller {
|
||||
draw: ctx.prerender.upload(geom),
|
||||
multi_txt,
|
||||
total_dims,
|
||||
zoom,
|
||||
|
||||
offset: 0.0,
|
||||
|
||||
// TODO The layouting is hardcoded
|
||||
top_left: ScreenPt::new(0.0, 0.0),
|
||||
dims: ScreenDims::new(100.0, 100.0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event(&mut self, ctx: &mut EventCtx) {
|
||||
let rect = ScreenRectangle::top_left(self.top_left, self.dims);
|
||||
if rect.contains(ctx.canvas.get_cursor_in_screen_space()) {
|
||||
if let Some(scroll) = ctx.input.get_mouse_scroll() {
|
||||
self.offset -= scroll;
|
||||
// TODO Clamp... or maybe last minute, based on dims, which'll get updated by
|
||||
// window resizing and such
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx) {
|
||||
let rect = ScreenRectangle::top_left(self.top_left, self.dims);
|
||||
g.canvas.mark_covered_area(rect);
|
||||
|
||||
g.fork_screenspace();
|
||||
g.draw_polygon(
|
||||
text::BG_COLOR,
|
||||
&Polygon::rectangle_topleft(
|
||||
Pt2D::new(0.0, 0.0),
|
||||
Distance::meters(self.dims.width),
|
||||
Distance::meters(self.dims.height),
|
||||
),
|
||||
);
|
||||
g.unfork();
|
||||
|
||||
g.fork(Pt2D::new(0.0, self.offset), self.top_left, self.zoom);
|
||||
g.redraw(&self.draw);
|
||||
g.unfork();
|
||||
|
||||
for (txt, pt) in &self.multi_txt.list {
|
||||
g.draw_text_at_screenspace_topleft(
|
||||
txt,
|
||||
ScreenPt::new(pt.x, pt.y - self.offset * self.zoom),
|
||||
);
|
||||
}
|
||||
|
||||
// TODO draw scrollbar
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::game::{State, Transition};
|
||||
use crate::helpers::ID;
|
||||
use crate::render::{DrawCtx, DrawOptions, DrawTurn, TrafficSignalDiagram};
|
||||
use crate::render::{DrawOptions, DrawTurn, TrafficSignalDiagram};
|
||||
use crate::ui::{ShowEverything, UI};
|
||||
use ezgui::{hotkey, Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu};
|
||||
use map_model::{IntersectionID, LaneID, Map, TurnType};
|
||||
@ -48,14 +48,14 @@ impl TurnCyclerState {
|
||||
"Traffic Signal Diagram",
|
||||
vec![
|
||||
vec![
|
||||
(hotkey(Key::UpArrow), "select previous cycle"),
|
||||
(hotkey(Key::DownArrow), "select next cycle"),
|
||||
(hotkey(Key::UpArrow), "select previous phase"),
|
||||
(hotkey(Key::DownArrow), "select next phase"),
|
||||
],
|
||||
vec![(hotkey(Key::Escape), "quit")],
|
||||
],
|
||||
ctx,
|
||||
),
|
||||
diagram: TrafficSignalDiagram::new(i, idx, &ui.primary.map, ctx),
|
||||
diagram: TrafficSignalDiagram::new(i, idx, ui, ctx),
|
||||
})));
|
||||
}
|
||||
}
|
||||
@ -144,13 +144,7 @@ impl State for ShowTrafficSignal {
|
||||
&ui.primary.sim,
|
||||
&ShowEverything::new(),
|
||||
);
|
||||
let ctx = DrawCtx {
|
||||
cs: &ui.cs,
|
||||
map: &ui.primary.map,
|
||||
draw_map: &ui.primary.draw_map,
|
||||
sim: &ui.primary.sim,
|
||||
};
|
||||
self.diagram.draw(g, &ctx);
|
||||
self.diagram.draw(g, &ui.draw_ctx());
|
||||
|
||||
self.menu.draw(g);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use crate::debug::DebugMode;
|
||||
use crate::game::{State, Transition, WizardState};
|
||||
use crate::helpers::{ColorScheme, ID};
|
||||
use crate::render::{
|
||||
DrawCtx, DrawIntersection, DrawLane, DrawMap, DrawOptions, DrawRoad, DrawTurn, Renderable,
|
||||
DrawIntersection, DrawLane, DrawMap, DrawOptions, DrawRoad, DrawTurn, Renderable,
|
||||
MIN_ZOOM_FOR_DETAIL,
|
||||
};
|
||||
use crate::sandbox::SandboxMode;
|
||||
@ -227,12 +227,7 @@ impl State for EditMode {
|
||||
// just show diff relative to basemap.
|
||||
let edits = ui.primary.map.get_edits();
|
||||
|
||||
let ctx = DrawCtx {
|
||||
cs: &ui.cs,
|
||||
map: &ui.primary.map,
|
||||
draw_map: &ui.primary.draw_map,
|
||||
sim: &ui.primary.sim,
|
||||
};
|
||||
let ctx = ui.draw_ctx();
|
||||
let mut opts = DrawOptions::new();
|
||||
|
||||
// TODO Similar to drawing areas with traffic or not -- would be convenient to just
|
||||
|
@ -2,7 +2,7 @@ use crate::common::CommonState;
|
||||
use crate::edit::apply_map_edits;
|
||||
use crate::game::{State, Transition, WizardState};
|
||||
use crate::helpers::ID;
|
||||
use crate::render::{draw_signal_phase, DrawCtx, DrawOptions, DrawTurn, TrafficSignalDiagram};
|
||||
use crate::render::{draw_signal_phase, DrawOptions, DrawTurn, TrafficSignalDiagram};
|
||||
use crate::ui::{ShowEverything, UI};
|
||||
use abstutil::Timer;
|
||||
use ezgui::{hotkey, Choice, Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu};
|
||||
@ -49,7 +49,7 @@ impl TrafficSignalEditor {
|
||||
TrafficSignalEditor {
|
||||
menu,
|
||||
icon_selected: None,
|
||||
diagram: TrafficSignalDiagram::new(id, 0, &ui.primary.map, ctx),
|
||||
diagram: TrafficSignalDiagram::new(id, 0, ui, ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -132,7 +132,7 @@ impl State for TrafficSignalEditor {
|
||||
.remove(0)
|
||||
.1;
|
||||
change_traffic_signal(signal, self.diagram.i, ui, ctx);
|
||||
self.diagram = TrafficSignalDiagram::new(self.diagram.i, 0, &ui.primary.map, ctx);
|
||||
self.diagram = TrafficSignalDiagram::new(self.diagram.i, 0, ui, ctx);
|
||||
return Transition::Keep;
|
||||
}
|
||||
|
||||
@ -148,15 +148,13 @@ impl State for TrafficSignalEditor {
|
||||
if current_phase != 0 && self.menu.action("move current phase up") {
|
||||
signal.phases.swap(current_phase, current_phase - 1);
|
||||
change_traffic_signal(signal, self.diagram.i, ui, ctx);
|
||||
self.diagram =
|
||||
TrafficSignalDiagram::new(self.diagram.i, current_phase - 1, &ui.primary.map, ctx);
|
||||
self.diagram = TrafficSignalDiagram::new(self.diagram.i, current_phase - 1, ui, ctx);
|
||||
} else if current_phase != signal.phases.len() - 1
|
||||
&& self.menu.action("move current phase down")
|
||||
{
|
||||
signal.phases.swap(current_phase, current_phase + 1);
|
||||
change_traffic_signal(signal, self.diagram.i, ui, ctx);
|
||||
self.diagram =
|
||||
TrafficSignalDiagram::new(self.diagram.i, current_phase + 1, &ui.primary.map, ctx);
|
||||
self.diagram = TrafficSignalDiagram::new(self.diagram.i, current_phase + 1, ui, ctx);
|
||||
} else if signal.phases.len() > 1 && self.menu.action("delete current phase") {
|
||||
signal.phases.remove(current_phase);
|
||||
let num_phases = signal.phases.len();
|
||||
@ -168,7 +166,7 @@ impl State for TrafficSignalEditor {
|
||||
} else {
|
||||
current_phase
|
||||
},
|
||||
&ui.primary.map,
|
||||
ui,
|
||||
ctx,
|
||||
);
|
||||
} else if self.menu.action("add a new empty phase") {
|
||||
@ -176,8 +174,7 @@ impl State for TrafficSignalEditor {
|
||||
.phases
|
||||
.insert(current_phase, Phase::new(self.diagram.i));
|
||||
change_traffic_signal(signal, self.diagram.i, ui, ctx);
|
||||
self.diagram =
|
||||
TrafficSignalDiagram::new(self.diagram.i, current_phase, &ui.primary.map, ctx);
|
||||
self.diagram = TrafficSignalDiagram::new(self.diagram.i, current_phase, ui, ctx);
|
||||
} else if has_sidewalks && self.menu.action("add a new pedestrian scramble phase") {
|
||||
let mut phase = Phase::new(self.diagram.i);
|
||||
for t in ui.primary.map.get_turns_in_intersection(self.diagram.i) {
|
||||
@ -187,8 +184,7 @@ impl State for TrafficSignalEditor {
|
||||
}
|
||||
signal.phases.insert(current_phase, phase);
|
||||
change_traffic_signal(signal, self.diagram.i, ui, ctx);
|
||||
self.diagram =
|
||||
TrafficSignalDiagram::new(self.diagram.i, current_phase, &ui.primary.map, ctx);
|
||||
self.diagram = TrafficSignalDiagram::new(self.diagram.i, current_phase, ui, ctx);
|
||||
} else if has_sidewalks
|
||||
&& self
|
||||
.menu
|
||||
@ -196,7 +192,7 @@ impl State for TrafficSignalEditor {
|
||||
{
|
||||
signal.convert_to_ped_scramble(&ui.primary.map);
|
||||
change_traffic_signal(signal, self.diagram.i, ui, ctx);
|
||||
self.diagram = TrafficSignalDiagram::new(self.diagram.i, 0, &ui.primary.map, ctx);
|
||||
self.diagram = TrafficSignalDiagram::new(self.diagram.i, 0, ui, ctx);
|
||||
}
|
||||
|
||||
Transition::Keep
|
||||
@ -210,12 +206,7 @@ impl State for TrafficSignalEditor {
|
||||
}
|
||||
|
||||
let mut batch = GeomBatch::new();
|
||||
let ctx = DrawCtx {
|
||||
cs: &ui.cs,
|
||||
map: &ui.primary.map,
|
||||
draw_map: &ui.primary.draw_map,
|
||||
sim: &ui.primary.sim,
|
||||
};
|
||||
let ctx = ui.draw_ctx();
|
||||
let map = &ui.primary.map;
|
||||
let phase = &map.get_traffic_signal(self.diagram.i).phases[self.diagram.current_phase()];
|
||||
for t in &ui.primary.draw_map.get_turns(self.diagram.i, map) {
|
||||
@ -285,7 +276,7 @@ fn make_change_phase_duration(current_duration: Duration) -> Box<dyn State> {
|
||||
let idx = editor.diagram.current_phase();
|
||||
signal.phases[idx].duration = Duration::seconds(new_duration as f64);
|
||||
change_traffic_signal(signal, editor.diagram.i, ui, ctx);
|
||||
editor.diagram = TrafficSignalDiagram::new(editor.diagram.i, idx, &ui.primary.map, ctx);
|
||||
editor.diagram = TrafficSignalDiagram::new(editor.diagram.i, idx, ui, ctx);
|
||||
})))
|
||||
}))
|
||||
}
|
||||
@ -303,7 +294,7 @@ fn make_change_preset(i: IntersectionID) -> Box<dyn State> {
|
||||
Some(Transition::PopWithData(Box::new(move |state, ui, ctx| {
|
||||
let mut editor = state.downcast_mut::<TrafficSignalEditor>().unwrap();
|
||||
change_traffic_signal(new_signal, editor.diagram.i, ui, ctx);
|
||||
editor.diagram = TrafficSignalDiagram::new(editor.diagram.i, 0, &ui.primary.map, ctx);
|
||||
editor.diagram = TrafficSignalDiagram::new(editor.diagram.i, 0, ui, ctx);
|
||||
})))
|
||||
}))
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
use crate::render::{DrawCtx, DrawTurn};
|
||||
use crate::ui::UI;
|
||||
use ezgui::{
|
||||
Color, EventCtx, GeomBatch, GfxCtx, Line, ModalMenu, ScreenDims, ScreenPt, Scroller, Text,
|
||||
Color, EventCtx, GeomBatch, GfxCtx, Line, ModalMenu, MultiText, NewScroller, ScreenDims,
|
||||
ScreenPt, Scroller, Text,
|
||||
};
|
||||
use geom::{Circle, Distance, Duration, Line, Polygon, Pt2D};
|
||||
use map_model::{IntersectionID, Map, Phase, TurnPriority, TurnType, LANE_THICKNESS};
|
||||
use map_model::{IntersectionID, Phase, TurnPriority, TurnType, LANE_THICKNESS};
|
||||
use ordered_float::NotNan;
|
||||
|
||||
// Only draws a box when time_left is present
|
||||
@ -221,7 +223,7 @@ fn draw_signal_phase_with_icons(phase: &Phase, batch: &mut GeomBatch, ctx: &Draw
|
||||
}
|
||||
|
||||
const PADDING: f64 = 5.0;
|
||||
const ZOOM: f64 = 10.0;
|
||||
const ZOOM: f64 = 15.0;
|
||||
|
||||
pub struct TrafficSignalDiagram {
|
||||
pub i: IntersectionID,
|
||||
@ -230,17 +232,19 @@ pub struct TrafficSignalDiagram {
|
||||
intersection_width: f64, // TODO needed?
|
||||
// The usizes are phase indices
|
||||
scroller: Scroller<usize>,
|
||||
|
||||
new_scroller: NewScroller,
|
||||
}
|
||||
|
||||
impl TrafficSignalDiagram {
|
||||
pub fn new(
|
||||
i: IntersectionID,
|
||||
current_phase: usize,
|
||||
map: &Map,
|
||||
ui: &UI,
|
||||
ctx: &EventCtx,
|
||||
) -> TrafficSignalDiagram {
|
||||
let (top_left, intersection_width, intersection_height) = {
|
||||
let b = map.get_i(i).polygon.get_bounds();
|
||||
let b = ui.primary.map.get_i(i).polygon.get_bounds();
|
||||
(
|
||||
Pt2D::new(b.min_x, b.min_y),
|
||||
b.max_x - b.min_x,
|
||||
@ -248,7 +252,7 @@ impl TrafficSignalDiagram {
|
||||
b.max_y - b.min_y,
|
||||
)
|
||||
};
|
||||
let phases = &map.get_traffic_signal(i).phases;
|
||||
let phases = &ui.primary.map.get_traffic_signal(i).phases;
|
||||
|
||||
// Precalculate maximum text width.
|
||||
let mut labels = Vec::new();
|
||||
@ -285,6 +289,8 @@ impl TrafficSignalDiagram {
|
||||
top_left,
|
||||
intersection_width,
|
||||
scroller,
|
||||
|
||||
new_scroller: make_new_scroller(i, &ui.draw_ctx(), ctx),
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,6 +307,8 @@ impl TrafficSignalDiagram {
|
||||
self.scroller.select_next(ctx.canvas);
|
||||
return;
|
||||
}
|
||||
|
||||
//self.new_scroller.event(ctx);
|
||||
}
|
||||
|
||||
pub fn current_phase(&self) -> usize {
|
||||
@ -324,5 +332,39 @@ impl TrafficSignalDiagram {
|
||||
}
|
||||
|
||||
g.unfork();
|
||||
|
||||
//self.new_scroller.draw(g);
|
||||
}
|
||||
}
|
||||
|
||||
fn make_new_scroller(i: IntersectionID, draw_ctx: &DrawCtx, ctx: &EventCtx) -> NewScroller {
|
||||
// TODO Nicer API would be passing in a list of (GeomBatch, MultiText)s each starting at the
|
||||
// origin, then do the translation later.
|
||||
let mut master_batch = GeomBatch::new();
|
||||
let mut txt = MultiText::new();
|
||||
|
||||
// Slightly inaccurate -- the turn rendering may slightly exceed the intersection polygon --
|
||||
// but this is close enough.
|
||||
let bounds = draw_ctx.map.get_i(i).polygon.get_bounds();
|
||||
let mut y_offset = 0.0;
|
||||
for (idx, phase) in draw_ctx.map.get_traffic_signal(i).phases.iter().enumerate() {
|
||||
let mut batch = GeomBatch::new();
|
||||
draw_signal_phase(phase, None, &mut batch, draw_ctx);
|
||||
for (color, poly) in batch.consume() {
|
||||
master_batch.push(
|
||||
color,
|
||||
poly.translate(
|
||||
Distance::meters(-bounds.min_x),
|
||||
Distance::meters(y_offset - bounds.min_y),
|
||||
),
|
||||
);
|
||||
}
|
||||
txt.add(
|
||||
Text::from(Line(format!("Phase {}: {}", idx + 1, phase.duration))),
|
||||
ScreenPt::new(10.0 + (bounds.max_x - bounds.min_x) * ZOOM, y_offset * ZOOM),
|
||||
);
|
||||
y_offset += bounds.max_y - bounds.min_y;
|
||||
}
|
||||
|
||||
NewScroller::new(master_batch, txt, ZOOM, ctx)
|
||||
}
|
||||
|
@ -80,6 +80,15 @@ impl UI {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_ctx<'a>(&'a self) -> DrawCtx<'a> {
|
||||
DrawCtx {
|
||||
cs: &self.cs,
|
||||
map: &self.primary.map,
|
||||
draw_map: &self.primary.draw_map,
|
||||
sim: &self.primary.sim,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(
|
||||
&self,
|
||||
g: &mut GfxCtx,
|
||||
@ -87,12 +96,7 @@ impl UI {
|
||||
source: &dyn GetDrawAgents,
|
||||
show_objs: &dyn ShowObject,
|
||||
) {
|
||||
let ctx = DrawCtx {
|
||||
cs: &self.cs,
|
||||
map: &self.primary.map,
|
||||
draw_map: &self.primary.draw_map,
|
||||
sim: &self.primary.sim,
|
||||
};
|
||||
let ctx = self.draw_ctx();
|
||||
let mut sample_intersection: Option<String> = None;
|
||||
|
||||
g.clear(self.cs.get_def("true background", Color::BLACK));
|
||||
|
Loading…
Reference in New Issue
Block a user