Simplify the combinatorial explosion of Panel sizing APIs

This commit is contained in:
Dustin Carlino 2022-03-08 08:56:55 +00:00
parent 04f00b4c8a
commit 477783e430
10 changed files with 78 additions and 105 deletions

View File

@ -5,8 +5,8 @@ use sim::AlertLocation;
use widgetry::tools::PopupMsg;
use widgetry::{
Choice, Color, ControlState, DrawWithTooltips, EdgeInsets, EventCtx, GeomBatch, GfxCtx,
HorizontalAlignment, Key, Line, Outcome, Panel, PersistentSplit, ScreenDims, Text, TextExt,
VerticalAlignment, Widget,
HorizontalAlignment, Key, Line, Outcome, Panel, PanelDims, PersistentSplit, ScreenDims, Text,
TextExt, VerticalAlignment, Widget,
};
use crate::app::{App, Transition};
@ -155,7 +155,7 @@ impl TimePanel {
]))
.aligned(HorizontalAlignment::Left, VerticalAlignment::Top);
if let Some(h) = self.override_height {
panel = panel.exact_height_pixels(h);
panel = panel.dims_height(PanelDims::ExactPixels(h));
}
self.panel = panel.build(ctx);
}

View File

@ -7,7 +7,7 @@ use map_gui::tools::grey_out_map;
use map_gui::ID;
use widgetry::tools::PopupMsg;
use widgetry::{
Choice, DrawBaselayer, EventCtx, GeomBatch, GfxCtx, Key, Line, Outcome, Panel, ScreenDims,
Choice, DrawBaselayer, EventCtx, GeomBatch, GfxCtx, Key, Line, Outcome, Panel, PanelDims,
Slider, State, TabController, Text, Toggle, UpdateType, Widget,
};
@ -103,7 +103,8 @@ impl JumpToTime {
ctx.style().btn_close_widget(ctx),
tabs.build_widget(ctx),
]))
.exact_size(ScreenDims::new(640.0, 360.0))
.dims_width(PanelDims::ExactPixels(640.0))
.dims_height(PanelDims::ExactPixels(360.0))
.build(ctx),
tabs,
})

View File

@ -9,7 +9,7 @@ mod trip;
use geom::CornerRadii;
use map_gui::tools::CityPicker;
use widgetry::{
EventCtx, HorizontalAlignment, Key, Line, Panel, ScreenDims, State, VerticalAlignment, Widget,
EventCtx, HorizontalAlignment, Key, Line, Panel, PanelDims, State, VerticalAlignment, Widget,
DEFAULT_CORNER_RADIUS,
};
@ -119,10 +119,8 @@ impl Tab {
let mut panel = Panel::new_builder(Widget::col(vec![header, tabs]))
// The different tabs have different widths. To avoid the UI bouncing around as the user
// navigates, this is hardcoded to be a bit wider than the widest tab.
.exact_size(ScreenDims {
width: 620.0,
height: ctx.canvas.window_height,
})
.dims_width(PanelDims::ExactPixels(620.0))
.dims_height(PanelDims::ExactPercent(1.0))
.aligned(HorizontalAlignment::Left, VerticalAlignment::Top);
if self == Tab::Trip {
// Hovering on a card

View File

@ -1,5 +1,5 @@
use widgetry::{
lctrl, EventCtx, HorizontalAlignment, Key, Line, Outcome, Panel, PanelBuilder,
lctrl, EventCtx, HorizontalAlignment, Key, Line, Outcome, Panel, PanelBuilder, PanelDims,
VerticalAlignment, Widget,
};
@ -21,7 +21,7 @@ pub fn app_top_panel(ctx: &mut EventCtx, app: &App) -> Panel {
.align_right(),
]))
.aligned(HorizontalAlignment::Left, VerticalAlignment::Top)
.exact_width_percent(1.0)
.dims_width(PanelDims::ExactPercent(1.0))
.build(ctx)
}
@ -58,5 +58,5 @@ pub fn left_panel_builder(contents: Widget) -> PanelBuilder {
HorizontalAlignment::Percent(0.0),
VerticalAlignment::Percent(0.1),
)
.exact_height_percent(0.9)
.dims_height(PanelDims::ExactPercent(0.9))
}

View File

@ -6,8 +6,8 @@ use map_model::City;
use widgetry::tools::FileLoader;
use widgetry::{
lctrl, Autocomplete, ClickOutcome, ControlState, DrawBaselayer, DrawWithTooltips, EventCtx,
GeomBatch, GfxCtx, Image, Key, Line, Outcome, Panel, RewriteColor, State, Text, TextExt,
Transition, Widget,
GeomBatch, GfxCtx, Image, Key, Line, Outcome, Panel, PanelDims, RewriteColor, State, Text,
TextExt, Transition, Widget,
};
use crate::load::MapLoader;
@ -278,7 +278,8 @@ impl<A: AppLike + 'static> AllCityPicker<A> {
.padding(8),
Widget::custom_row(buttons).flex_wrap(ctx, Percent::int(70)),
]))
.exact_size_percent(80, 80)
.dims_width(PanelDims::ExactPercent(0.8))
.dims_height(PanelDims::ExactPercent(0.8))
.build(ctx),
})
}
@ -404,7 +405,8 @@ impl<A: AppLike + 'static> CitiesInCountryPicker<A> {
Box::new(CitiesInCountryPicker {
on_load: Some(on_load),
panel: Panel::new_builder(Widget::col(col))
.exact_size_percent(80, 80)
.dims_width(PanelDims::ExactPercent(0.8))
.dims_height(PanelDims::ExactPercent(0.8))
.build(ctx),
})
}

View File

@ -7,7 +7,8 @@ use geom::{Percent, Polygon};
use crate::{
svg, Canvas, CanvasSettings, Color, Drawable, Event, GeomBatch, GfxCtx, HorizontalAlignment,
Key, Line, Panel, Prerender, ScreenDims, Style, Text, UserInput, VerticalAlignment, Widget,
Key, Line, Panel, PanelDims, Prerender, ScreenDims, Style, Text, UserInput, VerticalAlignment,
Widget,
};
#[derive(Clone, PartialEq, Debug)]
@ -203,7 +204,8 @@ impl<'a> EventCtx<'a> {
.padding(16)
.bg(Color::grey(0.3)),
]))
.exact_size_percent(80, 80)
.dims_width(PanelDims::ExactPercent(0.8))
.dims_height(PanelDims::ExactPercent(0.8))
.aligned(HorizontalAlignment::Center, VerticalAlignment::Center)
.build_custom(self)
}

View File

@ -75,8 +75,8 @@ pub use crate::widgets::text_box::TextBox;
pub use crate::widgets::toggle::Toggle;
pub use crate::widgets::DEFAULT_CORNER_RADIUS;
pub use crate::widgets::{
ClickOutcome, CornerRounding, EdgeInsets, Outcome, Panel, PanelBuilder, Widget, WidgetImpl,
WidgetOutput,
ClickOutcome, CornerRounding, EdgeInsets, Outcome, Panel, PanelBuilder, PanelDims, Widget,
WidgetImpl, WidgetOutput,
};
mod app_state;

View File

@ -11,7 +11,7 @@ use abstutil::CloneableAny;
use geom::{CornerRadii, Distance, Percent, Polygon};
use crate::widgets::containers::{Container, Nothing};
pub use crate::widgets::panel::{Panel, PanelBuilder};
pub use crate::widgets::panel::{Panel, PanelBuilder, PanelDims};
use crate::{
Button, Choice, Color, DeferDraw, Drawable, Dropdown, EventCtx, GeomBatch, GfxCtx, JustDraw,
OutlineStyle, ScreenDims, ScreenPt, ScreenRectangle, Toggle,

View File

@ -7,7 +7,7 @@ use stretch::node::{Node, Stretch};
use stretch::number::Number;
use stretch::style::{Dimension, Style};
use geom::{Percent, Polygon};
use geom::Polygon;
use crate::widgets::slider;
use crate::widgets::spinner::SpinnerValue;
@ -24,7 +24,8 @@ pub struct Panel {
cached_flexbox: Option<(Stretch, Vec<Node>, ScreenDims)>,
horiz: HorizontalAlignment,
vert: VerticalAlignment,
dims: Dims,
dims_x: PanelDims,
dims_y: PanelDims,
scrollable_x: bool,
scrollable_y: bool,
@ -39,7 +40,8 @@ impl Panel {
top_level,
horiz: HorizontalAlignment::Center,
vert: VerticalAlignment::Center,
dims: Dims::MaxPercent(Percent::int(100), Percent::int(100)),
dims_x: PanelDims::MaxPercent(1.0),
dims_y: PanelDims::MaxPercent(1.0),
ignore_initial_events: false,
}
}
@ -50,30 +52,17 @@ impl Panel {
}
fn update_container_dims_for_canvas_dims(&mut self, canvas_dims: ScreenDims) {
let new_container_dims = match self.dims {
Dims::MaxPercent(w, h) => ScreenDims::new(
self.contents_dims.width.min(w.inner() * canvas_dims.width),
self.contents_dims
.height
.min(h.inner() * canvas_dims.height),
),
Dims::ExactPercent(w, h) => {
ScreenDims::new(w * canvas_dims.width, h * canvas_dims.height)
}
Dims::ExactSize(dims) => dims,
Dims::ExactHeightPixels(h) => {
ScreenDims::new(self.contents_dims.width.min(canvas_dims.width), h)
}
Dims::ExactHeightPercent(pct) => ScreenDims::new(
self.contents_dims.width.min(canvas_dims.width),
pct * canvas_dims.height,
),
Dims::ExactWidthPercent(pct) => ScreenDims::new(
pct * canvas_dims.width,
self.contents_dims.height.min(canvas_dims.height),
),
let width = match self.dims_x {
PanelDims::MaxPercent(pct) => self.contents_dims.width.min(pct * canvas_dims.width),
PanelDims::ExactPercent(pct) => pct * canvas_dims.width,
PanelDims::ExactPixels(x) => x,
};
self.container_dims = new_container_dims;
let height = match self.dims_y {
PanelDims::MaxPercent(pct) => self.contents_dims.height.min(pct * canvas_dims.height),
PanelDims::ExactPercent(pct) => pct * canvas_dims.height,
PanelDims::ExactPixels(x) => x,
};
self.container_dims = ScreenDims::new(width, height);
}
fn recompute_scrollbar_layout(&mut self, ctx: &EventCtx) {
@ -589,17 +578,16 @@ pub struct PanelBuilder {
top_level: Widget,
horiz: HorizontalAlignment,
vert: VerticalAlignment,
dims: Dims,
dims_x: PanelDims,
dims_y: PanelDims,
ignore_initial_events: bool,
}
enum Dims {
MaxPercent(Percent, Percent),
ExactPercent(f64, f64),
ExactHeightPixels(f64),
ExactHeightPercent(f64),
ExactWidthPercent(f64),
ExactSize(ScreenDims),
#[derive(Clone, Copy)]
pub enum PanelDims {
MaxPercent(f64),
ExactPercent(f64),
ExactPixels(f64),
}
impl PanelBuilder {
@ -615,7 +603,8 @@ impl PanelBuilder {
horiz: self.horiz,
vert: self.vert,
dims: self.dims,
dims_x: self.dims_x,
dims_y: self.dims_y,
scrollable_x: false,
scrollable_y: false,
@ -624,30 +613,27 @@ impl PanelBuilder {
clip_rect: None,
cached_flexbox: None,
};
match panel.dims {
Dims::ExactPercent(w, h) => {
match self.dims_x {
PanelDims::MaxPercent(_) => {}
PanelDims::ExactPercent(pct) => {
// Don't set size, because then scrolling breaks -- the actual size has to be based
// on the contents.
panel.top_level.layout.style.min_size = Size {
width: Dimension::Points((w * ctx.canvas.window_width) as f32),
height: Dimension::Points((h * ctx.canvas.window_height) as f32),
};
}
Dims::ExactHeightPixels(h) => {
panel.top_level.layout.style.min_size.height = Dimension::Points(h as f32);
}
Dims::ExactHeightPercent(pct) => {
panel.top_level.layout.style.min_size.height =
Dimension::Points((pct * ctx.canvas.window_height) as f32);
}
Dims::ExactWidthPercent(pct) => {
panel.top_level.layout.style.min_size.width =
Dimension::Points((pct * ctx.canvas.window_width) as f32);
}
Dims::ExactSize(dims) => {
panel.top_level.layout.style.min_size = dims.into();
PanelDims::ExactPixels(x) => {
panel.top_level.layout.style.min_size.width = Dimension::Points(x as f32);
}
}
match self.dims_y {
PanelDims::MaxPercent(_) => {}
PanelDims::ExactPercent(pct) => {
panel.top_level.layout.style.min_size.height =
Dimension::Points((pct * ctx.canvas.window_height) as f32);
}
PanelDims::ExactPixels(x) => {
panel.top_level.layout.style.min_size.height = Dimension::Points(x as f32);
}
Dims::MaxPercent(_, _) => {}
}
// There is a dependency cycle in our layout logic. As a consequence:
@ -692,37 +678,20 @@ impl PanelBuilder {
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.");
}
self.dims = Dims::MaxPercent(width, height);
pub fn dims_width(mut self, dims: PanelDims) -> PanelBuilder {
self.dims_x = dims;
self
}
pub fn exact_size_percent(mut self, pct_width: usize, pct_height: usize) -> PanelBuilder {
self.dims = Dims::ExactPercent((pct_width as f64) / 100.0, (pct_height as f64) / 100.0);
pub fn dims_height(mut self, dims: PanelDims) -> PanelBuilder {
self.dims_y = dims;
self
}
pub fn exact_height_pixels(mut self, height: f64) -> PanelBuilder {
self.dims = Dims::ExactHeightPixels(height);
self
}
pub fn exact_height_percent(mut self, pct: f64) -> PanelBuilder {
self.dims = Dims::ExactHeightPercent(pct);
self
}
pub fn exact_width_percent(mut self, pct: f64) -> PanelBuilder {
self.dims = Dims::ExactWidthPercent(pct);
self
}
pub fn exact_size(mut self, size: ScreenDims) -> PanelBuilder {
self.dims = Dims::ExactSize(size);
self
// TODO Change all callers
pub fn exact_size_percent(self, x: usize, y: usize) -> PanelBuilder {
self.dims_width(PanelDims::ExactPercent((x as f64) / 100.0))
.dims_height(PanelDims::ExactPercent((y as f64) / 100.0))
}
/// When a panel is built, a fake, "no-op" mouseover event is immediately fired, to let all

View File

@ -1,12 +1,12 @@
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;
use geom::{Angle, Duration, Percent, Polygon, Pt2D, Time, UnitFmt};
use geom::{Angle, Duration, Polygon, Pt2D, Time, UnitFmt};
use widgetry::{
lctrl, Choice, Color, ContentMode, DragDrop, Drawable, EventCtx, Fill, GeomBatch, GfxCtx,
HorizontalAlignment, Image, Key, Line, LinePlot, Outcome, Panel, PersistentSplit, PlotOptions,
ScreenDims, Series, Settings, SharedAppState, StackAxis, State, TabController, Text, TextExt,
Texture, Toggle, Transition, UpdateType, VerticalAlignment, Widget,
HorizontalAlignment, Image, Key, Line, LinePlot, Outcome, Panel, PanelDims, PersistentSplit,
PlotOptions, ScreenDims, Series, Settings, SharedAppState, StackAxis, State, TabController,
Text, TextExt, Texture, Toggle, Transition, UpdateType, VerticalAlignment, Widget,
};
pub fn main() {
@ -121,7 +121,8 @@ impl Demo {
]))
// Don't let the panel exceed this percentage of the window. Scrollbars appear
// automatically if needed.
.max_size(Percent::int(30), Percent::int(40))
.dims_width(PanelDims::MaxPercent(0.3))
.dims_height(PanelDims::MaxPercent(0.4))
// We take up 30% width, and we want to leave 10% window width as buffer.
.aligned(HorizontalAlignment::Percent(0.6), VerticalAlignment::Center)
.build(ctx);