diff --git a/examples/simple_flexbox.rs b/examples/simple_flexbox.rs index a738c5d..b8c320b 100644 --- a/examples/simple_flexbox.rs +++ b/examples/simple_flexbox.rs @@ -1,8 +1,8 @@ use cursive::{ theme::{BorderStyle, ColorStyle, Palette, Theme}, - view::IntoBoxedView, - views::{Layer, Panel, TextView}, - Cursive, CursiveExt, + view::{IntoBoxedView, Nameable, Resizable}, + views::{Button, EditView, Layer, Panel, TextArea, TextView}, + Cursive, CursiveExt, With, }; use cursive_flexbox::prelude::*; @@ -27,8 +27,12 @@ fn main() { )) .into_boxed_view(), Panel::new(Layer::with_color( - TextView::new("I doubt I will be wrapped..."), - ColorStyle::back(cursive::theme::BaseColor::Green.dark()), + EditView::new() + .with(|v| { + v.set_content("I doubt I will be wrapped..."); + }) + .min_width(28), + ColorStyle::back(cursive::theme::BaseColor::Blue.dark()), )) .into_boxed_view(), Panel::new(Layer::with_color( @@ -37,16 +41,29 @@ fn main() { )) .into_boxed_view(), Panel::new(Layer::with_color( - TextView::new( - "And a bigger container\nto test out the alignment\nof items in the main \ - axis\na bit better.", - ), - ColorStyle::back(cursive::theme::BaseColor::Green.dark()), + TextArea::new() + .with(|v| { + v.set_content( + "And a bigger container\nto test out the alignment\nof items in the main \ + axis\na bit better.\n\nEdit me.", + ); + }) + .min_width(20), + ColorStyle::back(cursive::theme::BaseColor::Blue.dark()), )) .into_boxed_view(), Panel::new(Layer::with_color( - TextView::new("And a final item for good luck."), - ColorStyle::back(cursive::theme::BaseColor::Green.dark()), + Button::new("And a final button for good luck.", |c| { + let mut flexbox = c.find_name::("flexbox").unwrap(); + let new_align = match flexbox.align_items() { + AlignItems::FlexStart => AlignItems::Center, + AlignItems::Center => AlignItems::FlexEnd, + AlignItems::FlexEnd => AlignItems::Stretch, + AlignItems::Stretch => AlignItems::FlexStart, + }; + flexbox.set_align_items(new_align); + }), + ColorStyle::back(cursive::theme::BaseColor::Red.dark()), )) .into_boxed_view(), ]); @@ -77,7 +94,7 @@ fn main() { flexbox.set_flex_direction(FlexDirection::Row); // Add the flexbox to the ui. - cursive.add_fullscreen_layer(flexbox); + cursive.add_fullscreen_layer(flexbox.with_name("flexbox")); // Start running the eventloop. cursive.run(); diff --git a/src/lib.rs b/src/lib.rs index cfead58..7b1fb39 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,12 @@ use std::{ rc::{Rc, Weak}, }; -use cursive_core::{event::EventResult, view::IntoBoxedView, Rect, Vec2, View, XY}; +use cursive_core::{ + direction::{Absolute, Direction, Relative}, + event::{Event, EventResult, Key}, + view::IntoBoxedView, + Rect, Vec2, View, XY, +}; use layout::{Layout, PlacedElement}; /// A container that can be used to display a list of items in a flexible way. @@ -940,16 +945,54 @@ impl Flexbox { }); result } + + /// Attempt to focus the given item from the given source. + fn try_focus(&mut self, child_index: usize, source: Direction) -> Option { + if let Some(view) = self.content.get(child_index) { + if let Ok(result) = view.borrow_mut().view.take_focus(source) { + self.focused = Some(child_index); + return Some(result); + } + } + None + } + + /// Handle relative focus cycle towards the front or back of the container. + fn move_focus_rel(&mut self, target: Relative) -> EventResult { + let adv = if target == Relative::Back { + -1 + } else { + 1 + }; + let child_count = self.content.len(); + let get_next = |n| (n as isize + adv).rem_euclid(child_count as isize) as usize; + let mut attempts = child_count - 1; + let mut next = if let Some(n) = self.focused { + get_next(n) + } else { + 0 + }; + while attempts > 0 { + if let Some(result) = self.try_focus(next, Direction::Rel(target)) { + return result; + } + next = get_next(next); + attempts -= 1; + } + EventResult::Ignored + } } impl View for Flexbox { /// Draw this view using the printer. fn draw(&self, printer: &cursive_core::Printer<'_, '_>) { if let Some(ref layout) = self.layout { - for placed_element in layout { - RefCell::borrow(&placed_element.element) - .view - .draw(&printer.windowed(placed_element.position)); + for (i, placed_element) in layout.iter().enumerate() { + RefCell::borrow(&placed_element.element).view.draw( + &printer + .windowed(placed_element.position) + .focused(Some(i) == self.focused), + ); } } } @@ -992,7 +1035,13 @@ impl View for Flexbox { &mut self, mut event: cursive_core::event::Event, ) -> cursive_core::event::EventResult { - if let cursive_core::event::Event::Mouse { + if let Some(result) = match event { + Event::Shift(Key::Tab) => Some(self.move_focus_rel(Relative::Back)), + Event::Key(Key::Tab) => Some(self.move_focus_rel(Relative::Front)), + _ => None, + } { + result + } else if let cursive_core::event::Event::Mouse { ref mut offset, ref mut position, .. @@ -1003,9 +1052,18 @@ impl View for Flexbox { layout.element_at(global_to_view_coordinates(*position, *offset)) { *offset = *offset + placed_element.position.top_left(); - RefCell::borrow_mut(&placed_element.element) - .view - .on_event(event) + if let Some(index) = self + .content + .iter() + .position(|v| v.as_ptr() == placed_element.element.as_ptr()) + { + self.try_focus(index, Direction::Abs(Absolute::None)); + self.content[index].borrow_mut().view.on_event(event) + } else { + RefCell::borrow_mut(&placed_element.element) + .view + .on_event(event) + } } else { EventResult::Ignored }