moving ezgui stuff around a little, cleaning up some of the APIs for

instantiating widgets
This commit is contained in:
Dustin Carlino 2020-03-22 23:50:14 -07:00
parent 96d7987c7e
commit b6eb46ec04
20 changed files with 159 additions and 166 deletions

View File

@ -1,3 +1,21 @@
//! # Widgets
//!
//! If none of these do what you need, implementing a new [`WidgetImpl`] isn't tough.
//!
//! TODO inline pictures of some of these
//!
//! * [`Autocomplete`] - select predefined value by combining text entry with menus
//! * [`Button`] - clickable buttons with keybindings and tooltips
//! * [`Checkbox`] - toggle between two buttons
//! * [`Dropdown`] - a button that expands into a menu
//! * [`Filler`] - just carve out space in the layout for something else
//! * [`Histogram`] - visualize a distribution
//! * [`JustDraw`] (argh private) - just draw text, `GeomBatch`es, SVGs
//! * [`Menu`] - select something from a menu, with keybindings
//! * [`Plot`] - visualize 2 variables with a line plot
//! * [`Slider`] - horizontal and vertical sliders
//! * [`TexBox`] - single line text entry
mod assets;
#[cfg(feature = "glium-backend")]
mod backend_glium;
@ -33,6 +51,7 @@ pub use crate::runner::{run, EventLoopMode, Settings, GUI};
pub use crate::screen_geom::{ScreenDims, ScreenPt, ScreenRectangle};
pub use crate::text::{Line, Text, TextExt, TextSpan, HOTKEY_COLOR};
pub use crate::tools::warper::Warper;
pub use crate::tools::wizard::{Choice, Wizard, WrappedWizard};
pub use crate::widgets::autocomplete::Autocomplete;
pub use crate::widgets::button::Btn;
pub(crate) use crate::widgets::button::Button;
@ -40,12 +59,11 @@ pub use crate::widgets::checkbox::Checkbox;
pub(crate) use crate::widgets::dropdown::Dropdown;
pub use crate::widgets::filler::Filler;
pub use crate::widgets::histogram::Histogram;
pub use crate::widgets::no_op::JustDraw;
pub(crate) use crate::widgets::just_draw::JustDraw;
pub(crate) use crate::widgets::menu::Menu;
pub use crate::widgets::plot::{Plot, PlotOptions, Series};
pub(crate) use crate::widgets::popup_menu::PopupMenu;
pub use crate::widgets::slider::Slider;
pub(crate) use crate::widgets::text_box::TextBox;
pub use crate::widgets::wizard::{Choice, Wizard, WrappedWizard};
pub use crate::widgets::WidgetImpl;
pub enum InputResult<T: Clone> {

View File

@ -1,9 +1,8 @@
use crate::widgets::containers::{Container, Nothing};
use crate::widgets::plot::Yvalue;
use crate::{
Btn, Button, Checkbox, Choice, Color, Drawable, Dropdown, EventCtx, Filler, GeomBatch, GfxCtx,
Histogram, HorizontalAlignment, JustDraw, MultiKey, Plot, PopupMenu, RewriteColor, ScreenDims,
ScreenPt, ScreenRectangle, Slider, Text, TextBox, VerticalAlignment, WidgetImpl,
HorizontalAlignment, JustDraw, Menu, MultiKey, RewriteColor, ScreenDims, ScreenPt,
ScreenRectangle, Slider, TextBox, VerticalAlignment, WidgetImpl,
};
use geom::{Distance, Polygon};
use std::collections::HashSet;
@ -218,44 +217,19 @@ impl Widget {
}
}
// TODO dupe apis!
// TODO These are literally just convenient APIs to avoid importing JustDraw. Do we want this
// or not?
pub fn draw_batch(ctx: &EventCtx, batch: GeomBatch) -> Widget {
JustDraw::wrap(ctx, batch)
}
pub(crate) fn just_draw(j: JustDraw) -> Widget {
Widget::new(Box::new(j))
}
pub(crate) fn draw_text(ctx: &EventCtx, txt: Text) -> Widget {
JustDraw::text(ctx, txt)
}
pub fn draw_svg(ctx: &EventCtx, filename: &str) -> Widget {
JustDraw::svg(ctx, filename)
}
// TODO Argh uncomposable APIs
pub fn draw_svg_transform(ctx: &EventCtx, filename: &str, rewrite: RewriteColor) -> Widget {
JustDraw::svg_transform(ctx, filename, rewrite)
}
pub(crate) fn btn(btn: Button) -> Widget {
let action = btn.action.clone();
Widget::new(Box::new(btn)).named(action)
}
pub fn slider(slider: Slider) -> Widget {
Widget::new(Box::new(slider))
}
pub fn menu<T: 'static + Clone>(menu: PopupMenu<T>) -> Widget {
Widget::new(Box::new(menu))
}
pub fn filler(filler: Filler) -> Widget {
Widget::new(Box::new(filler))
}
// TODO Convenient constructors here, but shouldn't do it like this
pub fn checkbox(
ctx: &EventCtx,
label: &str,
@ -279,11 +253,13 @@ impl Widget {
)))
}
// TODO Likewise
pub fn text_entry(ctx: &EventCtx, prefilled: String, exclusive_focus: bool) -> Widget {
// TODO Hardcoded style, max chars
Widget::new(Box::new(TextBox::new(ctx, 50, prefilled, exclusive_focus)))
}
// TODO Likewise
pub fn dropdown<T: 'static + PartialEq + Clone>(
ctx: &EventCtx,
label: &str,
@ -295,14 +271,6 @@ impl Widget {
.outline(2.0, Color::WHITE)
}
pub(crate) fn plot<T: 'static + Yvalue<T>>(plot: Plot<T>) -> Widget {
Widget::new(Box::new(plot))
}
pub(crate) fn histogram(histogram: Histogram) -> Widget {
Widget::new(Box::new(histogram))
}
pub fn row(widgets: Vec<Widget>) -> Widget {
Widget::new(Box::new(Container::new(true, widgets)))
}
@ -732,7 +700,7 @@ impl Composite {
self.find_mut(name)
}
pub fn menu<T: 'static + Clone>(&self, name: &str) -> &PopupMenu<T> {
pub fn menu<T: 'static + Clone>(&self, name: &str) -> &Menu<T> {
self.find(name)
}
@ -850,11 +818,12 @@ impl CompositeBuilder {
c.scrollable_x = true;
c.top_level = Widget::col(vec![
c.top_level,
Widget::slider(Slider::horizontal(
Slider::horizontal(
ctx,
c.container_dims.width,
c.container_dims.width * (c.container_dims.width / c.contents_dims.width),
))
0.0,
)
.named("horiz scrollbar")
.abs(top_left.x, top_left.y + c.container_dims.height),
]);
@ -863,11 +832,12 @@ impl CompositeBuilder {
c.scrollable_y = true;
c.top_level = Widget::row(vec![
c.top_level,
Widget::slider(Slider::vertical(
Slider::vertical(
ctx,
c.container_dims.height,
c.container_dims.height * (c.container_dims.height / c.contents_dims.height),
))
0.0,
)
.named("vert scrollbar")
.abs(top_left.x + c.container_dims.width, top_left.y),
]);

View File

@ -1,5 +1,5 @@
use crate::assets::Assets;
use crate::{svg, Color, EventCtx, GeomBatch, GfxCtx, Prerender, ScreenDims, Widget};
use crate::{svg, Color, EventCtx, GeomBatch, GfxCtx, JustDraw, Prerender, ScreenDims, Widget};
use geom::Polygon;
use std::collections::hash_map::DefaultHasher;
use std::fmt::Write;
@ -265,7 +265,7 @@ impl Text {
}
pub fn draw(self, ctx: &EventCtx) -> Widget {
Widget::draw_text(ctx, self)
JustDraw::wrap(ctx, self.render_ctx(ctx))
}
}

View File

@ -1,2 +1,3 @@
pub mod screenshot;
pub mod warper;
pub mod wizard;

View File

@ -1,6 +1,6 @@
use crate::{
hotkey, Btn, Color, Composite, EventCtx, GfxCtx, HorizontalAlignment, InputResult, Key, Line,
MultiKey, Outcome, PopupMenu, Text, VerticalAlignment, Widget,
Menu, MultiKey, Outcome, Text, VerticalAlignment, Widget,
};
use abstutil::Cloneable;
use std::collections::VecDeque;
@ -253,13 +253,13 @@ impl<'a, 'b> WrappedWizard<'a, 'b> {
col.push(Line(l).roboto_bold().draw(self.ctx));
}
col.push(
Widget::menu(PopupMenu::new(
Menu::new(
self.ctx,
choices
.into_iter()
.map(|c| c.with_value(c.data.clone_box()))
.collect(),
))
)
.named("menu"),
);
self.wizard.menu_comp = Some(

View File

@ -30,18 +30,21 @@ impl Button {
hovered: GeomBatch,
hotkey: Option<MultiKey>,
tooltip: &str,
maybe_tooltip: Option<Text>,
hitbox: Polygon,
) -> Button {
) -> Widget {
// dims are based on the hitbox, not the two drawables!
let bounds = hitbox.get_bounds();
let dims = ScreenDims::new(bounds.width(), bounds.height());
assert!(!tooltip.is_empty());
Button {
Widget::new(Box::new(Button {
action: tooltip.to_string(),
draw_normal: ctx.upload(normal),
draw_hovered: ctx.upload(hovered),
tooltip: if let Some(ref key) = hotkey {
tooltip: if let Some(t) = maybe_tooltip {
t
} else if let Some(ref key) = hotkey {
let mut txt = Text::from(Line(key.describe()).fg(text::HOTKEY_COLOR).size(20));
txt.append(Line(format!(" - {}", tooltip)));
txt
@ -55,7 +58,8 @@ impl Button {
top_left: ScreenPt::new(0.0, 0.0),
dims,
}
}))
.named(tooltip)
}
}
@ -236,18 +240,15 @@ impl BtnBuilder {
normal.rewrite_color(rewrite_normal);
hovered.rewrite_color(rewrite_hover);
let mut btn = Button::new(
Button::new(
ctx,
normal,
hovered,
key,
&action_tooltip.into(),
maybe_t,
bounds.get_rectangle(),
);
if let Some(t) = maybe_t {
btn.tooltip = t;
}
Widget::btn(btn)
)
}
BtnBuilder::TextFG(_, normal_txt, maybe_t) => {
// TODO Padding here is unfortunate, but I don't understand when the flexbox padding
@ -269,11 +270,16 @@ impl BtnBuilder {
let mut hovered = GeomBatch::new();
hovered.add_translated(selected_batch, horiz_padding, vert_padding);
let mut btn = Button::new(ctx, normal, hovered, key, &action_tooltip.into(), geom);
if let Some(t) = maybe_t {
btn.tooltip = t;
}
Widget::btn(btn).outline(2.0, Color::WHITE)
Button::new(
ctx,
normal,
hovered,
key,
&action_tooltip.into(),
maybe_t,
geom,
)
.outline(2.0, Color::WHITE)
}
BtnBuilder::TextBG {
text,
@ -299,20 +305,25 @@ impl BtnBuilder {
let mut hovered = GeomBatch::from(vec![(selected_bg_color, geom.clone())]);
hovered.add_translated(txt_batch.clone(), HORIZ_PADDING, VERT_PADDING);
let mut btn = Button::new(ctx, normal, hovered, key, &action_tooltip.into(), geom);
if let Some(t) = maybe_tooltip {
btn.tooltip = t;
}
Widget::btn(btn)
}
BtnBuilder::Custom(normal, hovered, hitbox, maybe_t) => {
let mut btn =
Button::new(ctx, normal, hovered, key, &action_tooltip.into(), hitbox);
if let Some(t) = maybe_t {
btn.tooltip = t;
}
Widget::btn(btn)
Button::new(
ctx,
normal,
hovered,
key,
&action_tooltip.into(),
maybe_tooltip,
geom,
)
}
BtnBuilder::Custom(normal, hovered, hitbox, maybe_t) => Button::new(
ctx,
normal,
hovered,
key,
&action_tooltip.into(),
maybe_t,
hitbox,
),
}
}
@ -335,11 +346,11 @@ impl BtnBuilder {
let btn = Btn::custom_text_fg(txt.change_fg(Color::grey(0.5)))
.build(ctx, "dummy", None)
.take_btn();
Widget::just_draw(JustDraw {
Widget::new(Box::new(JustDraw {
draw: btn.draw_normal,
top_left: btn.top_left,
dims: btn.dims,
})
}))
.outline(2.0, Color::WHITE)
}
// TODO This'll only work reasonably for text_bg2
@ -350,11 +361,11 @@ impl BtnBuilder {
assert_eq!(*unselected_bg_color, Color::WHITE);
*unselected_bg_color = Color::grey(0.5);
let btn = self.build(ctx, "dummy", None).take_btn();
Widget::just_draw(JustDraw {
Widget::new(Box::new(JustDraw {
draw: btn.draw_normal,
top_left: btn.top_left,
dims: btn.dims,
})
}))
}
_ => panic!("Can't use inactive on this kind of button"),
}

View File

@ -1,13 +1,13 @@
use crate::{
Btn, Button, Choice, Color, EventCtx, GfxCtx, InputResult, Outcome, PopupMenu, ScreenDims,
ScreenPt, WidgetImpl,
Btn, Button, Choice, Color, EventCtx, GfxCtx, InputResult, Menu, Outcome, ScreenDims, ScreenPt,
WidgetImpl,
};
use geom::{Polygon, Pt2D};
pub struct Dropdown<T: Clone> {
current_idx: usize,
btn: Button,
menu: Option<PopupMenu<usize>>,
menu: Option<Menu<usize>>,
label: String,
choices: Vec<Choice<T>>,
@ -70,15 +70,18 @@ impl<T: 'static + Clone> WidgetImpl for Dropdown<T> {
} else {
if self.btn.event(ctx, redo_layout).is_some() {
// TODO set current idx in menu
// TODO Choice::map_value?
let mut menu = PopupMenu::new(
let mut menu = *Menu::new(
ctx,
self.choices
.iter()
.enumerate()
.map(|(idx, c)| c.with_value(idx))
.collect(),
);
)
.widget
.downcast::<Menu<usize>>()
.ok()
.unwrap();
menu.set_pos(ScreenPt::new(
self.btn.top_left.x,
self.btn.top_left.y + self.btn.dims.height + 15.0,

View File

@ -1,4 +1,4 @@
use crate::{EventCtx, GfxCtx, Outcome, ScreenDims, ScreenPt, WidgetImpl};
use crate::{EventCtx, GfxCtx, Outcome, ScreenDims, ScreenPt, Widget, WidgetImpl};
// Doesn't do anything by itself, just used for widgetsing. Something else reaches in, asks for the
// ScreenRectangle to use.
@ -8,11 +8,11 @@ pub struct Filler {
}
impl Filler {
pub fn new(dims: ScreenDims) -> Filler {
Filler {
pub fn new(dims: ScreenDims) -> Widget {
Widget::new(Box::new(Filler {
dims,
top_left: ScreenPt::new(0.0, 0.0),
}
}))
}
}

View File

@ -95,7 +95,10 @@ impl Histogram {
// Don't let the x-axis fill the parent container
Widget::row(vec![Widget::col(vec![
Widget::row(vec![y_axis.evenly_spaced(), Widget::histogram(histogram)]),
Widget::row(vec![
y_axis.evenly_spaced(),
Widget::new(Box::new(histogram)),
]),
x_axis.evenly_spaced(),
])])
}

View File

@ -1,5 +1,5 @@
use crate::{
svg, Drawable, EventCtx, GeomBatch, GfxCtx, Outcome, RewriteColor, ScreenDims, ScreenPt, Text,
svg, Drawable, EventCtx, GeomBatch, GfxCtx, Outcome, RewriteColor, ScreenDims, ScreenPt,
Widget, WidgetImpl,
};
@ -12,36 +12,32 @@ pub struct JustDraw {
}
impl JustDraw {
pub fn wrap(ctx: &EventCtx, batch: GeomBatch) -> Widget {
Widget::just_draw(JustDraw {
pub(crate) fn wrap(ctx: &EventCtx, batch: GeomBatch) -> Widget {
Widget::new(Box::new(JustDraw {
dims: batch.get_dims(),
draw: ctx.upload(batch),
top_left: ScreenPt::new(0.0, 0.0),
})
}))
}
pub fn svg(ctx: &EventCtx, filename: &str) -> Widget {
pub(crate) fn svg(ctx: &EventCtx, filename: &str) -> Widget {
let (batch, bounds) = svg::load_svg(ctx.prerender, filename);
// TODO The dims will be wrong; it'll only look at geometry, not the padding in the image.
Widget::just_draw(JustDraw {
Widget::new(Box::new(JustDraw {
dims: ScreenDims::new(bounds.width(), bounds.height()),
draw: ctx.upload(batch),
top_left: ScreenPt::new(0.0, 0.0),
})
}))
}
pub fn svg_transform(ctx: &EventCtx, filename: &str, rewrite: RewriteColor) -> Widget {
pub(crate) fn svg_transform(ctx: &EventCtx, filename: &str, rewrite: RewriteColor) -> Widget {
let (mut batch, bounds) = svg::load_svg(ctx.prerender, filename);
batch.rewrite_color(rewrite);
// TODO The dims will be wrong; it'll only look at geometry, not the padding in the image.
Widget::just_draw(JustDraw {
Widget::new(Box::new(JustDraw {
dims: ScreenDims::new(bounds.width(), bounds.height()),
draw: ctx.upload(batch),
top_left: ScreenPt::new(0.0, 0.0),
})
}
pub fn text(ctx: &EventCtx, text: Text) -> Widget {
JustDraw::wrap(ctx, text.render_ctx(ctx))
}))
}
}

View File

@ -1,10 +1,10 @@
use crate::{
hotkey, text, Choice, EventCtx, GfxCtx, InputResult, Key, Line, Outcome, ScreenDims, ScreenPt,
ScreenRectangle, Text, WidgetImpl,
ScreenRectangle, Text, Widget, WidgetImpl,
};
use geom::Pt2D;
pub struct PopupMenu<T: Clone> {
pub struct Menu<T: Clone> {
choices: Vec<Choice<T>>,
current_idx: usize,
@ -14,9 +14,9 @@ pub struct PopupMenu<T: Clone> {
dims: ScreenDims,
}
impl<T: Clone> PopupMenu<T> {
pub fn new(ctx: &EventCtx, choices: Vec<Choice<T>>) -> PopupMenu<T> {
let mut m = PopupMenu {
impl<T: 'static + Clone> Menu<T> {
pub fn new(ctx: &EventCtx, choices: Vec<Choice<T>>) -> Widget {
let mut m = Menu {
choices,
current_idx: 0,
@ -26,7 +26,7 @@ impl<T: Clone> PopupMenu<T> {
dims: ScreenDims::new(0.0, 0.0),
};
m.dims = m.calculate_txt().dims(&ctx.prerender.assets);
m
Widget::new(Box::new(m))
}
pub fn current_choice(&self) -> &T {
@ -70,7 +70,7 @@ impl<T: Clone> PopupMenu<T> {
}
}
impl<T: 'static + Clone> WidgetImpl for PopupMenu<T> {
impl<T: 'static + Clone> WidgetImpl for Menu<T> {
fn get_dims(&self) -> ScreenDims {
self.dims
}

View File

@ -5,12 +5,11 @@ pub mod containers;
pub mod dropdown;
pub mod filler;
pub mod histogram;
pub mod no_op;
pub mod just_draw;
pub mod menu;
pub mod plot;
pub mod popup_menu;
pub mod slider;
pub mod text_box;
pub mod wizard;
use crate::{EventCtx, GfxCtx, Outcome, ScreenDims, ScreenPt};

View File

@ -207,7 +207,7 @@ impl Plot<usize> {
// Don't let the x-axis fill the parent container
Widget::row(vec![Widget::col(vec![
legend,
Widget::row(vec![y_axis.evenly_spaced(), Widget::plot(plot)]),
Widget::row(vec![y_axis.evenly_spaced(), Widget::new(Box::new(plot))]),
x_axis.evenly_spaced(),
])])
}
@ -223,7 +223,7 @@ impl Plot<Duration> {
// Don't let the x-axis fill the parent container
Widget::row(vec![Widget::col(vec![
legend,
Widget::row(vec![y_axis.evenly_spaced(), Widget::plot(plot)]),
Widget::row(vec![y_axis.evenly_spaced(), Widget::new(Box::new(plot))]),
x_axis.evenly_spaced(),
])])
}

View File

@ -1,6 +1,6 @@
use crate::{
Color, Drawable, EventCtx, GeomBatch, GfxCtx, Outcome, ScreenDims, ScreenPt, ScreenRectangle,
WidgetImpl,
Widget, WidgetImpl,
};
use geom::Polygon;
@ -22,9 +22,14 @@ pub struct Slider {
const BG_CROSS_AXIS_LEN: f64 = 20.0;
impl Slider {
pub fn horizontal(ctx: &EventCtx, width: f64, dragger_len: f64) -> Slider {
pub fn horizontal(
ctx: &EventCtx,
width: f64,
dragger_len: f64,
current_percent: f64,
) -> Widget {
let mut s = Slider {
current_percent: 0.0,
current_percent,
mouse_on_slider: false,
dragging: false,
@ -38,12 +43,12 @@ impl Slider {
dims: ScreenDims::new(0.0, 0.0),
};
s.recalc(ctx);
s
Widget::new(Box::new(s))
}
pub fn vertical(ctx: &EventCtx, height: f64, dragger_len: f64) -> Slider {
pub fn vertical(ctx: &EventCtx, height: f64, dragger_len: f64, current_percent: f64) -> Widget {
let mut s = Slider {
current_percent: 0.0,
current_percent,
mouse_on_slider: false,
dragging: false,
@ -57,7 +62,7 @@ impl Slider {
dims: ScreenDims::new(0.0, 0.0),
};
s.recalc(ctx);
s
Widget::new(Box::new(s))
}
fn recalc(&mut self, ctx: &EventCtx) {
@ -128,10 +133,6 @@ impl Slider {
}
}
pub fn set_value(&mut self, ctx: &EventCtx, idx: usize, num_items: usize) {
self.set_percent(ctx, (idx as f64) / (num_items as f64 - 1.0));
}
fn inner_event(&mut self, ctx: &mut EventCtx) -> bool {
if self.dragging {
if ctx.input.get_moved_mouse().is_some() {

View File

@ -286,8 +286,7 @@ fn make_minimap_panel(ctx: &mut EventCtx, app: &App, zoom_lvl: usize) -> Composi
.build(ctx, "pan left", None)
.margin(5)
.centered_vert(),
Widget::filler(Filler::new(ScreenDims::new(square_len, square_len)))
.named("minimap"),
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)

View File

@ -11,8 +11,8 @@ use crate::render::MIN_ZOOM_FOR_DETAIL;
use abstutil::{prettyprint_usize, Counter};
use ezgui::{
hotkey, Btn, Color, Composite, Drawable, EventCtx, GeomBatch, GfxCtx, Histogram,
HorizontalAlignment, JustDraw, Key, Line, Outcome, Plot, PlotOptions, RewriteColor, Series,
Slider, Text, TextExt, VerticalAlignment, Widget,
HorizontalAlignment, Key, Line, Outcome, Plot, PlotOptions, RewriteColor, Series, Slider, Text,
TextExt, VerticalAlignment, Widget,
};
use geom::{Circle, Distance, Duration, PolyLine, Polygon, Pt2D, Statistic, Time};
use map_model::{BusRouteID, IntersectionID};
@ -893,7 +893,7 @@ impl Overlays {
.to_polygon(),
);
}
let timeline = JustDraw::wrap(ctx, batch);
let timeline = Widget::draw_batch(ctx, batch);
master_col.push(Widget::row(vec![
timeline.margin(5),
@ -1074,27 +1074,19 @@ fn population_controls(ctx: &mut EventCtx, app: &App, opts: Option<&HeatmapOptio
// TODO Display the value...
col.push(Widget::row(vec![
"Resolution (meters)".draw_text(ctx).margin(5),
Widget::slider({
let mut slider = Slider::horizontal(ctx, 100.0, 25.0);
// 1 to 100m
slider.set_percent(ctx, (o.resolution - 1.0) / 99.0);
slider
})
.named("resolution")
.align_right()
.centered_vert(),
// 1 to 100m
Slider::horizontal(ctx, 100.0, 25.0, (o.resolution - 1.0) / 99.0)
.named("resolution")
.align_right()
.centered_vert(),
]));
col.push(Widget::row(vec![
"Diffusion (num of passes)".draw_text(ctx).margin(5),
Widget::slider({
let mut slider = Slider::horizontal(ctx, 100.0, 25.0);
// 0 to 10
slider.set_percent(ctx, (o.num_passes as f64) / 10.0);
slider
})
.named("passes")
.align_right()
.centered_vert(),
// 0 to 10
Slider::horizontal(ctx, 100.0, 25.0, (o.num_passes as f64) / 10.0)
.named("passes")
.align_right()
.centered_vert(),
]));
col.push(Widget::dropdown(

View File

@ -219,7 +219,7 @@ fn make_panel(ctx: &mut EventCtx) -> Composite {
Btn::text_fg(">").build(ctx, "next", hotkey(Key::RightArrow)),
])
.evenly_spaced(),
Widget::slider(Slider::horizontal(ctx, 100.0, 25.0))
Slider::horizontal(ctx, 100.0, 25.0, 0.0)
.named("slider")
.centered_horiz(),
])

View File

@ -559,7 +559,7 @@ impl DotMap {
.build_def(ctx, hotkey(Key::Escape))
.align_right(),
]),
Widget::slider(Slider::horizontal(ctx, 150.0, 25.0)).named("time slider"),
Slider::horizontal(ctx, 150.0, 25.0, 0.0).named("time slider"),
])
.padding(10)
.bg(colors::PANEL_BG),

View File

@ -7,7 +7,7 @@ use crate::game::{State, Transition};
use crate::managed::{Callback, ManagedGUIState, WrappedComposite, WrappedOutcome};
use crate::sandbox::{GameplayMode, SandboxMode, TutorialPointer};
use ezgui::{
hotkey, hotkeys, Btn, Color, Composite, EventCtx, EventLoopMode, GfxCtx, JustDraw, Key, Line,
hotkey, hotkeys, Btn, Color, Composite, EventCtx, EventLoopMode, GfxCtx, Key, Line,
RewriteColor, Text, Widget,
};
use geom::{Duration, Line, Pt2D, Speed};
@ -29,7 +29,7 @@ impl TitleScreen {
composite: WrappedComposite::new(
Composite::new(
Widget::col(vec![
JustDraw::svg(ctx, "../data/system/assets/pregame/logo.svg").margin(5),
Widget::draw_svg(ctx, "../data/system/assets/pregame/logo.svg").margin(5),
// TODO that nicer font
// TODO Any key
Btn::text_bg2("PLAY")

View File

@ -362,13 +362,13 @@ impl JumpToTime {
txt.draw(ctx)
}
.named("target time"),
Widget::slider({
// TODO Auto-fill width?
let mut slider =
Slider::horizontal(ctx, 0.25 * ctx.canvas.window_width, 25.0);
slider.set_percent(ctx, target.to_percent(Time::END_OF_DAY).min(1.0));
slider
})
// TODO Auto-fill width?
Slider::horizontal(
ctx,
0.25 * ctx.canvas.window_width,
25.0,
target.to_percent(Time::END_OF_DAY).min(1.0),
)
.named("time slider")
.margin(10),
Widget::row(vec![