mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-29 12:43:38 +03:00
fleshing out the ezgui demo, and fixing a little bug with checkboxes
This commit is contained in:
parent
da6b4c57a0
commit
a8f862f83d
@ -5,19 +5,16 @@
|
||||
// > cargo web start --target wasm32-unknown-unknown --features wasm-backend --example demo
|
||||
|
||||
use ezgui::{
|
||||
hotkey, Button, Color, Composite, Drawable, EventCtx, EventLoopMode, GeomBatch, GfxCtx,
|
||||
HorizontalAlignment, Key, Line, ManagedWidget, Outcome, Text, VerticalAlignment, GUI,
|
||||
hotkey, lctrl, Button, Color, Composite, Drawable, EventCtx, EventLoopMode, GeomBatch, GfxCtx,
|
||||
HorizontalAlignment, Key, Line, ManagedWidget, Outcome, Plot, PlotOptions, Series, Text,
|
||||
VerticalAlignment, GUI,
|
||||
};
|
||||
use geom::{Angle, Duration, Polygon, Pt2D};
|
||||
|
||||
// TODO Add text to the logo (showing zoom)
|
||||
// TODO Some kind of plot?!
|
||||
// TODO Some popup dialogs with form entry, even some scrolling
|
||||
// TODO Loading screen with timer?
|
||||
use geom::{Angle, Duration, Polygon, Pt2D, Time};
|
||||
|
||||
struct App {
|
||||
top_center: Composite,
|
||||
draw: Drawable,
|
||||
side_panel: Option<(Duration, Composite)>,
|
||||
|
||||
elapsed: Duration,
|
||||
}
|
||||
@ -25,7 +22,10 @@ struct App {
|
||||
impl App {
|
||||
fn new(ctx: &mut EventCtx) -> App {
|
||||
let mut batch = GeomBatch::new();
|
||||
batch.push(Color::RED, Polygon::rounded_rectangle(5000.0, 5000.0, 25.0));
|
||||
batch.push(
|
||||
Color::hex("#4E30A6"),
|
||||
Polygon::rounded_rectangle(5000.0, 5000.0, 25.0),
|
||||
);
|
||||
batch.add_svg(
|
||||
&ctx.prerender,
|
||||
"../data/system/assets/pregame/logo.svg",
|
||||
@ -34,8 +34,10 @@ impl App {
|
||||
Angle::ZERO,
|
||||
);
|
||||
batch.add_transformed(
|
||||
Text::from(Line("Awesome vector text thanks to usvg and lyon"))
|
||||
.render_to_batch(&ctx.prerender),
|
||||
Text::from(
|
||||
Line("Awesome vector text thanks to usvg and lyon").fg(Color::hex("#DF8C3D")),
|
||||
)
|
||||
.render_to_batch(&ctx.prerender),
|
||||
Pt2D::new(600.0, 500.0),
|
||||
2.0,
|
||||
Angle::new_degs(30.0),
|
||||
@ -73,7 +75,8 @@ impl App {
|
||||
ctx,
|
||||
),
|
||||
)
|
||||
.named("paused"),
|
||||
.named("paused")
|
||||
.margin(5),
|
||||
ManagedWidget::btn(Button::text_no_bg(
|
||||
Text::from(Line("Reset")),
|
||||
Text::from(Line("Reset").fg(Color::ORANGE)),
|
||||
@ -82,8 +85,12 @@ impl App {
|
||||
true,
|
||||
ctx,
|
||||
))
|
||||
.outline(3.0, Color::WHITE),
|
||||
ManagedWidget::checkbox(ctx, "Draw logo", None, true),
|
||||
.outline(3.0, Color::WHITE)
|
||||
.margin(5),
|
||||
ManagedWidget::checkbox(ctx, "Draw scrollable canvas", None, true)
|
||||
.margin(5),
|
||||
ManagedWidget::checkbox(ctx, "Show timeseries", lctrl(Key::T), false)
|
||||
.margin(5),
|
||||
])
|
||||
.evenly_spaced(),
|
||||
ManagedWidget::draw_text(ctx, Text::from(Line("Stopwatch: ...")))
|
||||
@ -94,10 +101,102 @@ impl App {
|
||||
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
|
||||
.build(ctx),
|
||||
draw: batch.upload(ctx),
|
||||
side_panel: None,
|
||||
|
||||
elapsed: Duration::ZERO,
|
||||
}
|
||||
}
|
||||
|
||||
fn make_sidepanel(&self, ctx: &mut EventCtx) -> Composite {
|
||||
let mut col1 = vec![ManagedWidget::draw_text(
|
||||
ctx,
|
||||
Text::from(Line("Time").roboto_bold()),
|
||||
)];
|
||||
let mut col2 = vec![ManagedWidget::draw_text(
|
||||
ctx,
|
||||
Text::from(Line("Linear").roboto_bold()),
|
||||
)];
|
||||
let mut col3 = vec![ManagedWidget::draw_text(
|
||||
ctx,
|
||||
Text::from(Line("Quadratic").roboto_bold()),
|
||||
)];
|
||||
for s in 0..(self.elapsed.inner_seconds() as usize) {
|
||||
col1.push(ManagedWidget::draw_text(
|
||||
ctx,
|
||||
Text::from(Line(Duration::seconds(s as f64).to_string())),
|
||||
));
|
||||
col2.push(ManagedWidget::draw_text(
|
||||
ctx,
|
||||
Text::from(Line(s.to_string())),
|
||||
));
|
||||
col3.push(ManagedWidget::draw_text(
|
||||
ctx,
|
||||
Text::from(Line(s.pow(2).to_string())),
|
||||
));
|
||||
}
|
||||
|
||||
let mut c = Composite::new(
|
||||
ManagedWidget::col(vec![
|
||||
ManagedWidget::row(vec![ManagedWidget::draw_text(ctx, {
|
||||
let mut txt = Text::from(
|
||||
Line("Here's a bunch of text to force some scrolling.").roboto_bold(),
|
||||
);
|
||||
txt.add(
|
||||
Line(
|
||||
"Bug: scrolling by clicking and dragging doesn't work while the \
|
||||
stopwatch is running.",
|
||||
)
|
||||
.fg(Color::RED),
|
||||
);
|
||||
txt
|
||||
})]),
|
||||
ManagedWidget::row(vec![
|
||||
ManagedWidget::col(col1)
|
||||
.outline(3.0, Color::BLACK)
|
||||
.margin(5),
|
||||
ManagedWidget::col(col2)
|
||||
.outline(3.0, Color::BLACK)
|
||||
.margin(5),
|
||||
ManagedWidget::col(col3)
|
||||
.outline(3.0, Color::BLACK)
|
||||
.margin(5),
|
||||
]),
|
||||
Plot::new_usize(
|
||||
ctx,
|
||||
vec![
|
||||
Series {
|
||||
label: "Linear".to_string(),
|
||||
color: Color::GREEN,
|
||||
pts: (0..(self.elapsed.inner_seconds() as usize))
|
||||
.map(|s| (Time::START_OF_DAY + Duration::seconds(s as f64), s))
|
||||
.collect(),
|
||||
},
|
||||
Series {
|
||||
label: "Quadratic".to_string(),
|
||||
color: Color::BLUE,
|
||||
pts: (0..(self.elapsed.inner_seconds() as usize))
|
||||
.map(|s| {
|
||||
(Time::START_OF_DAY + Duration::seconds(s as f64), s.pow(2))
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
],
|
||||
PlotOptions {
|
||||
max_x: Some(Time::START_OF_DAY + self.elapsed),
|
||||
},
|
||||
),
|
||||
])
|
||||
.bg(Color::grey(0.4)),
|
||||
)
|
||||
.max_size_percent(30, 40)
|
||||
.aligned(HorizontalAlignment::Percent(0.6), VerticalAlignment::Center)
|
||||
.build(ctx);
|
||||
|
||||
if let Some((_, ref old)) = self.side_panel {
|
||||
c.restore_scroll(ctx, old.preserve_scroll());
|
||||
}
|
||||
c
|
||||
}
|
||||
}
|
||||
|
||||
impl GUI for App {
|
||||
@ -138,6 +237,27 @@ impl GUI for App {
|
||||
);
|
||||
}
|
||||
|
||||
if self.top_center.is_checked("Show timeseries") {
|
||||
if self
|
||||
.side_panel
|
||||
.as_ref()
|
||||
.map(|(dt, _)| *dt != self.elapsed)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
self.side_panel = Some((self.elapsed, self.make_sidepanel(ctx)));
|
||||
}
|
||||
} else {
|
||||
self.side_panel = None;
|
||||
}
|
||||
|
||||
if let Some((_, ref mut p)) = self.side_panel {
|
||||
match p.event(ctx) {
|
||||
// No buttons in there
|
||||
Some(Outcome::Clicked(_)) => unreachable!(),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
if self.top_center.is_checked("paused") {
|
||||
EventLoopMode::InputOnly
|
||||
} else {
|
||||
@ -148,11 +268,15 @@ impl GUI for App {
|
||||
fn draw(&self, g: &mut GfxCtx) {
|
||||
g.clear(Color::BLACK);
|
||||
|
||||
if self.top_center.is_checked("Draw logo") {
|
||||
if self.top_center.is_checked("Draw scrollable canvas") {
|
||||
g.redraw(&self.draw);
|
||||
}
|
||||
|
||||
self.top_center.draw(g);
|
||||
|
||||
if let Some((_, ref p)) = self.side_panel {
|
||||
p.draw(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,6 +391,7 @@ impl ManagedWidget {
|
||||
ctx: &mut EventCtx,
|
||||
sliders: &mut HashMap<String, Slider>,
|
||||
menus: &mut HashMap<String, Menu>,
|
||||
redo_layout: &mut bool,
|
||||
) -> Option<Outcome> {
|
||||
match self.widget {
|
||||
WidgetType::Draw(_) => {}
|
||||
@ -401,7 +402,9 @@ impl ManagedWidget {
|
||||
}
|
||||
}
|
||||
WidgetType::Checkbox(ref mut checkbox) => {
|
||||
checkbox.event(ctx);
|
||||
if checkbox.event(ctx) {
|
||||
*redo_layout = true;
|
||||
}
|
||||
}
|
||||
WidgetType::TextBox(ref mut textbox) => {
|
||||
textbox.event(ctx);
|
||||
@ -421,7 +424,7 @@ impl ManagedWidget {
|
||||
| WidgetType::Histogram(_) => {}
|
||||
WidgetType::Row(ref mut widgets) | WidgetType::Column(ref mut widgets) => {
|
||||
for w in widgets {
|
||||
if let Some(o) = w.event(ctx, sliders, menus) {
|
||||
if let Some(o) = w.event(ctx, sliders, menus, redo_layout) {
|
||||
return Some(o);
|
||||
}
|
||||
}
|
||||
@ -937,11 +940,12 @@ impl Composite {
|
||||
}
|
||||
|
||||
let before = self.scroll_offset();
|
||||
let result = self
|
||||
.top_level
|
||||
.event(ctx, &mut self.sliders, &mut self.menus);
|
||||
if self.scroll_offset() != before {
|
||||
self.recompute_layout(ctx, false);
|
||||
let mut redo_layout = false;
|
||||
let result =
|
||||
self.top_level
|
||||
.event(ctx, &mut self.sliders, &mut self.menus, &mut redo_layout);
|
||||
if self.scroll_offset() != before || redo_layout {
|
||||
self.recompute_layout(ctx, true);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
@ -24,12 +24,16 @@ impl Checkbox {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn event(&mut self, ctx: &mut EventCtx) {
|
||||
// If true, layout should be recomputed.
|
||||
pub(crate) fn event(&mut self, ctx: &mut EventCtx) -> bool {
|
||||
self.btn.event(ctx);
|
||||
if self.btn.clicked() {
|
||||
std::mem::swap(&mut self.btn, &mut self.other_btn);
|
||||
self.btn.set_pos(self.other_btn.top_left);
|
||||
self.enabled = !self.enabled;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user