mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-29 17:34:58 +03:00
moving ezgui stuff around a little, cleaning up some of the APIs for
instantiating widgets
This commit is contained in:
parent
96d7987c7e
commit
b6eb46ec04
@ -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> {
|
||||
|
@ -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),
|
||||
]);
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,2 +1,3 @@
|
||||
pub mod screenshot;
|
||||
pub mod warper;
|
||||
pub mod wizard;
|
||||
|
@ -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(
|
@ -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"),
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
])])
|
||||
}
|
||||
|
@ -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))
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -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};
|
||||
|
||||
|
@ -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(),
|
||||
])])
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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)
|
||||
|
@ -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(
|
||||
|
@ -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(),
|
||||
])
|
||||
|
@ -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),
|
||||
|
@ -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")
|
||||
|
@ -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![
|
||||
|
Loading…
Reference in New Issue
Block a user