fleshing out the ezgui demo, and fixing a little bug with checkboxes

This commit is contained in:
Dustin Carlino 2020-03-06 10:31:08 -08:00
parent da6b4c57a0
commit a8f862f83d
3 changed files with 155 additions and 23 deletions

View File

@ -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);
}
}
}

View File

@ -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
}

View File

@ -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
}
}