yet more layout refactor

This commit is contained in:
Dustin Carlino 2020-07-01 15:31:52 -07:00
parent f9cfe136e0
commit 834f060462
33 changed files with 284 additions and 363 deletions

View File

@ -60,31 +60,21 @@ impl App {
}
let mut c = Composite::new(
Widget::col(vec![
Widget::row(vec![{
let mut txt = Text::from(
Line("Here's a bunch of text to force some scrolling.").small_heading(),
);
txt.add(
Line(
"Bug: scrolling by clicking and dragging doesn't work while the \
stopwatch is running.",
)
.fg(Color::RED),
);
txt.draw(ctx)
}]),
Widget::row(vec![
Widget::col2(vec![
Text::from_multiline(vec![
Line("Here's a bunch of text to force some scrolling.").small_heading(),
Line(
"Bug: scrolling by clicking and dragging doesn't work while the stopwatch \
is running.",
)
.fg(Color::RED),
])
.draw(ctx),
Widget::row2(vec![
// Examples of styling widgets
Widget::col(col1)
.outline(3.0, Color::BLACK)
.padding(5)
.margin_right(5),
Widget::col(col2)
.outline(3.0, Color::BLACK)
.padding(5)
.margin_right(5),
Widget::col(col3).outline(3.0, Color::BLACK).padding(5),
Widget::col2(col1).outline(3.0, Color::BLACK).padding(5),
Widget::col2(col2).outline(3.0, Color::BLACK).padding(5),
Widget::col2(col3).outline(3.0, Color::BLACK).padding(5),
]),
LinePlot::new(
ctx,
@ -117,6 +107,7 @@ impl App {
},
),
])
.padding(16)
.bg(Color::grey(0.4)),
)
// Don't let the panel exceed this percentage of the window. Scrollbars appear
@ -267,36 +258,30 @@ fn setup_scrollable_canvas(ctx: &mut EventCtx) -> Drawable {
fn make_controls(ctx: &mut EventCtx) -> Composite {
Composite::new(
Widget::col(vec![
{
let mut txt = Text::from(Line("ezgui demo").small_heading());
txt.add(Line(
"Click and drag to pan, use touchpad or scroll wheel to zoom",
));
txt.draw(ctx)
},
Widget::row(vec![
Widget::col2(vec![
Text::from_multiline(vec![
Line("ezgui demo").small_heading(),
Line("Click and drag to pan, use touchpad or scroll wheel to zoom"),
])
.draw(ctx),
Widget::row2(vec![
// This just cycles between two arbitrary buttons
Checkbox::new(
false,
Btn::text_bg1("Pause").build(ctx, "pause the stopwatch", hotkey(Key::Space)),
Btn::text_bg1("Resume").build(ctx, "resume the stopwatch", hotkey(Key::Space)),
)
.named("paused")
.margin(5),
Btn::text_fg("Reset timer")
.build(ctx, "reset the stopwatch", None)
.margin(5),
Btn::text_fg("New faces")
.build(ctx, "generate new faces", hotkey(Key::F))
.margin(5),
Checkbox::text(ctx, "Draw scrollable canvas", None, true).margin(5),
Checkbox::text(ctx, "Show timeseries", lctrl(Key::T), false).margin(5),
.named("paused"),
Btn::text_fg("Reset timer").build(ctx, "reset the stopwatch", None),
Btn::text_fg("New faces").build(ctx, "generate new faces", hotkey(Key::F)),
Checkbox::text(ctx, "Draw scrollable canvas", None, true),
Checkbox::text(ctx, "Show timeseries", lctrl(Key::T), false),
])
.evenly_spaced(),
"Stopwatch: ...".draw_text(ctx).named("stopwatch"),
])
.bg(Color::grey(0.4)),
.bg(Color::grey(0.4))
.padding(16),
)
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
.build(ctx)

View File

@ -78,12 +78,11 @@ impl Wizard {
if self.tb_comp.is_none() {
self.tb_comp = Some(
Composite::new(
Widget::col(vec![
Widget::row(vec![
Widget::col2(vec![
Widget::row2(vec![
Line(query).small_heading().draw(ctx),
Btn::text_fg("X")
.build(ctx, "quit", hotkey(Key::Escape))
.margin(5)
.align_right(),
]),
Text::new().draw(ctx).named("error"),
@ -93,7 +92,7 @@ impl Wizard {
])
.bg(ctx.style().panel_bg)
.outline(5.0, Color::WHITE)
.padding(5),
.padding(16),
)
.build(ctx),
);
@ -264,8 +263,8 @@ impl<'a, 'b> WrappedWizard<'a, 'b> {
);
self.wizard.menu_comp = Some(
Composite::new(
Widget::row(vec![
Widget::col(col).margin_right(15),
Widget::row2(vec![
Widget::col2(col),
Btn::plaintext("X").build(self.ctx, "quit", hotkey(Key::Escape)),
])
.bg(self.ctx.style().panel_bg)
@ -388,15 +387,13 @@ impl<'a, 'b> WrappedWizard<'a, 'b> {
assert!(self.wizard.ack.is_none());
self.wizard.ack = Some(
Composite::new(
Widget::col(vec![
Widget::col2(vec![
txt.draw(self.ctx),
Btn::text_bg2("OK")
.build(self.ctx, "OK", hotkey(Key::Enter))
.margin(5),
Btn::text_bg2("OK").build(self.ctx, "OK", hotkey(Key::Enter)),
])
.bg(self.ctx.style().panel_bg)
.outline(10.0, Color::WHITE)
.padding(10),
.padding(16),
)
.build(self.ctx),
);

View File

@ -85,7 +85,7 @@ impl CompareTimes {
top_left: ScreenPt::new(0.0, 0.0),
}));
let y_axis = Widget::col(
let y_axis = Widget::custom_col(
labels
.iter()
.rev()
@ -102,7 +102,7 @@ impl CompareTimes {
JustDraw::wrap(ctx, label).centered_vert().margin_right(5)
};
let x_axis = Widget::row(
let x_axis = Widget::custom_row(
labels
.iter()
.map(|x| Line(x.to_string()).small().draw(ctx))
@ -115,12 +115,13 @@ impl CompareTimes {
// It's a bit of work to make both the x and y axis line up with the plot. :)
let plot_width = plot.get_width_for_forcing();
Widget::row(vec![Widget::col(vec![
Widget::row(vec![y_label, y_axis, plot]),
Widget::col(vec![x_axis, x_label])
Widget::custom_col(vec![
Widget::custom_row(vec![y_label, y_axis, plot]),
Widget::custom_col(vec![x_axis, x_label])
.force_width(plot_width)
.align_right(),
])])
])
.container()
}
}

View File

@ -176,7 +176,7 @@ impl<T: Yvalue<T>> LinePlot<T> {
// The text is already scaled; don't use Widget::draw_batch and scale it again.
row.push(JustDraw::wrap(ctx, batch));
}
let x_axis = Widget::row(row).padding(10);
let x_axis = Widget::custom_row(row).padding(10).evenly_spaced();
let num_y_labels = 4;
let mut col = Vec::new();
@ -185,14 +185,15 @@ impl<T: Yvalue<T>> LinePlot<T> {
col.push(max_y.from_percent(percent_y).prettyprint().draw_text(ctx));
}
col.reverse();
let y_axis = Widget::col(col).padding(10);
let y_axis = Widget::custom_col(col).padding(10).evenly_spaced();
// Don't let the x-axis fill the parent container
Widget::row(vec![Widget::col(vec![
Widget::custom_col(vec![
legend.margin_below(10),
Widget::row(vec![y_axis.evenly_spaced(), Widget::new(Box::new(plot))]),
x_axis.evenly_spaced(),
])])
Widget::custom_row(vec![y_axis, Widget::new(Box::new(plot))]),
x_axis,
])
.container()
}
}
@ -321,14 +322,13 @@ pub fn make_legend<T: Yvalue<T>>(
}
seen.insert(s.label.clone());
if opts.filterable {
row.push(Widget::row(vec![
Checkbox::colored(ctx, &s.label, s.color, !opts.disabled.contains(&s.label))
.margin_right(8),
row.push(Widget::row2(vec![
Checkbox::colored(ctx, &s.label, s.color, !opts.disabled.contains(&s.label)),
Line(&s.label).draw(ctx),
]));
} else {
let radius = 15.0;
row.push(Widget::row(vec![
row.push(Widget::row2(vec![
Widget::draw_batch(
ctx,
GeomBatch::from(vec![(
@ -336,13 +336,12 @@ pub fn make_legend<T: Yvalue<T>>(
Circle::new(Pt2D::new(radius, radius), Distance::meters(radius))
.to_polygon(),
)]),
)
.margin(5),
),
s.label.clone().draw_text(ctx),
]));
}
}
Widget::row(row).flex_wrap(ctx, 24)
Widget::custom_row(row).flex_wrap(ctx, 24)
}
// TODO If this proves useful, lift to geom

View File

@ -156,7 +156,7 @@ impl ScatterPlot {
// The text is already scaled; don't use Widget::draw_batch and scale it again.
row.push(JustDraw::wrap(ctx, batch));
}
let x_axis = Widget::row(row).padding(10);
let x_axis = Widget::custom_row(row).padding(10).evenly_spaced();
let num_y_labels = 4;
let mut col = Vec::new();
@ -165,14 +165,15 @@ impl ScatterPlot {
col.push(max_y.from_percent(percent_y).prettyprint().draw_text(ctx));
}
col.reverse();
let y_axis = Widget::col(col).padding(10);
let y_axis = Widget::custom_col(col).padding(10).evenly_spaced();
// Don't let the x-axis fill the parent container
Widget::row(vec![Widget::col(vec![
Widget::custom_col(vec![
legend.margin_below(10),
Widget::row(vec![y_axis.evenly_spaced(), Widget::new(Box::new(plot))]),
x_axis.evenly_spaced(),
])])
Widget::custom_row(vec![y_axis, Widget::new(Box::new(plot))]),
x_axis,
])
.container()
}
}

View File

@ -131,16 +131,15 @@ impl Tab {
master_col.push({
let mut txt = Text::from(Line("A/B STREET").display_title());
txt.add(Line("CHALLENGES").big_heading_styled());
txt.draw(ctx).centered_horiz().margin_below(20)
txt.draw(ctx).centered_horiz()
});
master_col.push(
Btn::text_bg2("Introduction and tutorial")
.build_def(ctx, None)
.centered_horiz()
.bg(app.cs.panel_bg)
.padding(10)
.outline(10.0, Color::BLACK)
.margin_below(10),
.padding(16)
.outline(2.0, Color::BLACK),
);
// Slightly inconsistent: pushes twice and leaves this challenge picker open
cbs.push((
@ -156,13 +155,9 @@ impl Tab {
Tab::ChallengeStage(ref n, _) => &name == n,
};
if current {
flex_row.push(Btn::text_bg2(&name).inactive(ctx).margin(10));
flex_row.push(Btn::text_bg2(&name).inactive(ctx));
} else {
flex_row.push(
Btn::text_bg2(&name)
.build_def(ctx, hotkey(Key::NUM_KEYS[idx]))
.margin(10),
);
flex_row.push(Btn::text_bg2(&name).build_def(ctx, hotkey(Key::NUM_KEYS[idx])));
cbs.push((
name.clone(),
Box::new(move |ctx, app| {
@ -174,12 +169,11 @@ impl Tab {
}
}
master_col.push(
Widget::row(flex_row)
Widget::custom_row(flex_row)
.flex_wrap(ctx, 80)
.bg(app.cs.panel_bg)
.padding(10)
.margin(10)
.outline(10.0, Color::BLACK),
.padding(16)
.outline(2.0, Color::BLACK),
);
let mut main_row = Vec::new();
@ -194,9 +188,9 @@ impl Tab {
.enumerate()
{
if current == idx {
col.push(Btn::text_fg(&stage.title).inactive(ctx).margin(10));
col.push(Btn::text_fg(&stage.title).inactive(ctx));
} else {
col.push(Btn::text_fg(&stage.title).build_def(ctx, None).margin(10));
col.push(Btn::text_fg(&stage.title).build_def(ctx, None));
let name = name.to_string();
cbs.push((
stage.title,
@ -209,11 +203,10 @@ impl Tab {
}
}
main_row.push(
Widget::col(col)
Widget::col2(col)
.bg(app.cs.panel_bg)
.padding(10)
.margin(10)
.outline(10.0, Color::BLACK),
.padding(16)
.outline(2.0, Color::BLACK),
);
}
@ -227,9 +220,7 @@ impl Tab {
let mut inner_col = vec![
txt.draw(ctx),
Btn::text_fg("Start!")
.build_def(ctx, hotkey(Key::Enter))
.margin(10),
Btn::text_fg("Start!").build_def(ctx, hotkey(Key::Enter)),
];
if let Some(scores) = app.session.high_scores.get(&challenge.gameplay) {
@ -249,11 +240,10 @@ impl Tab {
}
main_row.push(
Widget::col(inner_col)
Widget::col2(inner_col)
.bg(app.cs.panel_bg)
.padding(10)
.margin(10)
.outline(10.0, Color::BLACK),
.padding(16)
.outline(2.0, Color::BLACK),
);
cbs.push((
"Start!".to_string(),
@ -271,10 +261,10 @@ impl Tab {
));
}
master_col.push(Widget::row(main_row));
master_col.push(Widget::row2(main_row));
let mut c = WrappedComposite::new(
Composite::new(Widget::col(master_col))
Composite::new(Widget::col2(master_col))
.exact_size_percent(90, 85)
.build(ctx),
)

View File

@ -142,16 +142,17 @@ impl ColorLegend {
);
// Extra wrapping to make the labels stretch against just the scale, not everything else
// TODO Long labels aren't nicely lined up with the boundaries between buckets
Widget::custom_row(vec![Widget::col(vec![
Widget::col2(vec![
Widget::draw_batch(ctx, batch),
Widget::row(
Widget::custom_row(
labels
.into_iter()
.map(|lbl| Line(lbl).small().draw(ctx))
.collect(),
)
.evenly_spaced(),
])])
])
.container()
}
}

View File

@ -312,9 +312,11 @@ impl Minimap {
fn make_minimap_panel(ctx: &mut EventCtx, app: &App, zoom_lvl: usize) -> Composite {
if ctx.canvas.cam_zoom < app.opts.min_zoom_for_detail {
return Composite::new(Widget::row(vec![
make_tool_panel(ctx, app).align_right().margin_right(16),
make_vert_viz_panel(ctx, app).bg(app.cs.panel_bg).padding(7),
return Composite::new(Widget::row2(vec![
make_tool_panel(ctx, app).align_right(),
make_vert_viz_panel(ctx, app)
.bg(app.cs.panel_bg)
.padding(16),
]))
.aligned(
HorizontalAlignment::Right,
@ -326,7 +328,7 @@ fn make_minimap_panel(ctx: &mut EventCtx, app: &App, zoom_lvl: usize) -> Composi
let zoom_col = {
let mut col = vec![Btn::svg_def("../data/system/assets/speed/speed_up.svg")
.build(ctx, "zoom in", None)
.margin(12)];
.margin_below(20)];
for i in (0..=3).rev() {
let color = if zoom_lvl < i {
Color::WHITE.alpha(0.2)
@ -341,50 +343,47 @@ fn make_minimap_panel(ctx: &mut EventCtx, app: &App, zoom_lvl: usize) -> Composi
rect,
)
.build(ctx, format!("zoom to level {}", i + 1), None)
.margin(12),
.margin_below(20),
);
}
col.push(
Btn::svg_def("../data/system/assets/speed/slow_down.svg")
.build(ctx, "zoom out", None)
.margin(12),
Btn::svg_def("../data/system/assets/speed/slow_down.svg").build(ctx, "zoom out", None),
);
// The zoom column should start below the "pan up" arrow. But if we put it on the row with
// <, minimap, and > then it messes up the horizontal alignment of the pan up arrow.
// Also, double column to avoid the background color stretching to the bottom of the row.
Widget::col(vec![Widget::col(col).bg(app.cs.inner_panel)]).margin_above(26)
Widget::custom_col(vec![Widget::custom_col(col)
.padding(10)
.bg(app.cs.inner_panel)])
.margin_above(26)
};
let square_len = 0.15 * ctx.canvas.window_width;
let minimap_controls = Widget::col(vec![
let minimap_controls = Widget::col2(vec![
Btn::svg_def("../data/system/assets/minimap/up.svg")
.build(ctx, "pan up", None)
.margin(5)
.centered_horiz(),
Widget::row(vec![
Widget::row2(vec![
Btn::svg_def("../data/system/assets/minimap/left.svg")
.build(ctx, "pan left", None)
.margin(5)
.centered_vert(),
Filler::new(ScreenDims::new(square_len, square_len)).named("minimap"),
Btn::svg_def("../data/system/assets/minimap/right.svg")
.build(ctx, "pan right", None)
.margin(5)
.centered_vert(),
]),
Btn::svg_def("../data/system/assets/minimap/down.svg")
.build(ctx, "pan down", None)
.margin(5)
.centered_horiz(),
]);
Composite::new(Widget::row(vec![
make_tool_panel(ctx, app).margin_right(16),
Widget::col(vec![
Widget::row(vec![minimap_controls, zoom_col]),
Composite::new(Widget::row2(vec![
make_tool_panel(ctx, app),
Widget::col2(vec![
Widget::row2(vec![minimap_controls, zoom_col]),
make_horiz_viz_panel(ctx, app),
])
.padding(7)
.padding(16)
.bg(app.cs.panel_bg),
]))
.aligned(
@ -395,8 +394,7 @@ fn make_minimap_panel(ctx: &mut EventCtx, app: &App, zoom_lvl: usize) -> Composi
}
fn make_tool_panel(ctx: &mut EventCtx, app: &App) -> Widget {
// TODO Apply something to everything in the column
Widget::col(vec![
Widget::col2(vec![
(if ctx.canvas.cam_zoom >= app.opts.min_zoom_for_detail {
Btn::svg_def("../data/system/assets/minimap/zoom_out_fully.svg").build(
ctx,
@ -410,16 +408,13 @@ fn make_tool_panel(ctx: &mut EventCtx, app: &App) -> Widget {
None,
)
})
.bg(app.cs.inner_panel)
.margin_below(16),
.bg(app.cs.inner_panel),
Btn::svg_def("../data/system/assets/tools/layers.svg")
.build(ctx, "change layers", hotkey(Key::L))
.bg(app.cs.inner_panel)
.margin_below(16),
.bg(app.cs.inner_panel),
Btn::svg_def("../data/system/assets/tools/search.svg")
.build(ctx, "search", hotkey(Key::K))
.bg(app.cs.inner_panel)
.margin_below(16),
.bg(app.cs.inner_panel),
])
}
@ -431,7 +426,7 @@ fn make_horiz_viz_panel(ctx: &mut EventCtx, app: &App) -> Widget {
}
let last = row.pop().unwrap();
row.push(last.margin_right(0));
Widget::row(row)
Widget::custom_row(row)
}
fn make_vert_viz_panel(ctx: &mut EventCtx, app: &App) -> Widget {
@ -441,10 +436,8 @@ fn make_vert_viz_panel(ctx: &mut EventCtx, app: &App) -> Widget {
let mut row = Vec::new();
row.push(Checkbox::colored(ctx, label, *color, *enabled).margin_right(8));
row.push(Line(label).draw(ctx));
col.push(Widget::row(row).margin_below(7));
col.push(Widget::custom_row(row));
}
let last = col.pop().unwrap();
col.push(last.margin_below(0));
Widget::col(col)
Widget::col2(col)
}

View File

@ -18,8 +18,8 @@ impl Navigator {
pub fn new(ctx: &mut EventCtx, app: &App) -> Box<dyn State> {
Box::new(Navigator {
composite: Composite::new(
Widget::col(vec![
Widget::row(vec![
Widget::col2(vec![
Widget::row2(vec![
Line("Enter a street name").small_heading().draw(ctx),
Btn::text_fg("X")
.build(ctx, "close", hotkey(Key::Escape))
@ -36,6 +36,7 @@ impl Navigator {
)
.named("street"),
])
.padding(16)
.bg(app.cs.panel_bg),
)
.build(ctx),
@ -104,8 +105,8 @@ impl CrossStreet {
Box::new(CrossStreet {
composite: Composite::new(
Widget::col(vec![
Widget::row(vec![
Widget::col2(vec![
Widget::row2(vec![
{
let mut txt = Text::from(Line("What cross street?").small_heading());
// TODO This isn't so clear...
@ -128,7 +129,8 @@ impl CrossStreet {
)
.named("street"),
])
.bg(app.cs.panel_bg),
.bg(app.cs.panel_bg)
.padding(16),
)
.build(ctx),
first,

View File

@ -10,15 +10,15 @@ pub fn tool_panel(ctx: &mut EventCtx, app: &App) -> WrappedComposite {
let row = vec![
// TODO Maybe this is confusing -- it doesn't jump to the title screen necessarily.
// Caller has to handle this one
Btn::svg_def("../data/system/assets/tools/home.svg")
.build(ctx, "back", hotkey(Key::Escape))
.margin(10),
Btn::svg_def("../data/system/assets/tools/settings.svg")
.build(ctx, "settings", None)
.margin(10),
Btn::svg_def("../data/system/assets/tools/home.svg").build(
ctx,
"back",
hotkey(Key::Escape),
),
Btn::svg_def("../data/system/assets/tools/settings.svg").build(ctx, "settings", None),
];
WrappedComposite::new(
Composite::new(Widget::row(row).bg(app.cs.panel_bg))
Composite::new(Widget::row2(row).bg(app.cs.panel_bg).padding(16))
.aligned(HorizontalAlignment::Left, VerticalAlignment::BottomAboveOSD)
.build(ctx),
)

View File

@ -54,8 +54,8 @@ impl Floodfiller {
let (unzoomed, zoomed, legend) = colorer.build(ctx);
Box::new(Floodfiller {
composite: Composite::new(
Widget::col(vec![
Widget::row(vec![
Widget::col2(vec![
Widget::row2(vec![
Line(title).small_heading().draw(ctx),
Btn::text_fg("X")
.build(ctx, "close", hotkey(Key::Escape))

View File

@ -35,23 +35,21 @@ impl DebugMode {
pub fn new(ctx: &mut EventCtx, app: &App) -> DebugMode {
DebugMode {
composite: Composite::new(
Widget::col(vec![
Widget::row(vec![
Widget::col2(vec![
Widget::row2(vec![
Line("Debug Mode").small_heading().draw(ctx),
Btn::text_fg("X")
.build(ctx, "close", hotkey(Key::Escape))
.align_right(),
]),
Text::new().draw(ctx).named("current info"),
Checkbox::text(ctx, "show buildings", hotkey(Key::Num1), true).margin_below(5),
Checkbox::text(ctx, "show intersections", hotkey(Key::Num2), true)
.margin_below(5),
Checkbox::text(ctx, "show lanes", hotkey(Key::Num3), true).margin_below(5),
Checkbox::text(ctx, "show areas", hotkey(Key::Num4), true).margin_below(5),
Checkbox::text(ctx, "show labels", hotkey(Key::Num5), false).margin_below(5),
Checkbox::text(ctx, "show route for all agents", hotkey(Key::R), false)
.margin_below(5),
Widget::col(
Checkbox::text(ctx, "show buildings", hotkey(Key::Num1), true),
Checkbox::text(ctx, "show intersections", hotkey(Key::Num2), true),
Checkbox::text(ctx, "show lanes", hotkey(Key::Num3), true),
Checkbox::text(ctx, "show areas", hotkey(Key::Num4), true),
Checkbox::text(ctx, "show labels", hotkey(Key::Num5), false),
Checkbox::text(ctx, "show route for all agents", hotkey(Key::R), false),
Widget::col2(
vec![
(lctrl(Key::H), "unhide everything"),
(None, "screenshot everything"),
@ -64,13 +62,11 @@ impl DebugMode {
(None, "find bad traffic signals"),
]
.into_iter()
.map(|(key, action)| {
Btn::text_fg(action).build_def(ctx, key).margin_below(5)
})
.map(|(key, action)| Btn::text_fg(action).build_def(ctx, key))
.collect(),
),
])
.padding(10)
.padding(16)
.bg(app.cs.panel_bg),
)
.aligned(HorizontalAlignment::Right, VerticalAlignment::Top)

View File

@ -137,17 +137,14 @@ impl State for PolygonDebugger {
fn make_panel(ctx: &mut EventCtx, app: &App) -> Composite {
Composite::new(
Widget::col(vec![
Widget::row(vec![
Line("Geometry debugger")
.small_heading()
.draw(ctx)
.margin(5),
Widget::col2(vec![
Widget::row2(vec![
Line("Geometry debugger").small_heading().draw(ctx),
Btn::text_fg("X")
.build(ctx, "close", hotkey(Key::Escape))
.align_right(),
]),
Widget::row(vec![
Widget::row2(vec![
// TODO inactive
Btn::text_fg("<").build(ctx, "previous", hotkey(Key::LeftArrow)),
"noun X/Y".draw_text(ctx).named("pointer"),
@ -159,7 +156,7 @@ fn make_panel(ctx: &mut EventCtx, app: &App) -> Composite {
.centered_horiz(),
])
.bg(app.cs.panel_bg)
.padding(5),
.padding(16),
)
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
.build(ctx)

View File

@ -22,7 +22,7 @@ impl ClusterTrafficSignalEditor {
app.primary.current_selection = None;
Box::new(ClusterTrafficSignalEditor {
composite: Composite::new(
Widget::row(vec![
Widget::row2(vec![
Btn::text_fg("Finish").build_def(ctx, hotkey(Key::Escape))
])
.bg(app.cs.panel_bg),

View File

@ -48,7 +48,7 @@ impl StopSignEditor {
.collect();
let composite = Composite::new(
Widget::col(vec![
Widget::col2(vec![
"Stop sign editor".draw_text(ctx),
if ControlStopSign::new(&app.primary.map, id)
!= app.primary.map.get_stop_sign(id).clone()
@ -62,7 +62,7 @@ impl StopSignEditor {
Btn::text_fg("Finish").build_def(ctx, hotkey(Key::Escape)),
])
.bg(app.cs.panel_bg)
.padding(10),
.padding(16),
)
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
.build(ctx);

View File

@ -234,5 +234,5 @@ pub fn checkbox_per_mode(
);
filters.push(m.ongoing_verb().draw_text(ctx).margin_right(10));
}
Widget::row(filters)
Widget::custom_row(filters)
}

View File

@ -119,7 +119,7 @@ pub fn people(ctx: &mut EventCtx, app: &App, details: &mut Details, id: Building
details
.hyperlinks
.insert(p.to_string(), Tab::PersonTrips(p, BTreeMap::new()));
let widget = Widget::col(vec![
let widget = Widget::col2(vec![
Btn::text_bg1(p.to_string()).build_def(ctx, None),
if let Some((t, mode)) = next_trip {
format!(
@ -161,7 +161,7 @@ fn header(
) -> Vec<Widget> {
let mut rows = vec![];
rows.push(Widget::row(vec![
rows.push(Widget::row2(vec![
Line(id.to_string()).small_heading().draw(ctx),
header_btns(ctx),
]));

View File

@ -15,7 +15,7 @@ pub fn stop(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusStopID)
let sim = &app.primary.sim;
rows.push(Widget::row(vec![
rows.push(Widget::row2(vec![
Line("Bus stop").small_heading().draw(ctx),
header_btns(ctx),
]));
@ -99,7 +99,7 @@ fn bus_header(
}
let mut rows = vec![];
rows.push(Widget::row(vec![
rows.push(Widget::row2(vec![
Line(format!(
"{} (route {})",
id,
@ -145,9 +145,9 @@ fn delays_over_time(ctx: &mut EventCtx, app: &App, id: BusRouteID) -> Widget {
.unwrap_or_else(Vec::new),
});
}
Widget::col(vec![
Widget::col2(vec![
Line("Delays between stops").small_heading().draw(ctx),
LinePlot::new(ctx, series, PlotOptions::fixed()).margin(10),
LinePlot::new(ctx, series, PlotOptions::fixed()),
])
}
@ -163,7 +163,7 @@ fn passenger_delay(ctx: &mut EventCtx, app: &App, details: &mut Details, id: Bus
.bus_passenger_delays(app.primary.sim.time(), id)
.collect::<BTreeMap<_, _>>();
for idx in 0..route.stops.len() {
col.push(Widget::row(vec![
col.push(Widget::row2(vec![
format!("Stop {}", idx + 1).draw_text(ctx),
Btn::svg(
"../data/system/assets/tools/pin.svg",
@ -214,10 +214,7 @@ fn passenger_delay(ctx: &mut EventCtx, app: &App, details: &mut Details, id: Bus
}
let timeline = Widget::draw_batch(ctx, batch);
master_col.push(Widget::row(vec![
timeline.margin(5),
Widget::col(col).margin(5),
]));
master_col.push(Widget::row2(vec![timeline, Widget::col2(col)]));
Widget::col(master_col)
Widget::col2(master_col)
}

View File

@ -6,7 +6,7 @@ use map_model::AreaID;
pub fn area(ctx: &EventCtx, app: &App, _: &mut Details, id: AreaID) -> Vec<Widget> {
let mut rows = vec![];
rows.push(Widget::row(vec![
rows.push(Widget::row2(vec![
Line(id.to_string()).small_heading().draw(ctx),
header_btns(ctx),
]));

View File

@ -58,7 +58,7 @@ pub fn traffic(
)));
rows.push(txt.draw(ctx));
rows.push(opts.to_controls(ctx, app).margin_below(15));
rows.push(opts.to_controls(ctx, app));
let time = if opts.show_end_of_day {
app.primary.sim.get_end_of_day()
@ -98,7 +98,7 @@ pub fn delay(
let i = app.primary.map.get_i(id);
assert!(i.is_traffic_signal());
rows.push(opts.to_controls(ctx, app).margin_below(10));
rows.push(opts.to_controls(ctx, app));
rows.push(delay_plot(ctx, app, id, opts));
@ -168,13 +168,10 @@ pub fn current_demand(
);
rows.push(
Widget::col(vec![
txt.draw(ctx).margin_below(10),
Widget::draw_batch(ctx, batch),
])
.padding(10)
.bg(app.cs.inner_panel)
.outline(2.0, Color::WHITE),
Widget::col2(vec![txt.draw(ctx), Widget::draw_batch(ctx, batch)])
.padding(10)
.bg(app.cs.inner_panel)
.outline(2.0, Color::WHITE),
);
rows
@ -212,11 +209,8 @@ fn delay_plot(ctx: &EventCtx, app: &App, i: IntersectionID, opts: &DataOptions)
pts,
})
.collect();
Widget::col(vec![
Line("Delay through intersection")
.small_heading()
.draw(ctx)
.margin_below(10),
Widget::col2(vec![
Line("Delay through intersection").small_heading().draw(ctx),
ScatterPlot::new(
ctx,
series,
@ -250,7 +244,7 @@ fn header(
IntersectionType::Border => format!("Border #{}", id.0),
IntersectionType::Construction => format!("{} (under construction)", id),
};
rows.push(Widget::row(vec![
rows.push(Widget::row2(vec![
Line(label).small_heading().draw(ctx),
header_btns(ctx),
]));

View File

@ -60,7 +60,7 @@ pub fn info(ctx: &EventCtx, app: &App, details: &mut Details, id: LaneID) -> Vec
),
});
}
rows.push("Parking spots available".draw_text(ctx).margin_above(10));
rows.push("Parking spots available".draw_text(ctx));
rows.push(LinePlot::new(
ctx,
series,
@ -130,10 +130,8 @@ pub fn debug(ctx: &EventCtx, app: &App, details: &mut Details, id: LaneID) -> Ve
rows.extend(make_table(ctx, kv.into_iter()));
rows.push(Widget::row(vec![
"Copy OriginalLane to clipboard: "
.draw_text(ctx)
.margin_right(15),
rows.push(Widget::row2(vec![
"Copy OriginalLane to clipboard: ".draw_text(ctx),
Btn::svg_def("../data/system/assets/tools/clipboard.svg").build(
ctx,
"copy OriginalLane",
@ -184,7 +182,7 @@ pub fn traffic(
)));
rows.push(txt.draw(ctx));
rows.push(opts.to_controls(ctx, app).margin_below(15));
rows.push(opts.to_controls(ctx, app));
let r = map.get_l(id).parent;
let time = if opts.show_end_of_day {
@ -216,7 +214,7 @@ fn header(ctx: &EventCtx, app: &App, details: &mut Details, id: LaneID, tab: Tab
let r = map.get_r(l.parent);
let label = if l.is_sidewalk() { "Sidewalk" } else { "Lane" };
rows.push(Widget::row(vec![
rows.push(Widget::row2(vec![
Line(format!("{} #{}", label, id.0))
.small_heading()
.draw(ctx),

View File

@ -253,7 +253,7 @@ impl InfoPanel {
if let Some(id) = maybe_id.clone() {
for (key, label) in ctx_actions.actions(app, id) {
cached_actions.push(key);
col.push(hotkey_btn(ctx, app, label, key).margin(5));
col.push(hotkey_btn(ctx, app, label, key));
}
}
}
@ -318,7 +318,7 @@ impl InfoPanel {
tab,
time: app.primary.sim.time(),
is_paused: ctx_actions.is_paused(),
composite: Composite::new(Widget::col(col).bg(Color::hex("#5B5B5B")).padding(16))
composite: Composite::new(Widget::col2(col).bg(Color::hex("#5B5B5B")).padding(16))
.aligned(
HorizontalAlignment::Percent(0.02),
VerticalAlignment::Percent(0.2),
@ -489,25 +489,13 @@ fn make_table<I: Into<String>>(
rows: impl Iterator<Item = (I, String)>,
) -> Vec<Widget> {
rows.map(|(k, v)| {
Widget::row(vec![
Widget::row2(vec![
Line(k).secondary().draw(ctx),
// TODO not quite...
v.draw_text(ctx).centered_vert().align_right(),
])
})
.collect()
// Attempt two
/*let mut keys = Text::new();
let mut values = Text::new();
for (k, v) in rows {
keys.add(Line(k));
values.add(Line(v));
}
vec![Widget::row(vec![
keys.draw(ctx),
values.draw(ctx).centered_vert().bg(Color::GREEN),
])]*/
}
fn throughput<F: Fn(&Analytics) -> Vec<(TripMode, Vec<(Time, usize)>)>>(
@ -537,11 +525,10 @@ fn throughput<F: Fn(&Analytics) -> Vec<(TripMode, Vec<(Time, usize)>)>>(
let mut plot_opts = PlotOptions::filterable();
plot_opts.disabled = opts.disabled_series();
Widget::col(vec![
Widget::col2(vec![
Line("Number of crossing agents per hour")
.small_heading()
.draw(ctx)
.margin_below(10),
.draw(ctx),
LinePlot::new(ctx, series, plot_opts),
])
.padding(10)
@ -558,22 +545,24 @@ fn make_tabs(
let mut row = Vec::new();
for (name, link) in tabs {
if current_tab == link {
row.push(Btn::text_bg2(name).inactive(ctx));
row.push(Btn::text_bg2(name).inactive(ctx).centered_vert());
} else {
hyperlinks.insert(name.to_string(), link);
row.push(Btn::text_bg2(name).build_def(ctx, None));
row.push(Btn::text_bg2(name).build_def(ctx, None).centered_vert());
}
}
// TODO Centered, but actually, we need to set the padding of each button to divide the
// available space evenly. Fancy fill rules... hmmm.
Widget::row(row).bg(Color::WHITE).margin_vert(16)
Widget::custom_row(row).bg(Color::WHITE).margin_vert(16)
}
fn header_btns(ctx: &EventCtx) -> Widget {
Widget::row(vec![
Btn::svg_def("../data/system/assets/tools/location.svg")
.build(ctx, "jump to object", hotkey(Key::J))
.margin(5),
Widget::row2(vec![
Btn::svg_def("../data/system/assets/tools/location.svg").build(
ctx,
"jump to object",
hotkey(Key::J),
),
Btn::plaintext("X").build(ctx, "close info", hotkey(Key::Escape)),
])
.align_right()
@ -615,7 +604,7 @@ impl DataOptions {
if app.has_prebaked().is_none() {
return Widget::nothing();
}
Widget::row(vec![
Widget::row2(vec![
Checkbox::custom_text(
ctx,
"Show before changes",

View File

@ -39,7 +39,7 @@ pub fn info(ctx: &mut EventCtx, app: &App, details: &mut Details, id: ParkingLot
),
});
}
rows.push("Parking spots available".draw_text(ctx).margin_above(10));
rows.push("Parking spots available".draw_text(ctx));
rows.push(LinePlot::new(
ctx,
series,
@ -56,7 +56,7 @@ pub fn info(ctx: &mut EventCtx, app: &App, details: &mut Details, id: ParkingLot
fn header(ctx: &EventCtx, details: &mut Details, id: ParkingLotID, tab: Tab) -> Vec<Widget> {
vec![
Widget::row(vec![
Widget::row2(vec![
Line(id.to_string()).small_heading().draw(ctx),
header_btns(ctx),
]),

View File

@ -121,9 +121,9 @@ pub fn trips(
// TODO Style wrong. Button should be the entire row.
rows.push(
Widget::row(vec![
Widget::custom_row(vec![
format!("Trip {} ", idx + 1).draw_text(ctx).margin_right(21),
Widget::row(vec![
Widget::row2(vec![
Widget::draw_svg_transform(
ctx,
match trip_mode {
@ -133,8 +133,7 @@ pub fn trips(
TripMode::Transit => "../data/system/assets/meters/bus.svg",
},
RewriteColor::ChangeAll(color),
)
.margin_right(10),
),
Line(trip_status).small().fg(color).draw(ctx),
])
.fully_rounded()
@ -224,11 +223,7 @@ pub fn bio(
let batch = GeomBatch::from_svg_contents(svg_data).autocrop();
let dims = batch.get_dims();
let batch = batch.scale((200.0 / dims.width).min(200.0 / dims.height));
rows.push(
Widget::draw_batch(ctx, batch)
.centered_horiz()
.margin_below(10),
);
rows.push(Widget::draw_batch(ctx, batch).centered_horiz());
let nickname = petname::Petnames::default().generate(&mut rng, 2, " ");
let age = rng.gen_range(5, 100);
@ -267,8 +262,7 @@ pub fn bio(
Line("Pandemic model state: ").secondary(),
Line(status),
])
.draw(ctx)
.margin_below(5),
.draw(ctx),
);
}
@ -372,7 +366,7 @@ pub fn crowd(
) -> Vec<Widget> {
let mut rows = vec![];
rows.push(Widget::row(vec![
rows.push(Widget::row2(vec![
Line("Pedestrian crowd").small_heading().draw(ctx),
header_btns(ctx),
]));
@ -384,16 +378,10 @@ pub fn crowd(
.agent_to_person(AgentID::Pedestrian(*id))
.unwrap();
// TODO What other info is useful to summarize?
rows.push(
Widget::row(vec![
format!("{})", idx + 1)
.draw_text(ctx)
.centered_vert()
.margin_right(10),
Btn::text_fg(person.to_string()).build_def(ctx, None),
])
.margin_below(10),
);
rows.push(Widget::row2(vec![
format!("{})", idx + 1).draw_text(ctx).centered_vert(),
Btn::text_fg(person.to_string()).build_def(ctx, None),
]));
details.hyperlinks.insert(
person.to_string(),
Tab::PersonTrips(
@ -420,23 +408,24 @@ pub fn parked_car(
) -> Vec<Widget> {
let mut rows = vec![];
rows.push(Widget::row(vec![
rows.push(Widget::row2(vec![
Line(format!("Parked car #{}", id.0))
.small_heading()
.draw(ctx),
Widget::row(vec![
Widget::row2(vec![
// Little indirect, but the handler of this action is actually the ContextualActions
// for SandboxMode.
if is_paused {
Btn::svg_def("../data/system/assets/tools/location.svg")
.build(ctx, "follow (run the simulation)", hotkey(Key::F))
.margin(5)
Btn::svg_def("../data/system/assets/tools/location.svg").build(
ctx,
"follow (run the simulation)",
hotkey(Key::F),
)
} else {
// TODO Blink
Btn::svg_def("../data/system/assets/tools/location.svg")
.normal_color(RewriteColor::ChangeAll(Color::hex("#7FFA4D")))
.build(ctx, "unfollow (pause the simulation)", hotkey(Key::F))
.margin(5)
},
Btn::plaintext("X").build(ctx, "close info", hotkey(Key::Escape)),
])
@ -529,7 +518,7 @@ fn header(
PersonState::OffMap => (None, ("off map", None)),
};
rows.push(Widget::row(vec![
rows.push(Widget::custom_row(vec![
Line(format!("{}", id)).small_heading().draw(ctx),
if let Some(icon) = maybe_icon {
Widget::draw_svg_transform(ctx, icon, RewriteColor::ChangeAll(Color::hex("#A3A3A3")))
@ -542,19 +531,20 @@ fn header(
.fg(Color::hex("#A3A3A3"))
.draw(ctx)
.margin_horiz(10),
Widget::row(vec![
Widget::row2(vec![
// Little indirect, but the handler of this action is actually the ContextualActions
// for SandboxMode.
if is_paused {
Btn::svg_def("../data/system/assets/tools/location.svg")
.build(ctx, "follow (run the simulation)", hotkey(Key::F))
.margin(5)
Btn::svg_def("../data/system/assets/tools/location.svg").build(
ctx,
"follow (run the simulation)",
hotkey(Key::F),
)
} else {
// TODO Blink
Btn::svg_def("../data/system/assets/tools/location.svg")
.normal_color(RewriteColor::ChangeAll(Color::hex("#7FFA4D")))
.build(ctx, "unfollow (pause the simulation)", hotkey(Key::F))
.margin(5)
},
Btn::plaintext("X").build(ctx, "close info", hotkey(Key::Escape)),
])

View File

@ -70,8 +70,8 @@ pub fn ongoing(
let mut col = Vec::new();
{
col.push(Widget::row(vec![
Widget::row(vec![Line("Trip time").secondary().draw(ctx)])
col.push(Widget::custom_row(vec![
Widget::custom_row(vec![Line("Trip time").secondary().draw(ctx)])
.force_width_pct(ctx, col_width),
Text::from_all(vec![
Line(props.total_time.to_string()),
@ -81,10 +81,10 @@ pub fn ongoing(
]));
}
{
col.push(Widget::row(vec![
Widget::row(vec![Line("Distance").secondary().draw(ctx)])
col.push(Widget::custom_row(vec![
Widget::custom_row(vec![Line("Distance").secondary().draw(ctx)])
.force_width_pct(ctx, col_width),
Widget::col(vec![
Widget::col2(vec![
Text::from_all(vec![
Line(props.dist_crossed.describe_rounded()),
Line(format!("/{}", props.total_dist.describe_rounded())).secondary(),
@ -99,10 +99,13 @@ pub fn ongoing(
]));
}
{
col.push(Widget::row(vec![
Widget::row(vec![Line("Waiting").secondary().draw(ctx)])
col.push(Widget::custom_row(vec![
Line("Waiting")
.secondary()
.draw(ctx)
.container()
.force_width_pct(ctx, col_width),
Widget::col(vec![
Widget::col2(vec![
format!("{} here", props.waiting_here).draw_text(ctx),
Text::from_all(vec![
if props.total_waiting != Duration::ZERO {
@ -130,7 +133,7 @@ pub fn ongoing(
Some(props.dist_crossed / props.total_dist),
));
Widget::col(col)
Widget::col2(col)
}
pub fn future(
@ -185,15 +188,14 @@ pub fn future(
"This will advance the simulation to {}",
start_time.ampm_tostring()
))))
.build(ctx, format!("wait for {}", trip), None)
.margin_above(10),
.build(ctx, format!("wait for {}", trip), None),
);
details
.time_warpers
.insert(format!("wait for {}", trip), (trip, start_time));
}
Widget::col(col)
Widget::col2(col)
}
pub fn finished(
@ -270,15 +272,15 @@ pub fn finished(
let col_width = 15;
let total_trip_time = phases.last().as_ref().and_then(|p| p.end_time).unwrap() - start_time;
col.push(Widget::row(vec![
Widget::row(vec![Line("Trip time").secondary().draw(ctx)])
col.push(Widget::custom_row(vec![
Widget::custom_row(vec![Line("Trip time").secondary().draw(ctx)])
.force_width_pct(ctx, col_width),
total_trip_time.to_string().draw_text(ctx),
]));
let (_, waiting) = app.primary.sim.finished_trip_time(trip).unwrap();
col.push(Widget::row(vec![
Widget::row(vec![Line("Total waiting time").secondary().draw(ctx)])
col.push(Widget::custom_row(vec![
Widget::custom_row(vec![Line("Total waiting time").secondary().draw(ctx)])
.force_width_pct(ctx, col_width),
waiting.to_string().draw_text(ctx),
]));
@ -294,7 +296,7 @@ pub fn finished(
None,
));
Widget::col(col)
Widget::col2(col)
}
pub fn aborted(ctx: &mut EventCtx, app: &App, trip: TripID) -> Widget {
@ -319,7 +321,7 @@ pub fn aborted(ctx: &mut EventCtx, app: &App, trip: TripID) -> Widget {
.into_iter(),
));
Widget::col(col)
Widget::col2(col)
}
fn make_timeline(
@ -574,10 +576,10 @@ fn make_timeline(
}
let mut col = vec![
Widget::row(vec![start_btn, Widget::row(timeline), goal_btn])
Widget::custom_row(vec![start_btn, Widget::custom_row(timeline), goal_btn])
.evenly_spaced()
.margin_above(25),
Widget::row(vec![
Widget::row2(vec![
start_time.ampm_tostring().draw_text(ctx),
if let Some(t) = end_time {
t.ampm_tostring().draw_text(ctx).align_right()
@ -585,7 +587,7 @@ fn make_timeline(
Widget::nothing()
},
]),
Widget::row(vec![
Widget::row2(vec![
{
details
.time_warpers
@ -623,8 +625,7 @@ fn make_timeline(
} else {
Widget::nothing()
},
])
.margin_above(5),
]),
];
if path_impossible {
col.push("Map edits have disconnected the path taken before".draw_text(ctx));
@ -633,7 +634,7 @@ fn make_timeline(
if false {
col.extend(elevation);
}
Widget::col(col)
Widget::col2(col)
}
fn make_elevation(ctx: &EventCtx, color: Color, walking: bool, path: &Path, map: &Map) -> Widget {

View File

@ -331,11 +331,11 @@ pub fn make_signal_diagram(
};
let mut col = if edit_mode {
vec![
txt_widget.margin_below(10),
txt_widget,
Btn::text_bg2("Edit entire signal").build_def(ctx, hotkey(Key::E)),
]
} else {
vec![Widget::row(vec![
vec![Widget::row2(vec![
txt_widget,
Btn::text_fg("X")
.build(ctx, "close", hotkey(Key::Escape))
@ -353,7 +353,6 @@ pub fn make_signal_diagram(
Polygon::rectangle(0.2 * ctx.canvas.window_width / ctx.get_scale_factor(), 2.0),
)]),
)
.margin(15)
.centered_horiz(),
);
@ -381,14 +380,16 @@ pub fn make_signal_diagram(
hovered.append(normal.clone());
hovered.push(Color::RED, bbox.to_outline(Distance::meters(5.0)));
Btn::custom(normal, hovered, bbox.clone())
.build(ctx, format!("phase {}", idx + 1), None)
.margin(5)
Btn::custom(normal, hovered, bbox.clone()).build(
ctx,
format!("phase {}", idx + 1),
None,
)
};
let phase_col = if edit_mode {
Widget::col(vec![
Widget::row(vec![
Widget::col2(vec![
Widget::row2(vec![
match phase.phase_type {
PhaseType::Fixed(d) => Line(format!("Phase {}: {}", idx + 1, d)),
PhaseType::Adaptive(d) => {
@ -396,8 +397,7 @@ pub fn make_signal_diagram(
}
}
.small_heading()
.draw(ctx)
.margin_right(10),
.draw(ctx),
Btn::svg_def("../data/system/assets/tools/edit.svg").build(
ctx,
format!("change duration of phase {}", idx + 1),
@ -414,17 +414,15 @@ pub fn make_signal_diagram(
} else {
Widget::nothing()
},
])
.margin_below(10),
Widget::row(vec![
]),
Widget::row2(vec![
phase_btn,
Widget::col(vec![
Widget::col2(vec![
if idx == 0 {
Btn::text_fg("").inactive(ctx)
} else {
Btn::text_fg("").build(ctx, format!("move up phase {}", idx + 1), None)
}
.margin_below(5),
},
if idx == signal.phases.len() - 1 {
Btn::text_fg("").inactive(ctx)
} else {
@ -440,7 +438,7 @@ pub fn make_signal_diagram(
]),
])
} else {
Widget::col(vec![
Widget::col2(vec![
match phase.phase_type {
PhaseType::Fixed(d) => format!("Phase {}: {}", idx + 1, d).draw_text(ctx),
PhaseType::Adaptive(d) => {
@ -469,14 +467,13 @@ pub fn make_signal_diagram(
Polygon::rectangle(0.2 * ctx.canvas.window_width / ctx.get_scale_factor(), 2.0),
)]),
)
.margin(15)
.centered_horiz(),
);
col.push(Btn::text_fg("Add new phase").build_def(ctx, None));
}
Composite::new(Widget::col(col).bg(app.cs.panel_bg).padding(10))
Composite::new(Widget::col2(col).bg(app.cs.panel_bg).padding(16))
.aligned(HorizontalAlignment::Left, VerticalAlignment::Top)
.exact_size_percent(30, 85)
.build(ctx)

View File

@ -34,12 +34,12 @@ impl ActiveTraffic {
Box::new(ActiveTraffic {
composite: Composite::new(
Widget::col(vec![
Widget::col2(vec![
DashTab::ActiveTraffic.picker(ctx, app),
LinePlot::new(ctx, active_agents, PlotOptions::fixed()),
])
.bg(app.cs.panel_bg)
.padding(10),
.padding(16),
)
.exact_size_percent(90, 90)
.build(ctx),
@ -86,11 +86,11 @@ impl BusRoutes {
Line("Bus routes").small_heading().draw(ctx),
];
for r in routes {
col.push(Btn::text_fg(r).build_def(ctx, None).margin(5));
col.push(Btn::text_fg(r).build_def(ctx, None));
}
Box::new(BusRoutes {
composite: Composite::new(Widget::col(col).bg(app.cs.panel_bg).padding(10))
composite: Composite::new(Widget::col2(col).bg(app.cs.panel_bg).padding(16))
.exact_size_percent(90, 90)
.build(ctx),
})

View File

@ -40,7 +40,7 @@ impl DashTab {
Widget::custom_row(vec![
// TODO Centered, but actually, we need to set the padding of each button to divide the
// available space evenly. Fancy fill rules... hmmm.
Widget::row(row).bg(Color::WHITE).margin_vert(16),
Widget::custom_row(row).bg(Color::WHITE).margin_vert(16),
Btn::plaintext("X")
.build(ctx, "close", hotkey(Key::Escape))
.align_right(),

View File

@ -273,7 +273,7 @@ fn make_meter(
]),
])
.bg(app.cs.panel_bg)
.padding(20),
.padding(16),
)
.aligned(HorizontalAlignment::Right, VerticalAlignment::Top)
.build(ctx)
@ -370,7 +370,7 @@ fn cutscene_task(mode: &GameplayMode) -> Box<dyn Fn(&mut EventCtx) -> Widget> {
])
.draw(ctx)
.margin_below(30),
Widget::row(vec![
Widget::row2(vec![
Widget::col2(vec![
Line("Time").fg(Color::BLACK).draw(ctx),
Widget::draw_svg_transform(

View File

@ -338,7 +338,7 @@ fn make_meter(
},
])
.bg(app.cs.panel_bg)
.padding(35),
.padding(16),
)
.aligned(HorizontalAlignment::Right, VerticalAlignment::Top)
.build(ctx)

View File

@ -284,21 +284,21 @@ impl AgentMeter {
let rows = vec![
"Active trips".draw_text(ctx),
Widget::row(vec![
Widget::row(vec![
Widget::custom_row(vec![
Widget::custom_row(vec![
Widget::draw_svg(ctx, "../data/system/assets/meters/pedestrian.svg")
.margin_right(5),
prettyprint_usize(by_mode[&TripMode::Walk]).draw_text(ctx),
]),
Widget::row(vec![
Widget::custom_row(vec![
Widget::draw_svg(ctx, "../data/system/assets/meters/bike.svg").margin_right(5),
prettyprint_usize(by_mode[&TripMode::Bike]).draw_text(ctx),
]),
Widget::row(vec![
Widget::custom_row(vec![
Widget::draw_svg(ctx, "../data/system/assets/meters/car.svg").margin_right(5),
prettyprint_usize(by_mode[&TripMode::Drive]).draw_text(ctx),
]),
Widget::row(vec![
Widget::custom_row(vec![
Widget::draw_svg(ctx, "../data/system/assets/meters/bus.svg").margin_right(5),
prettyprint_usize(by_mode[&TripMode::Transit]).draw_text(ctx),
]),
@ -312,9 +312,8 @@ impl AgentMeter {
Polygon::rectangle(0.2 * ctx.canvas.window_width / ctx.get_scale_factor(), 2.0),
)]),
)
.margin(15)
.centered_horiz(),
Widget::row(vec![
Widget::row2(vec![
{
let mut txt = Text::new();
let pct = if unfinished == 0 {
@ -335,7 +334,7 @@ impl AgentMeter {
]),
];
let composite = Composite::new(Widget::col(rows).bg(app.cs.panel_bg).padding(20))
let composite = Composite::new(Widget::col2(rows).bg(app.cs.panel_bg).padding(16))
.aligned(HorizontalAlignment::Right, VerticalAlignment::Top)
.build(ctx);

View File

@ -33,7 +33,6 @@ enum SpeedSetting {
}
impl SpeedControls {
// TODO Could use checkbox here, but not sure it'll make things that much simpler.
fn make_panel(ctx: &mut EventCtx, app: &App, paused: bool, setting: SpeedSetting) -> Composite {
let mut row = Vec::new();
row.push(
@ -51,7 +50,7 @@ impl SpeedControls {
);
row.push(
Widget::row(
Widget::custom_row(
vec![
(SpeedSetting::Realtime, "real-time speed"),
(SpeedSetting::Fast, "5x speed"),
@ -100,7 +99,7 @@ impl SpeedControls {
);
row.push(
Widget::row(vec![
Widget::custom_row(vec![
Btn::svg_def("../data/system/assets/speed/jump_to_time.svg")
.pad(9)
.build(ctx, "jump to specific time", hotkey(Key::B)),
@ -111,7 +110,7 @@ impl SpeedControls {
.bg(app.cs.section_bg),
);
Composite::new(Widget::row(row).bg(app.cs.panel_bg).padding(16))
Composite::new(Widget::custom_row(row).bg(app.cs.panel_bg).padding(16))
.aligned(
HorizontalAlignment::Center,
VerticalAlignment::BottomAboveOSD,
@ -350,14 +349,13 @@ impl JumpToTime {
target,
maybe_mode,
composite: Composite::new(
Widget::col(vec![
Widget::row(vec![
Widget::col2(vec![
Widget::row2(vec![
Line("Jump to what time?").small_heading().draw(ctx),
Btn::plaintext("X")
.build(ctx, "close", hotkey(Key::Escape))
.align_right(),
])
.margin_below(15),
]),
if app.has_prebaked().is_some() {
Widget::draw_batch(
ctx,
@ -380,8 +378,7 @@ impl JumpToTime {
0.25 * ctx.canvas.window_width,
target.to_percent(end_of_day).min(1.0),
)
.named("time slider")
.margin_below(15),
.named("time slider"),
Btn::text_bg2(format!("Jump to {}", target.ampm_tostring()))
.build(ctx, "jump to time", hotkey(Key::Enter))
.centered_horiz()
@ -393,8 +390,7 @@ impl JumpToTime {
Polygon::rectangle(0.25 * ctx.canvas.window_width, 2.0),
)]),
)
.margin_above(20)
.margin_below(20),
.margin_above(10),
Btn::text_bg2("Jump to the next delay over 5 minutes")
.build_def(ctx, None)
.centered_horiz(),
@ -506,7 +502,7 @@ impl TimeWarpScreen {
started: Instant::now(),
traffic_jams,
composite: Composite::new(
Widget::col(vec![
Widget::col2(vec![
Text::new().draw(ctx).named("text"),
Btn::text_bg2("stop now")
.build_def(ctx, hotkey(Key::Escape))
@ -644,12 +640,11 @@ impl TimePanel {
TimePanel {
time: app.primary.sim.time(),
composite: Composite::new(
Widget::col(vec![
Widget::col2(vec![
Text::from(
Line(app.primary.sim.time().ampm_tostring_spacers()).big_heading_styled(),
)
.draw(ctx)
.margin(10)
.centered_horiz(),
{
let mut batch = GeomBatch::new();
@ -684,17 +679,16 @@ impl TimePanel {
Widget::draw_batch(ctx, batch)
},
Widget::row(vec![
Widget::custom_row(vec![
Line("00:00").small().draw(ctx),
Widget::draw_svg(ctx, "../data/system/assets/speed/sunrise.svg"),
Line("12:00").small().draw(ctx),
Widget::draw_svg(ctx, "../data/system/assets/speed/sunset.svg"),
Line("24:00").small().draw(ctx),
])
.padding(10)
.evenly_spaced(),
])
.padding(10)
.padding(16)
.bg(app.cs.panel_bg),
)
.aligned(HorizontalAlignment::Left, VerticalAlignment::Top)

View File

@ -72,10 +72,10 @@ impl UI {
model,
state: State::viewing(),
composite: Composite::new(
Widget::col(vec![
Widget::col2(vec![
Line("Map Editor").small_heading().draw(ctx),
Text::new().draw(ctx).named("current info"),
Widget::col(
Widget::col2(
vec![
(hotkey(Key::Escape), "quit"),
(None, "save raw map"),
@ -89,7 +89,7 @@ impl UI {
.collect(),
),
])
.padding(10)
.padding(16)
.bg(Color::grey(0.4)),
)
.aligned(HorizontalAlignment::Right, VerticalAlignment::Top)