Add methods to access ListView's children

This commit is contained in:
Alexandre Bury 2017-05-21 09:50:16 -07:00
parent f608073bf5
commit d031d3784a
2 changed files with 50 additions and 21 deletions

View File

@ -13,22 +13,27 @@ use view::ScrollBase;
use view::Selector; use view::Selector;
use view::View; use view::View;
enum Child { /// Represents a child from a [`ListView`].
///
/// [`ListView`]: struct.ListView.html
pub enum ListChild {
/// A single row, with a label and a view.
Row(String, Box<View>), Row(String, Box<View>),
/// A delimiter between groups.
Delimiter, Delimiter,
} }
impl Child { impl ListChild {
fn label(&self) -> &str { fn label(&self) -> &str {
match *self { match *self {
Child::Row(ref label, _) => label, ListChild::Row(ref label, _) => label,
_ => "", _ => "",
} }
} }
fn view(&mut self) -> Option<&mut Box<View>> { fn view(&mut self) -> Option<&mut Box<View>> {
match *self { match *self {
Child::Row(_, ref mut view) => Some(view), ListChild::Row(_, ref mut view) => Some(view),
_ => None, _ => None,
} }
} }
@ -36,7 +41,7 @@ impl Child {
/// Displays a scrollable list of elements. /// Displays a scrollable list of elements.
pub struct ListView { pub struct ListView {
children: Vec<Child>, children: Vec<ListChild>,
scrollbase: ScrollBase, scrollbase: ScrollBase,
focus: usize, focus: usize,
// This callback is called when the selection is changed. // This callback is called when the selection is changed.
@ -56,10 +61,34 @@ impl ListView {
} }
} }
/// Returns the number of children, including delimiters.
pub fn len(&self) -> usize {
self.children.len()
}
/// Returns a reference to the children
pub fn children(&self) -> &[ListChild] {
&self.children[..]
}
/// Returns a reference to the child at the given position.
pub fn get_row(&self, id: usize) -> &ListChild {
&self.children[id]
}
/// Gives mutable access to the child at the given position.
///
/// # Panics
///
/// Panics if `id >= self.len()`.
pub fn row_mut(&mut self, id: usize) -> &mut ListChild {
&mut self.children[id]
}
/// Adds a view to the end of the list. /// Adds a view to the end of the list.
pub fn add_child<V: View + 'static>(&mut self, label: &str, mut view: V) { pub fn add_child<V: View + 'static>(&mut self, label: &str, mut view: V) {
view.take_focus(direction::Direction::none()); view.take_focus(direction::Direction::none());
self.children.push(Child::Row(label.to_string(), Box::new(view))); self.children.push(ListChild::Row(label.to_string(), Box::new(view)));
} }
/// Removes all children from this view. /// Removes all children from this view.
@ -77,7 +106,7 @@ impl ListView {
/// Adds a delimiter to the end of the list. /// Adds a delimiter to the end of the list.
pub fn add_delimiter(&mut self) { pub fn add_delimiter(&mut self) {
self.children.push(Child::Delimiter); self.children.push(ListChild::Delimiter);
} }
/// Adds a delimiter to the end of the list. /// Adds a delimiter to the end of the list.
@ -112,7 +141,7 @@ impl ListView {
fn iter_mut<'a>(&'a mut self, from_focus: bool, fn iter_mut<'a>(&'a mut self, from_focus: bool,
source: direction::Relative) source: direction::Relative)
-> Box<Iterator<Item = (usize, &mut Child)> + 'a> { -> Box<Iterator<Item = (usize, &mut ListChild)> + 'a> {
match source { match source {
direction::Relative::Front => { direction::Relative::Front => {
@ -162,11 +191,11 @@ impl ListView {
} }
} }
fn try_focus((i, child): (usize, &mut Child), source: direction::Direction) fn try_focus((i, child): (usize, &mut ListChild), source: direction::Direction)
-> Option<usize> { -> Option<usize> {
match *child { match *child {
Child::Delimiter => None, ListChild::Delimiter => None,
Child::Row(_, ref mut view) => { ListChild::Row(_, ref mut view) => {
if view.take_focus(source) { if view.take_focus(source) {
Some(i) Some(i)
} else { } else {
@ -185,18 +214,18 @@ impl View for ListView {
let offset = self.children let offset = self.children
.iter() .iter()
.map(Child::label) .map(ListChild::label)
.map(UnicodeWidthStr::width) .map(UnicodeWidthStr::width)
.max() .max()
.unwrap_or(0) + 1; .unwrap_or(0) + 1;
// println_stderr!("Offset: {}", offset); // println_stderr!("Offset: {}", offset);
self.scrollbase.draw(printer, |printer, i| match self.children[i] { self.scrollbase.draw(printer, |printer, i| match self.children[i] {
Child::Row(ref label, ref view) => { ListChild::Row(ref label, ref view) => {
printer.print((0, 0), label); printer.print((0, 0), label);
view.draw(&printer.offset((offset, 0), i == self.focus)); view.draw(&printer.offset((offset, 0), i == self.focus));
} }
Child::Delimiter => (), ListChild::Delimiter => (),
}); });
} }
@ -204,14 +233,14 @@ impl View for ListView {
// We'll show 2 columns: the labels, and the views. // We'll show 2 columns: the labels, and the views.
let label_width = self.children let label_width = self.children
.iter() .iter()
.map(Child::label) .map(ListChild::label)
.map(UnicodeWidthStr::width) .map(UnicodeWidthStr::width)
.max() .max()
.unwrap_or(0); .unwrap_or(0);
let view_size = self.children let view_size = self.children
.iter_mut() .iter_mut()
.filter_map(Child::view) .filter_map(ListChild::view)
.map(|v| v.required_size(req).x) .map(|v| v.required_size(req).x)
.max() .max()
.unwrap_or(0); .unwrap_or(0);
@ -229,7 +258,7 @@ impl View for ListView {
// We'll show 2 columns: the labels, and the views. // We'll show 2 columns: the labels, and the views.
let label_width = self.children let label_width = self.children
.iter() .iter()
.map(Child::label) .map(ListChild::label)
.map(UnicodeWidthStr::width) .map(UnicodeWidthStr::width)
.max() .max()
.unwrap_or(0); .unwrap_or(0);
@ -246,7 +275,7 @@ impl View for ListView {
// println_stderr!("Available: {}", available); // println_stderr!("Available: {}", available);
for child in self.children.iter_mut().filter_map(Child::view) { for child in self.children.iter_mut().filter_map(ListChild::view) {
child.layout(Vec2::new(available, 1)); child.layout(Vec2::new(available, 1));
} }
} }
@ -256,7 +285,7 @@ impl View for ListView {
return EventResult::Ignored; return EventResult::Ignored;
} }
if let Child::Row(_, ref mut view) = self.children[self.focus] { if let ListChild::Row(_, ref mut view) = self.children[self.focus] {
let result = view.on_event(event.clone()); let result = view.on_event(event.clone());
if result.is_consumed() { if result.is_consumed() {
return result; return result;
@ -317,7 +346,7 @@ impl View for ListView {
mut callback: Box<FnMut(&mut Any) + 'a>) { mut callback: Box<FnMut(&mut Any) + 'a>) {
for view in self.children for view in self.children
.iter_mut() .iter_mut()
.filter_map(Child::view) { .filter_map(ListChild::view) {
view.call_on_any(selector, Box::new(|any| callback(any))); view.call_on_any(selector, Box::new(|any| callback(any)));
} }
} }

View File

@ -72,7 +72,7 @@ pub use self::id_view::{IdView, ViewRef};
pub use self::key_event_view::KeyEventView; pub use self::key_event_view::KeyEventView;
pub use self::layer::Layer; pub use self::layer::Layer;
pub use self::linear_layout::LinearLayout; pub use self::linear_layout::LinearLayout;
pub use self::list_view::ListView; pub use self::list_view::{ListChild, ListView};
pub use self::menu_popup::MenuPopup; pub use self::menu_popup::MenuPopup;
pub use self::menubar::Menubar; pub use self::menubar::Menubar;
pub use self::panel::Panel; pub use self::panel::Panel;