diff --git a/ezgui/src/managed.rs b/ezgui/src/managed.rs index 9f47124a97..763bb333c0 100644 --- a/ezgui/src/managed.rs +++ b/ezgui/src/managed.rs @@ -23,7 +23,6 @@ pub struct Widget { enum WidgetType { Btn(Button), - Dropdown(Dropdown), Slider(Slider), Row(Vec), Column(Vec), @@ -297,18 +296,18 @@ impl Widget { )))) } - pub fn dropdown( + pub fn dropdown( ctx: &EventCtx, label: &str, default_value: T, choices: Vec>, ) -> Widget { - Widget::new(WidgetType::Dropdown(Dropdown::new( + Widget::new(WidgetType::Generic(Box::new(Dropdown::new( ctx, label, default_value, choices, - ))) + )))) .named(label) .outline(2.0, Color::WHITE) } @@ -360,11 +359,6 @@ impl Widget { return Some(Outcome::Clicked(btn.action.clone())); } } - WidgetType::Dropdown(ref mut dropdown) => { - if dropdown.event(ctx, &self.rect) { - *redo_layout = true; - } - } WidgetType::Slider(ref mut slider) => { slider.event(ctx); } @@ -392,7 +386,6 @@ impl Widget { match self.widget { WidgetType::Btn(ref btn) => btn.draw(g), - WidgetType::Dropdown(ref dropdown) => dropdown.draw(g), WidgetType::Slider(ref slider) => { if self.id != Some("horiz scrollbar".to_string()) && self.id != Some("vert scrollbar".to_string()) @@ -414,7 +407,6 @@ impl Widget { fn get_flexbox(&self, parent: Node, stretch: &mut Stretch, nodes: &mut Vec) { let dims = match self.widget { WidgetType::Btn(ref widget) => widget.get_dims(), - WidgetType::Dropdown(ref widget) => widget.get_dims(), WidgetType::Slider(ref widget) => widget.get_dims(), WidgetType::Row(ref widgets) => { let mut style = Style { @@ -507,9 +499,6 @@ impl Widget { WidgetType::Btn(ref mut widget) => { widget.set_pos(top_left); } - WidgetType::Dropdown(ref mut widget) => { - widget.set_pos(top_left); - } WidgetType::Slider(ref mut widget) => { widget.set_pos(top_left); } @@ -549,7 +538,7 @@ impl Widget { fn get_all_click_actions(&self, actions: &mut HashSet) { match self.widget { - WidgetType::Slider(_) | WidgetType::Dropdown(_) => {} + WidgetType::Slider(_) => {} WidgetType::Btn(ref btn) => { if actions.contains(&btn.action) { panic!( @@ -915,15 +904,14 @@ impl Composite { } } - pub fn dropdown_value(&mut self, name: &str) -> T { - match self.find_mut(name).widget { - WidgetType::Dropdown(ref mut dropdown) => { - // Amusing little pattern here. - // TODO I think this entire hack goes away when WidgetImpl is just a trait. - let choice: Choice = dropdown.take_value(); - let value = choice.data.clone(); - dropdown.return_value(choice); - value + pub fn dropdown_value(&mut self, name: &str) -> T { + match self.find(name).widget { + WidgetType::Generic(ref w) => { + if let Some(dropdown) = w.downcast_ref::>() { + dropdown.current_value() + } else { + panic!("{} isn't a dropdown", name); + } } _ => panic!("{} isn't a dropdown", name), } diff --git a/ezgui/src/widgets/dropdown.rs b/ezgui/src/widgets/dropdown.rs index 6f0a0f3053..6402d424f3 100644 --- a/ezgui/src/widgets/dropdown.rs +++ b/ezgui/src/widgets/dropdown.rs @@ -1,26 +1,25 @@ use crate::{ - Btn, Button, Choice, Color, EventCtx, GfxCtx, InputResult, PopupMenu, ScreenDims, ScreenPt, - ScreenRectangle, WidgetImpl, + Btn, Button, Choice, Color, EventCtx, GfxCtx, InputResult, Outcome, PopupMenu, ScreenDims, + ScreenPt, ScreenRectangle, WidgetImpl, }; use geom::{Polygon, Pt2D}; -use std::any::Any; -pub struct Dropdown { +pub struct Dropdown { current_idx: usize, btn: Button, menu: Option>, label: String, - choices: Vec>>, + choices: Vec>, } -impl Dropdown { - pub fn new( +impl Dropdown { + pub fn new( ctx: &EventCtx, label: &str, default_value: T, choices: Vec>, - ) -> Dropdown { + ) -> Dropdown { let current_idx = choices .iter() .position(|c| c.data == default_value) @@ -31,30 +30,34 @@ impl Dropdown { btn: make_btn(ctx, &choices[current_idx].label, label), menu: None, label: label.to_string(), - - choices: choices - .into_iter() - .map(|c| { - // TODO Can't use with_value here :( - let data: Box = Box::new(c.data); - Choice { - label: c.label, - data, - hotkey: c.hotkey, - active: c.active, - tooltip: c.tooltip, - } - }) - .collect(), + choices, } } - // If true, widgets should be recomputed. - pub fn event(&mut self, ctx: &mut EventCtx, our_rect: &ScreenRectangle) -> bool { + pub fn current_value(&self) -> T { + self.choices[self.current_idx].data.clone() + } +} + +impl WidgetImpl for Dropdown { + fn get_dims(&self) -> ScreenDims { + self.btn.get_dims() + } + + fn set_pos(&mut self, top_left: ScreenPt) { + self.btn.set_pos(top_left); + } + + fn event( + &mut self, + ctx: &mut EventCtx, + rect: &ScreenRectangle, + redo_layout: &mut bool, + ) -> Option { if let Some(ref mut m) = self.menu { - // TODO wraaaaaaaaaaaawng - let mut redo_layout = false; - m.event(ctx, our_rect, &mut redo_layout); + // TODO Pass in the dropdown's rectangle, not the menu's. This is a lie! But the menu + // doesn't use it, so fine? + m.event(ctx, rect, redo_layout); match m.state { InputResult::StillActive => {} InputResult::Canceled => { @@ -68,7 +71,7 @@ impl Dropdown { // change self.btn = make_btn(ctx, &self.choices[self.current_idx].label, &self.label); self.btn.set_pos(top_left); - return true; + *redo_layout = true; } } } else { @@ -84,15 +87,15 @@ impl Dropdown { .map(|(idx, c)| c.with_value(idx)) .collect(), ); - menu.set_pos(ScreenPt::new(our_rect.x1, our_rect.y2 + 15.0)); + menu.set_pos(ScreenPt::new(rect.x1, rect.y2 + 15.0)); self.menu = Some(menu); } } - false + None } - pub fn draw(&self, g: &mut GfxCtx) { + fn draw(&self, g: &mut GfxCtx) { self.btn.draw(g); if let Some(ref m) = self.menu { // We need a background too! @@ -106,43 +109,6 @@ impl Dropdown { m.draw(g); } } - - // TODO This invalidates the entire widget! Have to call return_value - pub fn take_value(&mut self) -> Choice { - let c = self.choices.remove(self.current_idx); - let data: Box = c.data; - let boxed: Box = data.downcast().unwrap(); - Choice { - label: c.label, - data: *boxed, - hotkey: c.hotkey, - active: c.active, - tooltip: c.tooltip, - } - } - pub fn return_value(&mut self, c: Choice) { - let data: Box = Box::new(c.data); - self.choices.insert( - self.current_idx, - Choice { - label: c.label, - data, - hotkey: c.hotkey, - active: c.active, - tooltip: c.tooltip, - }, - ); - } -} - -impl WidgetImpl for Dropdown { - fn get_dims(&self) -> ScreenDims { - self.btn.get_dims() - } - - fn set_pos(&mut self, top_left: ScreenPt) { - self.btn.set_pos(top_left); - } } fn make_btn(ctx: &EventCtx, name: &str, label: &str) -> Button {