let plots have a chance to update themselves. hacky.

This commit is contained in:
Dustin Carlino 2020-04-06 12:16:54 -07:00
parent 694b1f6cc9
commit 5868fe4736
22 changed files with 167 additions and 114 deletions

View File

@ -49,7 +49,7 @@ pub use crate::event::{hotkey, hotkeys, lctrl, Event, Key, MultiKey};
pub use crate::event_ctx::EventCtx;
pub use crate::geom::{GeomBatch, RewriteColor};
pub use crate::input::UserInput;
pub use crate::managed::{Composite, Outcome, Widget};
pub use crate::managed::{Composite, Widget};
pub use crate::runner::{run, EventLoopMode, Settings, GUI};
pub use crate::screen_geom::{ScreenDims, ScreenPt, ScreenRectangle};
pub use crate::style::Style;
@ -70,7 +70,7 @@ pub use crate::widgets::plot::{Plot, PlotOptions, Series};
pub use crate::widgets::slider::Slider;
pub use crate::widgets::spinner::Spinner;
pub(crate) use crate::widgets::text_box::TextBox;
pub use crate::widgets::WidgetImpl;
pub use crate::widgets::{Outcome, WidgetImpl, WidgetOutput};
pub(crate) enum InputResult<T: Clone> {
Canceled,

View File

@ -1,8 +1,9 @@
use crate::widgets::containers::{Container, Nothing};
use crate::{
Autocomplete, Button, Checkbox, Choice, Color, Drawable, Dropdown, EventCtx, Filler, GeomBatch,
GfxCtx, HorizontalAlignment, JustDraw, Menu, PersistentSplit, RewriteColor, ScreenDims,
ScreenPt, ScreenRectangle, Slider, Spinner, TextBox, VerticalAlignment, WidgetImpl,
GfxCtx, HorizontalAlignment, JustDraw, Menu, Outcome, PersistentSplit, RewriteColor,
ScreenDims, ScreenPt, ScreenRectangle, Slider, Spinner, TextBox, VerticalAlignment, WidgetImpl,
WidgetOutput,
};
use geom::{Distance, Polygon};
use std::collections::HashSet;
@ -425,6 +426,9 @@ impl Widget {
pub(crate) fn take_just_draw(self) -> JustDraw {
*self.widget.downcast::<JustDraw>().ok().unwrap()
}
pub(crate) fn take_checkbox(self) -> Checkbox {
*self.widget.downcast::<Checkbox>().ok().unwrap()
}
}
enum Dims {
@ -453,10 +457,6 @@ pub struct Composite {
clip_rect: Option<ScreenRectangle>,
}
pub enum Outcome {
Clicked(String),
}
const SCROLL_SPEED: f64 = 5.0;
impl Composite {
@ -586,12 +586,27 @@ impl Composite {
}
let before = self.scroll_offset();
let mut redo_layout = false;
let result = self.top_level.widget.event(ctx, &mut redo_layout);
if self.scroll_offset() != before || redo_layout {
let mut output = WidgetOutput {
redo_layout: false,
outcome: None,
plot_changed: Vec::new(),
};
self.top_level.widget.event(ctx, &mut output);
if self.scroll_offset() != before || output.redo_layout {
self.recompute_layout(ctx, true);
}
result
// TODO Fantastic hack
for ((plot_id, checkbox_label), enabled) in output.plot_changed {
// TODO Can't downcast and ignore the type param
self.top_level
.find_mut(&plot_id)
.unwrap()
.widget
.update_series(checkbox_label, enabled);
}
output.outcome
}
pub fn draw(&self, g: &mut GfxCtx) {

View File

@ -1,6 +1,6 @@
use crate::{
Choice, EventCtx, GfxCtx, InputResult, Menu, Outcome, ScreenDims, ScreenPt, TextBox, Widget,
WidgetImpl,
Choice, EventCtx, GfxCtx, InputResult, Menu, ScreenDims, ScreenPt, TextBox, Widget, WidgetImpl,
WidgetOutput,
};
use simsearch::SimSearch;
use std::collections::HashMap;
@ -88,16 +88,16 @@ impl<T: 'static + Clone> WidgetImpl for Autocomplete<T> {
));
}
fn event(&mut self, ctx: &mut EventCtx, redo_layout: &mut bool) -> Option<Outcome> {
fn event(&mut self, ctx: &mut EventCtx, output: &mut WidgetOutput) {
assert!(self.chosen_values.is_none());
self.tb.event(ctx, redo_layout);
self.tb.event(ctx, output);
if self.tb.get_line() != self.current_line {
self.current_line = self.tb.get_line();
self.recalc_menu(ctx);
*redo_layout = true;
output.redo_layout = true;
} else {
self.menu.event(ctx, redo_layout);
self.menu.event(ctx, output);
match self.menu.state {
InputResult::StillActive => {}
// Ignore this and make sure the Composite has a quit control
@ -109,8 +109,6 @@ impl<T: 'static + Clone> WidgetImpl for Autocomplete<T> {
}
}
}
None
}
fn draw(&self, g: &mut GfxCtx) {

View File

@ -1,6 +1,6 @@
use crate::{
svg, Color, Drawable, EventCtx, GeomBatch, GfxCtx, JustDraw, Line, MultiKey, Outcome,
RewriteColor, ScreenDims, ScreenPt, Text, Widget, WidgetImpl,
RewriteColor, ScreenDims, ScreenPt, Text, Widget, WidgetImpl, WidgetOutput,
};
use geom::Polygon;
@ -68,7 +68,7 @@ impl WidgetImpl for Button {
self.top_left = top_left;
}
fn event(&mut self, ctx: &mut EventCtx, _redo_layout: &mut bool) -> Option<Outcome> {
fn event(&mut self, ctx: &mut EventCtx, output: &mut WidgetOutput) {
if ctx.redo_mouseover() {
if let Some(pt) = ctx.canvas.get_cursor_in_screen_space() {
self.hovering = self
@ -81,21 +81,21 @@ impl WidgetImpl for Button {
}
if self.hovering && ctx.normal_left_click() {
self.hovering = false;
return Some(Outcome::Clicked(self.action.clone()));
output.outcome = Some(Outcome::Clicked(self.action.clone()));
return;
}
if let Some(ref hotkey) = self.hotkey {
if ctx.input.new_was_pressed(hotkey) {
self.hovering = false;
return Some(Outcome::Clicked(self.action.clone()));
output.outcome = Some(Outcome::Clicked(self.action.clone()));
return;
}
}
if self.hovering {
ctx.cursor_clickable();
}
None
}
fn draw(&self, g: &mut GfxCtx) {

View File

@ -1,11 +1,14 @@
use crate::{
Btn, Button, EventCtx, GfxCtx, MultiKey, Outcome, ScreenDims, ScreenPt, Widget, WidgetImpl,
Btn, Button, EventCtx, GfxCtx, MultiKey, ScreenDims, ScreenPt, Widget, WidgetImpl, WidgetOutput,
};
pub struct Checkbox {
pub(crate) enabled: bool,
btn: Button,
other_btn: Button,
// TODO Biiiit of a hack. If Plot could embed a Composite, that'd actually work better.
cb_to_plot: Option<(String, String)>,
}
impl Checkbox {
@ -16,12 +19,14 @@ impl Checkbox {
enabled,
btn: true_btn.take_btn(),
other_btn: false_btn.take_btn(),
cb_to_plot: None,
}))
} else {
Widget::new(Box::new(Checkbox {
enabled,
btn: false_btn.take_btn(),
other_btn: true_btn.take_btn(),
cb_to_plot: None,
}))
}
}
@ -35,6 +40,11 @@ impl Checkbox {
.outline(ctx.style().outline_thickness, ctx.style().outline_color)
.named(label)
}
pub(crate) fn callback_to_plot(mut self, plot_id: &str, checkbox_label: &str) -> Checkbox {
self.cb_to_plot = Some((plot_id.to_string(), checkbox_label.to_string()));
self
}
}
impl WidgetImpl for Checkbox {
@ -46,15 +56,17 @@ impl WidgetImpl for Checkbox {
self.btn.set_pos(top_left);
}
fn event(&mut self, ctx: &mut EventCtx, redo_layout: &mut bool) -> Option<Outcome> {
if self.btn.event(ctx, redo_layout).is_some() {
fn event(&mut self, ctx: &mut EventCtx, output: &mut WidgetOutput) {
self.btn.event(ctx, output);
if output.outcome.take().is_some() {
std::mem::swap(&mut self.btn, &mut self.other_btn);
self.btn.set_pos(self.other_btn.top_left);
self.enabled = !self.enabled;
*redo_layout = true;
output.redo_layout = true;
if let Some(ref pair) = self.cb_to_plot {
output.plot_changed.push((pair.clone(), self.enabled));
}
}
None
}
fn draw(&self, g: &mut GfxCtx) {

View File

@ -1,4 +1,4 @@
use crate::{EventCtx, GfxCtx, Outcome, ScreenDims, ScreenPt, Widget, WidgetImpl};
use crate::{EventCtx, GfxCtx, ScreenDims, ScreenPt, Widget, WidgetImpl, WidgetOutput};
pub struct Nothing {}
@ -11,7 +11,7 @@ impl WidgetImpl for Nothing {
unreachable!()
}
fn event(&mut self, _ctx: &mut EventCtx, _redo_layout: &mut bool) -> Option<Outcome> {
fn event(&mut self, _ctx: &mut EventCtx, _output: &mut WidgetOutput) {
unreachable!()
}
fn draw(&self, _g: &mut GfxCtx) {
@ -40,13 +40,13 @@ impl WidgetImpl for Container {
unreachable!()
}
fn event(&mut self, ctx: &mut EventCtx, redo_layout: &mut bool) -> Option<Outcome> {
fn event(&mut self, ctx: &mut EventCtx, output: &mut WidgetOutput) {
for w in &mut self.members {
if let Some(o) = w.widget.event(ctx, redo_layout) {
return Some(o);
w.widget.event(ctx, output);
if output.outcome.is_some() {
return;
}
}
None
}
fn draw(&self, g: &mut GfxCtx) {

View File

@ -1,6 +1,6 @@
use crate::{
Btn, Button, Choice, Color, EventCtx, GeomBatch, GfxCtx, InputResult, Menu, Outcome,
ScreenDims, ScreenPt, ScreenRectangle, WidgetImpl,
Btn, Button, Choice, Color, EventCtx, GeomBatch, GfxCtx, InputResult, Menu, ScreenDims,
ScreenPt, ScreenRectangle, WidgetImpl, WidgetOutput,
};
use geom::{Distance, Polygon, Pt2D};
@ -56,9 +56,9 @@ impl<T: 'static + Clone> WidgetImpl for Dropdown<T> {
self.btn.set_pos(top_left);
}
fn event(&mut self, ctx: &mut EventCtx, redo_layout: &mut bool) -> Option<Outcome> {
fn event(&mut self, ctx: &mut EventCtx, output: &mut WidgetOutput) {
if let Some(ref mut m) = self.menu {
m.event(ctx, redo_layout);
m.event(ctx, output);
match m.state {
InputResult::StillActive => {}
InputResult::Canceled => {
@ -75,11 +75,12 @@ impl<T: 'static + Clone> WidgetImpl for Dropdown<T> {
self.blank_btn_label,
);
self.btn.set_pos(top_left);
*redo_layout = true;
output.redo_layout = true;
}
}
} else {
if self.btn.event(ctx, redo_layout).is_some() {
self.btn.event(ctx, output);
if output.outcome.take().is_some() {
// TODO set current idx in menu
let mut menu = Menu::new(
ctx,
@ -104,8 +105,6 @@ impl<T: 'static + Clone> WidgetImpl for Dropdown<T> {
self.menu = Some(menu);
}
}
None
}
fn draw(&self, g: &mut GfxCtx) {

View File

@ -1,4 +1,4 @@
use crate::{EventCtx, GfxCtx, Outcome, ScreenDims, ScreenPt, Widget, WidgetImpl};
use crate::{EventCtx, GfxCtx, ScreenDims, ScreenPt, Widget, WidgetImpl, WidgetOutput};
// Doesn't do anything by itself, just used for widgetsing. Something else reaches in, asks for the
// ScreenRectangle to use.
@ -25,8 +25,6 @@ impl WidgetImpl for Filler {
self.top_left = top_left;
}
fn event(&mut self, _ctx: &mut EventCtx, _redo_layout: &mut bool) -> Option<Outcome> {
None
}
fn event(&mut self, _ctx: &mut EventCtx, _output: &mut WidgetOutput) {}
fn draw(&self, _g: &mut GfxCtx) {}
}

View File

@ -1,6 +1,6 @@
use crate::{
Color, Drawable, EventCtx, GeomBatch, GfxCtx, Line, Outcome, ScreenDims, ScreenPt, Text,
TextExt, Widget, WidgetImpl,
Color, Drawable, EventCtx, GeomBatch, GfxCtx, Line, ScreenDims, ScreenPt, Text, TextExt,
Widget, WidgetImpl, WidgetOutput,
};
use abstutil::prettyprint_usize;
use geom::{Distance, Duration, Polygon, Pt2D};
@ -113,9 +113,7 @@ impl WidgetImpl for Histogram {
self.top_left = top_left;
}
fn event(&mut self, _ctx: &mut EventCtx, _redo_layout: &mut bool) -> Option<Outcome> {
None
}
fn event(&mut self, _ctx: &mut EventCtx, _output: &mut WidgetOutput) {}
fn draw(&self, g: &mut GfxCtx) {
g.redraw_at(self.top_left, &self.draw);

View File

@ -1,6 +1,6 @@
use crate::{
svg, Drawable, EventCtx, GeomBatch, GfxCtx, Outcome, RewriteColor, ScreenDims, ScreenPt,
Widget, WidgetImpl,
svg, Drawable, EventCtx, GeomBatch, GfxCtx, RewriteColor, ScreenDims, ScreenPt, Widget,
WidgetImpl, WidgetOutput,
};
// Just draw something. A widget just so widgetsing works.
@ -50,9 +50,7 @@ impl WidgetImpl for JustDraw {
self.top_left = top_left;
}
fn event(&mut self, _ctx: &mut EventCtx, _redo_layout: &mut bool) -> Option<Outcome> {
None
}
fn event(&mut self, _ctx: &mut EventCtx, _output: &mut WidgetOutput) {}
fn draw(&self, g: &mut GfxCtx) {
g.redraw_at(self.top_left, &self.draw);

View File

@ -1,6 +1,6 @@
use crate::{
hotkey, text, Choice, EventCtx, GfxCtx, InputResult, Key, Line, Outcome, ScreenDims, ScreenPt,
ScreenRectangle, Text, Widget, WidgetImpl,
hotkey, text, Choice, EventCtx, GfxCtx, InputResult, Key, Line, ScreenDims, ScreenPt,
ScreenRectangle, Text, Widget, WidgetImpl, WidgetOutput,
};
use geom::Pt2D;
@ -79,9 +79,9 @@ impl<T: 'static + Clone> WidgetImpl for Menu<T> {
self.top_left = top_left;
}
fn event(&mut self, ctx: &mut EventCtx, _redo_layout: &mut bool) -> Option<Outcome> {
fn event(&mut self, ctx: &mut EventCtx, _output: &mut WidgetOutput) {
if self.choices.is_empty() {
return None;
return;
}
match self.state {
@ -123,14 +123,14 @@ impl<T: 'static + Clone> WidgetImpl for Menu<T> {
if let Some(pt) = ctx.canvas.get_cursor_in_screen_space() {
if rect.contains(pt) && choice.active {
self.state = InputResult::Done(choice.label.clone(), choice.data.clone());
return None;
return;
}
// Unconsume the click, it was in screen space, but not on us.
ctx.input.unconsume_event();
} else {
// Clicked on the map? Cancel out
self.state = InputResult::Canceled;
return None;
return;
}
}
}
@ -143,7 +143,7 @@ impl<T: 'static + Clone> WidgetImpl for Menu<T> {
if let Some(ref hotkey) = choice.hotkey {
if ctx.input.new_was_pressed(hotkey) {
self.state = InputResult::Done(choice.label.clone(), choice.data.clone());
return None;
return;
}
}
}
@ -153,9 +153,9 @@ impl<T: 'static + Clone> WidgetImpl for Menu<T> {
let choice = &self.choices[self.current_idx];
if choice.active {
self.state = InputResult::Done(choice.label.clone(), choice.data.clone());
return None;
return;
} else {
return None;
return;
}
} else if ctx.input.new_was_pressed(&hotkey(Key::UpArrow).unwrap()) {
if self.current_idx > 0 {
@ -166,8 +166,6 @@ impl<T: 'static + Clone> WidgetImpl for Menu<T> {
self.current_idx += 1;
}
}
None
}
fn draw(&self, g: &mut GfxCtx) {

View File

@ -13,7 +13,7 @@ pub mod slider;
pub mod spinner;
pub mod text_box;
use crate::{EventCtx, GfxCtx, Outcome, ScreenDims, ScreenPt};
use crate::{EventCtx, GfxCtx, ScreenDims, ScreenPt};
/// Create a new widget by implementing this trait. You can instantiate your widget by calling
/// `Widget::new(Box::new(instance of your new widget))`, which gives you the usual style options.
@ -23,12 +23,31 @@ pub trait WidgetImpl: downcast_rs::Downcast {
fn get_dims(&self) -> ScreenDims;
/// Your widget's top left corner should be here. Handle mouse events and draw appropriately.
fn set_pos(&mut self, top_left: ScreenPt);
/// Your chance to react to an event. If this event should trigger layouting to be recalculated
/// (because this widget changes dimensions), set `redo_layout` to true. Most widgets should
/// return `None` instead of an `Outcome`.
fn event(&mut self, ctx: &mut EventCtx, redo_layout: &mut bool) -> Option<Outcome>;
/// Your chance to react to an event. Any side effects outside of this widget are communicated
/// through the output.
fn event(&mut self, ctx: &mut EventCtx, output: &mut WidgetOutput);
/// Draw the widget. Be sure to draw relative to the top-left specified by `set_pos`.
fn draw(&self, g: &mut GfxCtx);
/// Internal hack. Don't override.
fn update_series(&mut self, _label: String, _enabled: bool) {
unreachable!()
}
}
pub enum Outcome {
Clicked(String),
}
pub struct WidgetOutput {
/// This widget changed dimensions, so recalculate layout.
pub redo_layout: bool,
/// This widget produced an Outcome, and event handling should immediately stop. Most widgets
/// shouldn't set this.
pub outcome: Option<Outcome>,
/// Internal hack.
pub(crate) plot_changed: Vec<((String, String), bool)>,
}
downcast_rs::impl_downcast!(WidgetImpl);

View File

@ -1,6 +1,6 @@
use crate::{
Btn, Button, Choice, Color, Dropdown, EventCtx, GeomBatch, GfxCtx, JustDraw, MultiKey, Outcome,
ScreenDims, ScreenPt, Widget, WidgetImpl,
Btn, Button, Choice, Color, Dropdown, EventCtx, GeomBatch, GfxCtx, JustDraw, MultiKey,
ScreenDims, ScreenPt, Widget, WidgetImpl, WidgetOutput,
};
use geom::Polygon;
@ -67,12 +67,13 @@ impl<T: 'static + Clone + PartialEq> WidgetImpl for PersistentSplit<T> {
));
}
fn event(&mut self, ctx: &mut EventCtx, redo_layout: &mut bool) -> Option<Outcome> {
if let Some(o) = self.btn.event(ctx, redo_layout) {
return Some(o);
fn event(&mut self, ctx: &mut EventCtx, output: &mut WidgetOutput) {
self.btn.event(ctx, output);
if output.outcome.is_some() {
return;
}
self.dropdown.event(ctx, redo_layout);
self.dropdown.event(ctx, output);
let new_value = self.dropdown.current_value();
if new_value != self.current_value {
self.current_value = new_value;
@ -81,10 +82,8 @@ impl<T: 'static + Clone + PartialEq> WidgetImpl for PersistentSplit<T> {
self.btn = Btn::plaintext(self.dropdown.current_value_label())
.build(ctx, label, hotkey)
.take_btn();
*redo_layout = true;
output.redo_layout = true;
}
None
}
fn draw(&self, g: &mut GfxCtx) {

View File

@ -1,6 +1,6 @@
use crate::{
Checkbox, Color, Drawable, EventCtx, GeomBatch, GfxCtx, Line, Outcome, ScreenDims, ScreenPt,
ScreenRectangle, Text, TextExt, Widget, WidgetImpl,
Checkbox, Color, Drawable, EventCtx, GeomBatch, GfxCtx, Line, ScreenDims, ScreenPt,
ScreenRectangle, Text, TextExt, Widget, WidgetImpl, WidgetOutput,
};
use abstutil::prettyprint_usize;
use geom::{Angle, Bounds, Circle, Distance, Duration, FindClosest, PolyLine, Pt2D, Time};
@ -36,7 +36,8 @@ impl PlotOptions {
}
impl<T: Yvalue<T>> Plot<T> {
pub fn new(ctx: &EventCtx, series: Vec<Series<T>>, opts: PlotOptions) -> Widget {
// ID must be unique in a Composite
pub fn new(ctx: &EventCtx, id: &str, series: Vec<Series<T>>, opts: PlotOptions) -> Widget {
let legend = if series.len() == 1 {
let radius = 15.0;
// Can't hide if there's just one series
@ -58,7 +59,11 @@ impl<T: Yvalue<T>> Plot<T> {
.iter()
.map(|s| {
// TODO Colored checkbox
Checkbox::text(ctx, &s.label, None, true)
Widget::new(Box::new(
Checkbox::text(ctx, &s.label, None, true)
.take_checkbox()
.callback_to_plot(id, &s.label),
))
})
.collect(),
)
@ -220,7 +225,10 @@ impl<T: Yvalue<T>> Plot<T> {
// 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::new(Box::new(plot))]),
Widget::row(vec![
y_axis.evenly_spaced(),
Widget::new(Box::new(plot)).named(id),
]),
x_axis.evenly_spaced(),
])])
}
@ -235,9 +243,7 @@ impl<T: Yvalue<T>> WidgetImpl for Plot<T> {
self.top_left = top_left;
}
fn event(&mut self, _ctx: &mut EventCtx, _redo_layout: &mut bool) -> Option<Outcome> {
None
}
fn event(&mut self, _ctx: &mut EventCtx, _output: &mut WidgetOutput) {}
fn draw(&self, g: &mut GfxCtx) {
g.redraw_at(self.top_left, &self.draw_grid);
@ -278,6 +284,16 @@ impl<T: Yvalue<T>> WidgetImpl for Plot<T> {
}
}
}
fn update_series(&mut self, label: String, enabled: bool) {
for series in &mut self.series {
if series.label == label {
series.enabled = enabled;
return;
}
}
panic!("Plot doesn't have a series {}", label);
}
}
pub trait Yvalue<T>: 'static + Copy + std::cmp::Ord {

View File

@ -1,6 +1,6 @@
use crate::{
Color, Drawable, EventCtx, GeomBatch, GfxCtx, Outcome, ScreenDims, ScreenPt, ScreenRectangle,
Widget, WidgetImpl,
Color, Drawable, EventCtx, GeomBatch, GfxCtx, ScreenDims, ScreenPt, ScreenRectangle, Widget,
WidgetImpl, WidgetOutput,
};
use geom::Polygon;
@ -204,12 +204,10 @@ impl WidgetImpl for Slider {
self.top_left = top_left;
}
fn event(&mut self, ctx: &mut EventCtx, _redo_layout: &mut bool) -> Option<Outcome> {
fn event(&mut self, ctx: &mut EventCtx, _output: &mut WidgetOutput) {
if self.inner_event(ctx) {
self.recalc(ctx);
}
None
}
fn draw(&self, g: &mut GfxCtx) {

View File

@ -1,6 +1,6 @@
use crate::{
text, Btn, Button, EventCtx, GeomBatch, GfxCtx, Line, Outcome, ScreenDims, ScreenPt, Text,
Widget, WidgetImpl,
text, Btn, Button, EventCtx, GeomBatch, GfxCtx, Line, ScreenDims, ScreenPt, Text, Widget,
WidgetImpl, WidgetOutput,
};
use geom::{Polygon, Pt2D};
@ -67,18 +67,21 @@ impl WidgetImpl for Spinner {
));
}
fn event(&mut self, ctx: &mut EventCtx, redo_layout: &mut bool) -> Option<Outcome> {
if self.up.event(ctx, redo_layout).is_some() {
fn event(&mut self, ctx: &mut EventCtx, output: &mut WidgetOutput) {
self.up.event(ctx, output);
if output.outcome.take().is_some() {
if self.current != self.high {
self.current += 1;
}
} else if self.down.event(ctx, redo_layout).is_some() {
return;
}
self.down.event(ctx, output);
if output.outcome.take().is_some() {
if self.current != self.low {
self.current -= 1;
}
}
None
}
fn draw(&self, g: &mut GfxCtx) {

View File

@ -1,6 +1,6 @@
use crate::{
text, Color, EventCtx, GeomBatch, GfxCtx, Key, Line, Outcome, ScreenDims, ScreenPt,
ScreenRectangle, Text, WidgetImpl,
text, Color, EventCtx, GeomBatch, GfxCtx, Key, Line, ScreenDims, ScreenPt, ScreenRectangle,
Text, WidgetImpl, WidgetOutput,
};
use geom::Polygon;
@ -63,7 +63,7 @@ impl WidgetImpl for TextBox {
self.top_left = top_left;
}
fn event(&mut self, ctx: &mut EventCtx, _redo_layout: &mut bool) -> Option<Outcome> {
fn event(&mut self, ctx: &mut EventCtx, _output: &mut WidgetOutput) {
if ctx.redo_mouseover() {
if let Some(pt) = ctx.canvas.get_cursor_in_screen_space() {
self.hovering = ScreenRectangle::top_left(self.top_left, self.dims).contains(pt);
@ -80,7 +80,7 @@ impl WidgetImpl for TextBox {
}
if !self.has_focus && !self.autofocus {
return None;
return;
}
if let Some(key) = ctx.input.any_key_pressed() {
match key {
@ -108,8 +108,6 @@ impl WidgetImpl for TextBox {
}
};
}
None
}
fn draw(&self, g: &mut GfxCtx) {

View File

@ -137,7 +137,7 @@ fn delays_over_time(ctx: &mut EventCtx, app: &App, id: BusRouteID) -> Widget {
}
Widget::col(vec![
Line("Delays between stops").small_heading().draw(ctx),
Plot::new(ctx, series, PlotOptions::new()).margin(10),
Plot::new(ctx, "delay btwn stops", series, PlotOptions::new()).margin(10),
])
}

View File

@ -136,7 +136,7 @@ fn delay_plot(ctx: &EventCtx, app: &App, i: IntersectionID, opts: &DataOptions)
}
}
Plot::new(ctx, all_series, PlotOptions::new())
Plot::new(ctx, "delay", all_series, PlotOptions::new())
}
fn header(

View File

@ -472,7 +472,7 @@ fn throughput<F: Fn(&Analytics, Time) -> BTreeMap<TripMode, Vec<(Time, usize)>>>
}
}
Plot::new(ctx, series, PlotOptions::new())
Plot::new(ctx, "throughput", series, PlotOptions::new())
}
fn color_for_mode(m: TripMode, app: &App) -> Color {

View File

@ -353,6 +353,7 @@ fn make_elevation(ctx: &EventCtx, color: Color, walking: bool, path: &Path, map:
// TODO Show roughly where we are in the trip; use distance covered by current path for this
Plot::new(
ctx,
"elevation",
vec![Series {
label: if walking {
"Elevation for walking"

View File

@ -161,6 +161,7 @@ fn trips_summary_prebaked(ctx: &EventCtx, app: &App) -> Widget {
Line("Active agents").small_heading().draw(ctx),
Plot::new(
ctx,
"active agents",
vec![
Series {
label: "Baseline".to_string(),
@ -229,6 +230,7 @@ fn trips_summary_not_prebaked(ctx: &EventCtx, app: &App) -> Widget {
Line("Active agents").small_heading().draw(ctx),
Plot::new(
ctx,
"active agents",
vec![Series {
label: "Active agents".to_string(),
color: Color::RED,
@ -291,6 +293,7 @@ fn finished_trips_plot(ctx: &EventCtx, app: &App) -> Widget {
let plot = Plot::new(
ctx,
"finished trips",
lines
.into_iter()
.map(|(label, color, m)| Series {