Place layer panels and info panels in the same place, on the left side of the screen. Simplify layer code, now that we don't need to align relative to the minimap.

This commit is contained in:
Dustin Carlino 2021-03-17 11:26:08 -07:00
parent 24a60b0b29
commit 1773782975
12 changed files with 82 additions and 179 deletions

View File

@ -11,14 +11,15 @@ use sim::{
VehicleType,
};
use widgetry::{
Color, ControlState, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key, Line,
LinePlot, Outcome, Panel, PlotOptions, Series, TextExt, Toggle, VerticalAlignment, Widget,
Color, ControlState, Drawable, EventCtx, GeomBatch, GfxCtx, Key, Line, LinePlot, Outcome,
Panel, PlotOptions, Series, TextExt, Toggle, Widget,
};
use crate::app::{App, Transition};
use crate::common::{color_for_agent_type, Warping};
use crate::debug::path_counter::PathCounter;
use crate::edit::{EditMode, RouteEditor};
use crate::layer::PANEL_PLACEMENT;
use crate::sandbox::{dashboards, GameplayMode, SandboxMode, TimeWarpScreen};
mod building;
@ -440,10 +441,7 @@ impl InfoPanel {
time: app.primary.sim.time(),
is_paused: ctx_actions.is_paused(),
panel: Panel::new(Widget::col(col).bg(app.cs.panel_bg).padding(16))
.aligned(
HorizontalAlignment::Percent(0.02),
VerticalAlignment::Percent(0.2),
)
.aligned_pair(PANEL_PLACEMENT)
// TODO Some headings are too wide.. Intersection #xyz (Traffic signals)
.exact_size_percent(30, 60)
.build_custom(ctx),

View File

@ -1,12 +1,9 @@
use geom::{ArrowCap, Distance, PolyLine};
use map_gui::tools::{ColorLegend, ColorNetwork};
use widgetry::{
Color, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Line, Panel, Text,
VerticalAlignment, Widget,
};
use widgetry::{Color, Drawable, EventCtx, GeomBatch, GfxCtx, Line, Panel, Text, Widget};
use crate::app::App;
use crate::layer::{header, Layer, LayerOutcome};
use crate::layer::{header, Layer, LayerOutcome, PANEL_PLACEMENT};
pub struct Elevation {
unzoomed: Drawable,
@ -18,8 +15,8 @@ impl Layer for Elevation {
fn name(&self) -> Option<&'static str> {
Some("elevation")
}
fn event(&mut self, ctx: &mut EventCtx, _: &mut App, minimap: &Panel) -> Option<LayerOutcome> {
Layer::simple_event(ctx, minimap, &mut self.panel)
fn event(&mut self, ctx: &mut EventCtx, _: &mut App) -> Option<LayerOutcome> {
Layer::simple_event(ctx, &mut self.panel)
}
fn draw(&self, g: &mut GfxCtx, app: &App) {
self.panel.draw(g);
@ -96,7 +93,7 @@ impl Elevation {
.into_widget(ctx),
ColorLegend::gradient(ctx, &app.cs.good_to_bad_red, vec!["flat", "steep"]),
]))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx);
Elevation {

View File

@ -5,13 +5,10 @@ use serde::{Deserialize, Serialize};
use abstutil::Timer;
use map_model::osm::OsmID;
use map_model::BuildingID;
use widgetry::{
Color, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Panel, RewriteColor,
VerticalAlignment,
};
use widgetry::{Color, Drawable, EventCtx, GeomBatch, GfxCtx, Panel, RewriteColor};
use crate::app::App;
use crate::layer::{header, Layer, LayerOutcome};
use crate::layer::{header, Layer, LayerOutcome, PANEL_PLACEMENT};
/// A set of buildings that the player has starred, persisted as player data.
#[derive(Serialize, Deserialize)]
@ -63,8 +60,8 @@ impl Layer for ShowFavorites {
fn name(&self) -> Option<&'static str> {
Some("favorites")
}
fn event(&mut self, ctx: &mut EventCtx, _: &mut App, minimap: &Panel) -> Option<LayerOutcome> {
Layer::simple_event(ctx, minimap, &mut self.panel)
fn event(&mut self, ctx: &mut EventCtx, _: &mut App) -> Option<LayerOutcome> {
Layer::simple_event(ctx, &mut self.panel)
}
fn draw(&self, g: &mut GfxCtx, _: &App) {
self.panel.draw(g);
@ -89,7 +86,7 @@ impl ShowFavorites {
}
let panel = Panel::new(header(ctx, "Your favorite buildings"))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx);
ShowFavorites {

View File

@ -6,13 +6,10 @@ use map_gui::tools::{ColorDiscrete, ColorLegend, ColorNetwork};
use map_gui::ID;
use map_model::{AmenityType, LaneType, PathConstraints};
use sim::AgentType;
use widgetry::{
Color, Drawable, EventCtx, GfxCtx, HorizontalAlignment, Line, Panel, Text, TextExt,
VerticalAlignment, Widget,
};
use widgetry::{Color, Drawable, EventCtx, GfxCtx, Line, Panel, Text, TextExt, Widget};
use crate::app::App;
use crate::layer::{header, Layer, LayerOutcome};
use crate::layer::{header, Layer, LayerOutcome, PANEL_PLACEMENT};
pub struct BikeActivity {
panel: Panel,
@ -26,12 +23,7 @@ impl Layer for BikeActivity {
fn name(&self) -> Option<&'static str> {
Some("cycling activity")
}
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
minimap: &Panel,
) -> Option<LayerOutcome> {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Option<LayerOutcome> {
let mut recalc_tooltip = false;
if app.primary.sim.time() != self.time {
*self = BikeActivity::new(ctx, app);
@ -58,7 +50,7 @@ impl Layer for BikeActivity {
self.tooltip = None;
}
Layer::simple_event(ctx, minimap, &mut self.panel)
Layer::simple_event(ctx, &mut self.panel)
}
fn draw(&self, g: &mut GfxCtx, app: &App) {
self.panel.draw(g);
@ -156,7 +148,7 @@ impl BikeActivity {
vec!["lowest count", "highest"],
),
]))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx);
let mut colorer = ColorNetwork::new(app);
@ -187,8 +179,8 @@ impl Layer for Static {
fn name(&self) -> Option<&'static str> {
Some(self.name)
}
fn event(&mut self, ctx: &mut EventCtx, _: &mut App, minimap: &Panel) -> Option<LayerOutcome> {
Layer::simple_event(ctx, minimap, &mut self.panel)
fn event(&mut self, ctx: &mut EventCtx, _: &mut App) -> Option<LayerOutcome> {
Layer::simple_event(ctx, &mut self.panel)
}
fn draw(&self, g: &mut GfxCtx, app: &App) {
self.panel.draw(g);
@ -213,7 +205,7 @@ impl Static {
) -> Static {
let (unzoomed, zoomed, legend) = colorer.build(ctx);
let panel = Panel::new(Widget::col(vec![header(ctx, &title), extra, legend]))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx);
Static {
@ -356,12 +348,7 @@ impl Layer for CongestionCaps {
fn name(&self) -> Option<&'static str> {
Some("congestion caps")
}
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
minimap: &Panel,
) -> Option<LayerOutcome> {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Option<LayerOutcome> {
let mut recalc_tooltip = false;
if app.primary.sim.time() != self.time {
*self = CongestionCaps::new(ctx, app);
@ -394,7 +381,7 @@ impl Layer for CongestionCaps {
self.tooltip = None;
}
Layer::simple_event(ctx, minimap, &mut self.panel)
Layer::simple_event(ctx, &mut self.panel)
}
fn draw(&self, g: &mut GfxCtx, app: &App) {
self.panel.draw(g);
@ -438,7 +425,7 @@ impl CongestionCaps {
format!("{} roads have caps", prettyprint_usize(num_roads)).text_widget(ctx),
ColorLegend::gradient(ctx, &app.cs.good_to_bad_red, vec!["available", "full"]),
]))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx);
let (unzoomed, zoomed) = colorer.build(ctx);

View File

@ -1,7 +1,8 @@
use map_gui::tools::{grey_out_map, HeatmapOptions};
use sim::AgentType;
use widgetry::{
DrawBaselayer, EventCtx, GfxCtx, Image, Key, Line, Outcome, Panel, State, TextExt, Widget,
DrawBaselayer, EventCtx, GfxCtx, HorizontalAlignment, Image, Key, Line, Outcome, Panel, State,
TextExt, VerticalAlignment, Widget,
};
use crate::app::{App, Transition};
@ -21,8 +22,7 @@ pub mod transit;
pub trait Layer {
fn name(&self) -> Option<&'static str>;
fn event(&mut self, ctx: &mut EventCtx, app: &mut App, minimap: &Panel)
-> Option<LayerOutcome>;
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Option<LayerOutcome>;
// Draw both controls and, if zoomed, the layer contents
fn draw(&self, g: &mut GfxCtx, app: &App);
// Just draw contents and do it always
@ -30,12 +30,7 @@ pub trait Layer {
}
impl dyn Layer {
fn simple_event(
ctx: &mut EventCtx,
minimap: &Panel,
panel: &mut Panel,
) -> Option<LayerOutcome> {
panel.align_above(ctx, minimap);
fn simple_event(ctx: &mut EventCtx, panel: &mut Panel) -> Option<LayerOutcome> {
match panel.event(ctx) {
Outcome::Clicked(x) => match x.as_ref() {
"close" => Some(LayerOutcome::Close),
@ -58,14 +53,14 @@ pub struct PickLayer {
}
impl PickLayer {
pub fn update(ctx: &mut EventCtx, app: &mut App, minimap: &Panel) -> Option<Transition> {
pub fn update(ctx: &mut EventCtx, app: &mut App) -> Option<Transition> {
if app.primary.layer.is_none() {
return None;
}
// TODO Since the Layer is embedded in App, we have to do this slight trick
let mut layer = app.primary.layer.take().unwrap();
match layer.event(ctx, app, minimap) {
match layer.event(ctx, app) {
Some(LayerOutcome::Close) => {
app.primary.layer = None;
return None;
@ -275,3 +270,8 @@ pub fn header(ctx: &mut EventCtx, name: &str) -> Widget {
ctx.style().btn_close_widget(ctx),
])
}
pub const PANEL_PLACEMENT: (HorizontalAlignment, VerticalAlignment) = (
HorizontalAlignment::Percent(0.02),
VerticalAlignment::Percent(0.2),
);

View File

@ -5,12 +5,12 @@ use geom::{Circle, Distance, Pt2D, Time};
use map_gui::tools::{make_heatmap, HeatmapOptions};
use sim::PersonState;
use widgetry::{
Choice, Color, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Line, Outcome,
Panel, Text, TextExt, Toggle, VerticalAlignment, Widget,
Choice, Color, Drawable, EventCtx, GeomBatch, GfxCtx, Line, Outcome, Panel, Text, TextExt,
Toggle, Widget,
};
use crate::app::App;
use crate::layer::{header, Layer, LayerOutcome};
use crate::layer::{header, Layer, LayerOutcome, PANEL_PLACEMENT};
// TODO Disable drawing unzoomed agents... or alternatively, implement this by asking Sim to
// return this kind of data instead!
@ -25,19 +25,13 @@ impl Layer for Pandemic {
fn name(&self) -> Option<&'static str> {
Some("pandemic model")
}
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
minimap: &Panel,
) -> Option<LayerOutcome> {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Option<LayerOutcome> {
if app.primary.sim.time() != self.time {
let mut new = Pandemic::new(ctx, app, self.opts.clone());
new.panel.restore(ctx, &self.panel);
*self = new;
}
self.panel.align_above(ctx, minimap);
match self.panel.event(ctx) {
Outcome::Clicked(x) => match x.as_ref() {
"close" => {
@ -49,7 +43,6 @@ impl Layer for Pandemic {
let new_opts = self.options();
if self.opts != new_opts {
*self = Pandemic::new(ctx, app, new_opts);
self.panel.align_above(ctx, minimap);
}
}
}
@ -234,6 +227,6 @@ fn make_controls(ctx: &mut EventCtx, app: &App, opts: &Options, legend: Option<W
}
Panel::new(Widget::col(col))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx)
}

View File

@ -8,13 +8,10 @@ use map_model::{
BuildingID, Map, OffstreetParking, ParkingLotID, PathConstraints, PathRequest, RoadID,
};
use sim::{ParkingSpot, Scenario, VehicleType};
use widgetry::{
Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Line, Outcome, Panel, Text, Toggle,
VerticalAlignment, Widget,
};
use widgetry::{Drawable, EventCtx, GeomBatch, GfxCtx, Line, Outcome, Panel, Text, Toggle, Widget};
use crate::app::App;
use crate::layer::{header, Layer, LayerOutcome};
use crate::layer::{header, Layer, LayerOutcome, PANEL_PLACEMENT};
pub struct Occupancy {
time: Time,
@ -32,12 +29,7 @@ impl Layer for Occupancy {
fn name(&self) -> Option<&'static str> {
Some("parking occupancy")
}
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
minimap: &Panel,
) -> Option<LayerOutcome> {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Option<LayerOutcome> {
if app.primary.sim.time() != self.time {
*self = Occupancy::new(
ctx,
@ -50,7 +42,6 @@ impl Layer for Occupancy {
);
}
self.panel.align_above(ctx, minimap);
match self.panel.event(ctx) {
Outcome::Clicked(x) => match x.as_ref() {
"close" => {
@ -68,7 +59,6 @@ impl Layer for Occupancy {
self.panel.is_checked("Private buildings"),
self.panel.is_checked("Cars looking for parking"),
);
self.panel.align_above(ctx, minimap);
}
_ => {}
}
@ -127,7 +117,7 @@ impl Occupancy {
])
.into_widget(ctx),
]))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx);
return Occupancy {
time: app.primary.sim.time(),
@ -245,7 +235,7 @@ impl Occupancy {
),
ColorLegend::gradient(ctx, &app.cs.good_to_bad_red, vec!["0%", "100%"]),
]))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx);
let mut colorer = ColorNetwork::new(app);
@ -322,17 +312,11 @@ impl Layer for Efficiency {
fn name(&self) -> Option<&'static str> {
Some("parking efficiency")
}
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
minimap: &Panel,
) -> Option<LayerOutcome> {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Option<LayerOutcome> {
if app.primary.sim.time() != self.time {
*self = Efficiency::new(ctx, app);
}
self.panel.align_above(ctx, minimap);
match self.panel.event(ctx) {
Outcome::Clicked(x) => match x.as_ref() {
"close" => {
@ -372,7 +356,7 @@ impl Efficiency {
vec!["0", "3", "6", "10+"],
),
]))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx);
let map = &app.primary.map;

View File

@ -5,12 +5,11 @@ use geom::{Circle, Distance, Pt2D, Time};
use map_gui::tools::{make_heatmap, HeatmapOptions};
use sim::PersonState;
use widgetry::{
Color, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Image, Line, Outcome, Panel,
Toggle, VerticalAlignment, Widget,
Color, Drawable, EventCtx, GeomBatch, GfxCtx, Image, Line, Outcome, Panel, Toggle, Widget,
};
use crate::app::App;
use crate::layer::{header, Layer, LayerOutcome};
use crate::layer::{header, Layer, LayerOutcome, PANEL_PLACEMENT};
// TODO Disable drawing unzoomed agents... or alternatively, implement this by asking Sim to
// return this kind of data instead!
@ -25,20 +24,13 @@ impl Layer for PopulationMap {
fn name(&self) -> Option<&'static str> {
Some("population map")
}
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
minimap: &Panel,
) -> Option<LayerOutcome> {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Option<LayerOutcome> {
if app.primary.sim.time() != self.time {
let mut new = PopulationMap::new(ctx, app, self.opts.clone());
new.panel.align_above(ctx, minimap);
new.panel.restore(ctx, &self.panel);
*self = new;
}
self.panel.align_above(ctx, minimap);
match self.panel.event(ctx) {
Outcome::Clicked(x) => match x.as_ref() {
"close" => {
@ -50,7 +42,6 @@ impl Layer for PopulationMap {
let new_opts = self.options();
if self.opts != new_opts {
*self = PopulationMap::new(ctx, app, new_opts);
self.panel.align_above(ctx, minimap);
}
}
}
@ -185,6 +176,6 @@ fn make_controls(ctx: &mut EventCtx, app: &App, opts: &Options, legend: Option<W
}
Panel::new(Widget::col(col))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx)
}

View File

@ -10,12 +10,12 @@ use map_gui::ID;
use map_model::{IntersectionID, Map, Traversable};
use sim::{AgentType, VehicleType};
use widgetry::{
Color, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Line, Outcome, Panel, Text,
TextExt, Toggle, VerticalAlignment, Widget,
Color, Drawable, EventCtx, GeomBatch, GfxCtx, Line, Outcome, Panel, Text, TextExt, Toggle,
Widget,
};
use crate::app::App;
use crate::layer::{header, Layer, LayerOutcome};
use crate::layer::{header, Layer, LayerOutcome, PANEL_PLACEMENT};
pub struct Backpressure {
time: Time,
@ -28,17 +28,12 @@ impl Layer for Backpressure {
fn name(&self) -> Option<&'static str> {
Some("backpressure")
}
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
minimap: &Panel,
) -> Option<LayerOutcome> {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Option<LayerOutcome> {
if app.primary.sim.time() != self.time {
*self = Backpressure::new(ctx, app);
}
Layer::simple_event(ctx, minimap, &mut self.panel)
Layer::simple_event(ctx, &mut self.panel)
}
fn draw(&self, g: &mut GfxCtx, app: &App) {
self.panel.draw(g);
@ -84,7 +79,7 @@ impl Backpressure {
vec!["lowest count", "highest"],
),
]))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx);
let mut colorer = ColorNetwork::new(app);
@ -114,12 +109,7 @@ impl Layer for Throughput {
fn name(&self) -> Option<&'static str> {
Some("throughput")
}
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
minimap: &Panel,
) -> Option<LayerOutcome> {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Option<LayerOutcome> {
let mut recalc_tooltip = false;
if app.primary.sim.time() != self.time {
*self = Throughput::new(ctx, app, self.agent_types.clone());
@ -160,7 +150,6 @@ impl Layer for Throughput {
self.tooltip = None;
}
self.panel.align_above(ctx, minimap);
match self.panel.event(ctx) {
Outcome::Clicked(x) => match x.as_ref() {
"close" => {
@ -243,7 +232,7 @@ impl Throughput {
.flex_wrap(ctx, Percent::int(20)),
ColorLegend::gradient(ctx, &app.cs.good_to_bad_red, vec!["0", "highest"]),
]))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx);
let mut colorer = ColorNetwork::new(app);
@ -274,12 +263,7 @@ impl Layer for CompareThroughput {
fn name(&self) -> Option<&'static str> {
Some("throughput")
}
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
minimap: &Panel,
) -> Option<LayerOutcome> {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Option<LayerOutcome> {
let mut recalc_tooltip = false;
if app.primary.sim.time() != self.time {
*self = CompareThroughput::new(ctx, app);
@ -331,7 +315,6 @@ impl Layer for CompareThroughput {
self.tooltip = None;
}
self.panel.align_above(ctx, minimap);
match self.panel.event(ctx) {
Outcome::Clicked(x) => match x.as_ref() {
"close" => {
@ -421,7 +404,7 @@ impl CompareThroughput {
Toggle::switch(ctx, "Compare before proposal", None, true),
scale.make_legend(ctx, vec!["less traffic", "same", "more"]),
]))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx);
let (unzoomed, zoomed) = colorer.build(ctx);
@ -446,17 +429,12 @@ impl Layer for TrafficJams {
fn name(&self) -> Option<&'static str> {
Some("traffic jams")
}
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
minimap: &Panel,
) -> Option<LayerOutcome> {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Option<LayerOutcome> {
if app.primary.sim.time() != self.time {
*self = TrafficJams::new(ctx, app);
}
Layer::simple_event(ctx, minimap, &mut self.panel)
Layer::simple_event(ctx, &mut self.panel)
}
fn draw(&self, g: &mut GfxCtx, app: &App) {
self.panel.draw(g);
@ -510,7 +488,7 @@ impl TrafficJams {
.into_widget(ctx),
format!("{} jams detected", cnt).text_widget(ctx),
]))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx);
TrafficJams {
@ -584,17 +562,11 @@ impl Layer for Delay {
fn name(&self) -> Option<&'static str> {
Some("delay")
}
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
minimap: &Panel,
) -> Option<LayerOutcome> {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Option<LayerOutcome> {
if app.primary.sim.time() != self.time {
*self = Delay::new(ctx, app);
}
self.panel.align_above(ctx, minimap);
match self.panel.event(ctx) {
Outcome::Clicked(x) => match x.as_ref() {
"close" => {
@ -653,7 +625,7 @@ impl Delay {
header(ctx, "Delay per agent (minutes)"),
ColorLegend::gradient(ctx, &app.cs.good_to_bad_red, vec!["0", "5", "10", "15+"]),
]))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx),
}
}

View File

@ -1,12 +1,9 @@
use map_gui::tools::ColorDiscrete;
use map_model::{PathConstraints, PathStep};
use widgetry::{
Drawable, EventCtx, GfxCtx, HorizontalAlignment, Outcome, Panel, Toggle, VerticalAlignment,
Widget,
};
use widgetry::{Drawable, EventCtx, GfxCtx, Outcome, Panel, Toggle, Widget};
use crate::app::App;
use crate::layer::{header, Layer, LayerOutcome};
use crate::layer::{header, Layer, LayerOutcome, PANEL_PLACEMENT};
pub struct TransitNetwork {
panel: Panel,
@ -18,13 +15,7 @@ impl Layer for TransitNetwork {
fn name(&self) -> Option<&'static str> {
Some("transit network")
}
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
minimap: &Panel,
) -> Option<LayerOutcome> {
self.panel.align_above(ctx, minimap);
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Option<LayerOutcome> {
match self.panel.event(ctx) {
Outcome::Clicked(x) => match x.as_ref() {
"close" => {
@ -40,7 +31,6 @@ impl Layer for TransitNetwork {
self.panel.is_checked("show buses"),
self.panel.is_checked("show trains"),
);
self.panel.align_above(ctx, minimap);
}
_ => {}
}
@ -121,7 +111,7 @@ impl TransitNetwork {
Toggle::switch(ctx, "show trains", None, show_trains),
legend,
]))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.aligned_pair(PANEL_PLACEMENT)
.build(ctx);
TransitNetwork {

View File

@ -136,7 +136,7 @@ impl State<App> for SandboxMode {
if let Some(t) = m.event(ctx, app) {
return t;
}
if let Some(t) = PickLayer::update(ctx, app, m.get_panel()) {
if let Some(t) = PickLayer::update(ctx, app) {
return t;
}
}

View File

@ -454,21 +454,7 @@ impl Panel {
pub fn align(&mut self, horiz: HorizontalAlignment, vert: VerticalAlignment) {
self.horiz = horiz;
self.vert = vert;
}
pub fn align_above(&mut self, ctx: &mut EventCtx, other: &Panel) {
// Small padding
self.vert = VerticalAlignment::Above(other.top_level.rect.y1 - 5.0);
self.recompute_layout(ctx, false);
// Since we just moved things around, let all widgets respond to the mouse being somewhere
ctx.no_op_event(true, |ctx| assert_eq!(self.event(ctx), Outcome::Nothing));
}
pub fn align_below(&mut self, ctx: &mut EventCtx, other: &Panel, pad: f64) {
self.vert = VerticalAlignment::Below(other.top_level.rect.y2 + pad);
self.recompute_layout(ctx, false);
// Since we just moved things around, let all widgets respond to the mouse being somewhere
ctx.no_op_event(true, |ctx| assert_eq!(self.event(ctx), Outcome::Nothing));
// TODO Recompute layout and fire no_op_event?
}
/// All margins/padding/etc from the previous widget are retained. The ID is set on the new
@ -485,7 +471,9 @@ impl Panel {
new.layout.style = old.layout.style;
*old = new;
self.recompute_layout(ctx, true);
// TODO Same no_op_event as align_above? Should we always do this in recompute_layout?
// TODO Since we just moved things around, let all widgets respond to the mouse being
// somewhere? Maybe always do this in recompute_layout?
//ctx.no_op_event(true, |ctx| assert_eq!(self.event(ctx), Outcome::Nothing));
}
/// Removes a widget from the panel. Does not recalculate layout!
@ -578,6 +566,12 @@ impl PanelBuilder {
self
}
pub fn aligned_pair(mut self, pair: (HorizontalAlignment, VerticalAlignment)) -> PanelBuilder {
self.horiz = pair.0;
self.vert = pair.1;
self
}
pub fn max_size(mut self, width: Percent, height: Percent) -> PanelBuilder {
if width == Percent::int(100) && height == Percent::int(100) {
panic!("By default, Panels are capped at 100% of the screen. This is redundant.");