diff --git a/termwiz/src/widgets/mod.rs b/termwiz/src/widgets/mod.rs index fe91dcd19..d4b178457 100644 --- a/termwiz/src/widgets/mod.rs +++ b/termwiz/src/widgets/mod.rs @@ -53,16 +53,16 @@ pub struct UpdateArgs<'a> { /// Implementing the `Widget` trait allows for defining a potentially /// interactive component in a UI layout. -pub trait Widget { +pub trait Widget { /// Draw the widget to the RenderArgs::surface, and optionally /// update RenderArgs::cursor to reflect the cursor position and /// display attributes. - fn render(&mut self, args: &mut RenderArgs); + fn render(&mut self, args: &mut RenderArgs, state: &mut State); /// Override this to have your widget specify its layout constraints. /// You may wish to have your widget constructor receive a `Constraints` /// instance to make this more easily configurable in more generic widgets. - fn get_size_constraints(&self) -> layout::Constraints { + fn get_size_constraints(&self, _state: &State) -> layout::Constraints { Default::default() } @@ -70,7 +70,12 @@ pub trait Widget { /// other widget events. /// Return `true` if your widget handled the event, or `false` to allow /// the event to propagate to the widget parent. - fn process_event(&mut self, _event: &WidgetEvent, _args: &mut UpdateArgs) -> bool { + fn process_event( + &mut self, + _event: &WidgetEvent, + _args: &mut UpdateArgs, + _state: &mut State, + ) -> bool { false } } @@ -137,11 +142,11 @@ impl Default for WidgetId { } } -struct RenderData<'widget> { +struct RenderData<'widget, State> { surface: Surface, cursor: CursorShapeAndPosition, coordinates: ParentRelativeCoords, - widget: Box, + widget: Box + 'widget>, } #[derive(Default)] @@ -178,20 +183,26 @@ impl Graph { } /// Manages the widgets on the display -#[derive(Default)] -pub struct Ui<'widget> { +pub struct Ui<'widget, State> { graph: Graph, - render: FnvHashMap>, + render: FnvHashMap>, input_queue: VecDeque, focused: Option, + state: State, } -impl<'widget> Ui<'widget> { - pub fn new() -> Self { - Default::default() +impl<'widget, State> Ui<'widget, State> { + pub fn new(state: State) -> Self { + Self { + graph: Default::default(), + render: Default::default(), + input_queue: Default::default(), + focused: Default::default(), + state, + } } - pub fn add(&mut self, parent: Option, w: W) -> WidgetId { + pub fn add + 'widget>(&mut self, parent: Option, w: W) -> WidgetId { let id = self.graph.add(parent); self.render.insert( @@ -211,11 +222,11 @@ impl<'widget> Ui<'widget> { id } - pub fn set_root(&mut self, w: W) -> WidgetId { + pub fn set_root + 'widget>(&mut self, w: W) -> WidgetId { self.add(None, w) } - pub fn add_child(&mut self, parent: WidgetId, w: W) -> WidgetId { + pub fn add_child + 'widget>(&mut self, parent: WidgetId, w: W) -> WidgetId { self.add(Some(parent), w) } @@ -226,7 +237,9 @@ impl<'widget> Ui<'widget> { cursor: &mut render_data.cursor, }; - render_data.widget.process_event(event, &mut args) + render_data + .widget + .process_event(event, &mut args, &mut self.state) } fn deliver_event(&mut self, mut id: WidgetId, event: &WidgetEvent) { @@ -368,7 +381,7 @@ impl<'widget> Ui<'widget> { surface, is_focused: self.focused.map(|f| f == id).unwrap_or(false), }; - render_data.widget.render(&mut args); + render_data.widget.render(&mut args, &mut self.state); } screen.draw_from_screen( surface, @@ -425,7 +438,9 @@ impl<'widget> Ui<'widget> { layout: &mut layout::LayoutState, widget: WidgetId, ) -> Result<()> { - let constraints = self.render[&widget].widget.get_size_constraints(); + let constraints = self.render[&widget] + .widget + .get_size_constraints(&self.state); let children = self.graph.children(widget).to_vec(); layout.add_widget(widget, &constraints, &children); @@ -520,15 +535,15 @@ mod test { struct CursorHider {} - impl Widget for CursorHider { - fn render(&mut self, args: &mut RenderArgs) { + impl Widget<()> for CursorHider { + fn render(&mut self, args: &mut RenderArgs, _state: &mut ()) { args.cursor.visibility = CursorVisibility::Hidden; } } #[test] fn hide_cursor() { - let mut ui = Ui::new(); + let mut ui = Ui::new(()); ui.set_root(CursorHider {});