Add AnyCb type alias

This commit is contained in:
Alexandre Bury 2018-04-16 22:39:16 -07:00
parent 8c00b171c0
commit 39babacbf5
9 changed files with 148 additions and 113 deletions

View File

@ -17,6 +17,7 @@ use Cursive;
use std::ops::Deref; use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
use vec::Vec2; use vec::Vec2;
use std::any::Any;
/// Callback is a function that can be triggered by an event. /// Callback is a function that can be triggered by an event.
/// It has a mutable access to the cursive root. /// It has a mutable access to the cursive root.
@ -24,6 +25,9 @@ use vec::Vec2;
pub struct Callback(Rc<Box<Fn(&mut Cursive)>>); pub struct Callback(Rc<Box<Fn(&mut Cursive)>>);
// TODO: remove the Box when Box<T: Sized> -> Rc<T> is possible // TODO: remove the Box when Box<T: Sized> -> Rc<T> is possible
/// A boxed callback that can be run on `&mut Any`.
pub type AnyCb<'a> = Box<FnMut(&mut Any) + 'a>;
impl Callback { impl Callback {
/// Wraps the given function into a `Callback` object. /// Wraps the given function into a `Callback` object.
pub fn from_fn<F>(f: F) -> Self pub fn from_fn<F>(f: F) -> Self
@ -343,6 +347,17 @@ impl Event {
} }
} }
/// Returns a mutable reference to the position of the mouse/
///
/// Returns `None` if `self` is not a mouse event.
pub fn mouse_position_mut(&mut self) -> Option<&mut Vec2> {
if let Event::Mouse { ref mut position, .. } = *self {
Some(position)
} else {
None
}
}
/// Update `self` with the given offset. /// Update `self` with the given offset.
/// ///
/// If `self` is a mouse event, adds `top_left` to its offset. /// If `self` is a mouse event, adds `top_left` to its offset.

View File

@ -1,6 +1,6 @@
use Printer; use Printer;
use direction::Direction; use direction::Direction;
use event::{Event, EventResult}; use event::{AnyCb, Event, EventResult};
use rect::Rect; use rect::Rect;
use std::any::Any; use std::any::Any;
use vec::Vec2; use vec::Vec2;
@ -73,7 +73,7 @@ pub trait View: Any + AnyView {
/// If the selector doesn't find a match, the closure will not be run. /// If the selector doesn't find a match, the closure will not be run.
/// ///
/// Default implementation is a no-op. /// Default implementation is a no-op.
fn call_on_any<'a>(&mut self, _: &Selector, _: Box<FnMut(&mut Any) + 'a>) { fn call_on_any<'a>(&mut self, _: &Selector, _: AnyCb<'a>) {
// TODO: FnMut -> FnOnce once it works // TODO: FnMut -> FnOnce once it works
} }

View File

@ -1,6 +1,6 @@
use Printer; use Printer;
use direction::Direction; use direction::Direction;
use event::{Event, EventResult}; use event::{AnyCb, Event, EventResult};
use rect::Rect; use rect::Rect;
use std::any::Any; use std::any::Any;
use vec::Vec2; use vec::Vec2;
@ -79,7 +79,7 @@ pub trait ViewWrapper: 'static {
/// Wraps the `find` method. /// Wraps the `find` method.
fn wrap_call_on_any<'a>( fn wrap_call_on_any<'a>(
&mut self, selector: &Selector, callback: Box<FnMut(&mut Any) + 'a> &mut self, selector: &Selector, callback: AnyCb<'a>
) { ) {
self.with_view_mut(|v| v.call_on_any(selector, callback)); self.with_view_mut(|v| v.call_on_any(selector, callback));
} }
@ -92,8 +92,7 @@ pub trait ViewWrapper: 'static {
/// Wraps the `needs_relayout` method. /// Wraps the `needs_relayout` method.
fn wrap_needs_relayout(&self) -> bool { fn wrap_needs_relayout(&self) -> bool {
self.with_view(|v| v.needs_relayout()) self.with_view(|v| v.needs_relayout()).unwrap_or(true)
.unwrap_or(true)
} }
/// Wraps the `important_area` method. /// Wraps the `important_area` method.

View File

@ -1,9 +1,10 @@
use Printer; use Printer;
use With; use With;
use direction::Direction; use direction::Direction;
use event::{Event, EventResult}; use event::{AnyCb, Event, EventResult};
use rect::Rect;
use vec::Vec2; use vec::Vec2;
use view::View; use view::{Selector, View};
/// A blank view that forwards calls to closures. /// A blank view that forwards calls to closures.
/// ///
@ -17,6 +18,9 @@ pub struct Canvas<T> {
layout: Box<FnMut(&mut T, Vec2)>, layout: Box<FnMut(&mut T, Vec2)>,
take_focus: Box<FnMut(&mut T, Direction) -> bool>, take_focus: Box<FnMut(&mut T, Direction) -> bool>,
needs_relayout: Box<Fn(&T) -> bool>, needs_relayout: Box<Fn(&T) -> bool>,
focus_view: Box<FnMut(&mut T, &Selector) -> Result<(), ()>>,
call_on_any: Box<for<'a> FnMut(&mut T, &Selector, AnyCb<'a>)>,
important_area: Box<Fn(&T, Vec2) -> Rect>,
} }
impl<T: 'static + View> Canvas<T> { impl<T: 'static + View> Canvas<T> {
@ -31,6 +35,9 @@ impl<T: 'static + View> Canvas<T> {
.with_layout(T::layout) .with_layout(T::layout)
.with_take_focus(T::take_focus) .with_take_focus(T::take_focus)
.with_needs_relayout(T::needs_relayout) .with_needs_relayout(T::needs_relayout)
.with_focus_view(T::focus_view)
.with_call_on_any(T::call_on_any)
.with_important_area(T::important_area)
} }
} }
@ -55,6 +62,11 @@ impl<T> Canvas<T> {
layout: Box::new(|_, _| ()), layout: Box::new(|_, _| ()),
take_focus: Box::new(|_, _| false), take_focus: Box::new(|_, _| false),
needs_relayout: Box::new(|_| true), needs_relayout: Box::new(|_| true),
focus_view: Box::new(|_, _| Err(())),
call_on_any: Box::new(|_, _, _| ()),
important_area: Box::new(|_, size| {
Rect::from_corners((0, 0), size)
}),
} }
} }
@ -170,6 +182,60 @@ impl<T> Canvas<T> {
{ {
self.with(|s| s.set_needs_relayout(f)) self.with(|s| s.set_needs_relayout(f))
} }
/// Sets the closure for `call_on_any()`.
pub fn set_call_on_any<F>(&mut self, f: F)
where
F: 'static + for<'a> FnMut(&mut T, &Selector, AnyCb<'a>),
{
self.call_on_any = Box::new(f);
}
/// Sets the closure for `call_on_any()`.
///
/// Chainable variant.
pub fn with_call_on_any<F>(self, f: F) -> Self
where
F: 'static + for<'a> FnMut(&mut T, &Selector, AnyCb<'a>),
{
self.with(|s| s.set_call_on_any(f))
}
/// Sets the closure for `important_area()`.
pub fn set_important_area<F>(&mut self, f: F)
where
F: 'static + Fn(&T, Vec2) -> Rect,
{
self.important_area = Box::new(f);
}
/// Sets the closure for `important_area()`.
///
/// Chainable variant.
pub fn with_important_area<F>(self, f: F) -> Self
where
F: 'static + Fn(&T, Vec2) -> Rect,
{
self.with(|s| s.set_important_area(f))
}
/// Sets the closure for `focus_view()`.
pub fn set_focus_view<F>(&mut self, f: F)
where
F: 'static + FnMut(&mut T, &Selector) -> Result<(), ()>,
{
self.focus_view = Box::new(f);
}
/// Sets the closure for `focus_view()`.
///
/// Chainable variant.
pub fn with_focus_view<F>(self, f: F) -> Self
where
F: 'static + FnMut(&mut T, &Selector) -> Result<(), ()>,
{
self.with(|s| s.set_focus_view(f))
}
} }
impl<T: 'static> View for Canvas<T> { impl<T: 'static> View for Canvas<T> {
@ -192,4 +258,20 @@ impl<T: 'static> View for Canvas<T> {
fn take_focus(&mut self, source: Direction) -> bool { fn take_focus(&mut self, source: Direction) -> bool {
(self.take_focus)(&mut self.state, source) (self.take_focus)(&mut self.state, source)
} }
fn needs_relayout(&self) -> bool {
(self.needs_relayout)(&self.state)
}
fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
(self.focus_view)(&mut self.state, selector)
}
fn important_area(&self, view_size: Vec2) -> Rect {
(self.important_area)(&self.state, view_size)
}
fn call_on_any<'a>(&mut self, selector: &Selector, cb: AnyCb<'a>) {
(self.call_on_any)(&mut self.state, selector, cb);
}
} }

View File

@ -3,9 +3,8 @@ use Printer;
use With; use With;
use align::*; use align::*;
use direction::Direction; use direction::Direction;
use event::*; use event::{AnyCb, Event, EventResult, Key};
use rect::Rect; use rect::Rect;
use std::any::Any;
use std::cell::Cell; use std::cell::Cell;
use std::cmp::max; use std::cmp::max;
use theme::ColorStyle; use theme::ColorStyle;
@ -249,11 +248,7 @@ impl Dialog {
pub fn buttons_mut<'a>( pub fn buttons_mut<'a>(
&'a mut self &'a mut self
) -> Box<'a + Iterator<Item = &'a mut Button>> { ) -> Box<'a + Iterator<Item = &'a mut Button>> {
Box::new( Box::new(self.buttons.iter_mut().map(|b| &mut b.button.view))
self.buttons
.iter_mut()
.map(|b| &mut b.button.view),
)
} }
/// Returns currently focused element /// Returns currently focused element
@ -566,9 +561,7 @@ impl View for Dialog {
} }
} }
fn call_on_any<'a>( fn call_on_any<'a>(&mut self, selector: &Selector, callback: AnyCb<'a>) {
&mut self, selector: &Selector, callback: Box<FnMut(&mut Any) + 'a>
) {
self.content.call_on_any(selector, callback); self.content.call_on_any(selector, callback);
} }

View File

@ -2,9 +2,8 @@ use Printer;
use With; use With;
use XY; use XY;
use direction; use direction;
use event::{Event, EventResult, Key}; use event::{AnyCb, Event, EventResult, Key};
use rect::Rect; use rect::Rect;
use std::any::Any;
use std::cmp::min; use std::cmp::min;
use std::ops::Deref; use std::ops::Deref;
use vec::Vec2; use vec::Vec2;
@ -81,10 +80,8 @@ impl<'a, T: Deref<Target = Child>, I: Iterator<Item = T>> Iterator
// eprintln!("Available: {}", self.available); // eprintln!("Available: {}", self.available);
let length = min( let length =
self.available, min(self.available, *child.size.get(self.orientation));
*child.size.get(self.orientation),
);
// Allocated width // Allocated width
self.available = self.available.saturating_sub(length); self.available = self.available.saturating_sub(length);
@ -175,9 +172,7 @@ impl LinearLayout {
/// Returns a mutable reference to a child. /// Returns a mutable reference to a child.
pub fn get_child_mut(&mut self, i: usize) -> Option<&mut View> { pub fn get_child_mut(&mut self, i: usize) -> Option<&mut View> {
self.children self.children.get_mut(i).map(|child| &mut *child.view)
.get_mut(i)
.map(|child| &mut *child.view)
} }
// If the cache can be used, return the cached size. // If the cache can be used, return the cached size.
@ -226,27 +221,21 @@ impl LinearLayout {
} else { } else {
self.children.len() self.children.len()
}; };
Box::new( Box::new(self.children[..end].iter_mut().enumerate().rev())
self.children[..end]
.iter_mut()
.enumerate()
.rev(),
)
} }
} }
} }
fn move_focus(&mut self, source: direction::Direction) -> EventResult { fn move_focus(&mut self, source: direction::Direction) -> EventResult {
let i = if let Some(i) = source.relative(self.orientation).and_then( let i = if let Some(i) =
|rel| { source.relative(self.orientation).and_then(|rel| {
// The iterator starts at the focused element. // The iterator starts at the focused element.
// We don't want that one. // We don't want that one.
self.iter_mut(true, rel) self.iter_mut(true, rel)
.skip(1) .skip(1)
.filter_map(|p| try_focus(p, source)) .filter_map(|p| try_focus(p, source))
.next() .next()
}, }) {
) {
i i
} else { } else {
return EventResult::Ignored; return EventResult::Ignored;
@ -291,9 +280,7 @@ impl LinearLayout {
let child_size = item.child.size.get(self.orientation); let child_size = item.child.size.get(self.orientation);
if (item.offset + child_size > position) if (item.offset + child_size > position)
&& item.child && item.child.view.take_focus(direction::Direction::none())
.view
.take_focus(direction::Direction::none())
{ {
// eprintln!("It's a match!"); // eprintln!("It's a match!");
self.focus = i; self.focus = i;
@ -359,9 +346,7 @@ impl View for LinearLayout {
// Every item has the same size orthogonal to the layout // Every item has the same size orthogonal to the layout
item.child.size.set_axis_from(o.swap(), &size); item.child.size.set_axis_from(o.swap(), &size);
item.child item.child.view.layout(size.with_axis(o, item.length));
.view
.layout(size.with_axis(o, item.length));
} }
} }
@ -438,11 +423,7 @@ impl View for LinearLayout {
let mut overweight: Vec<(usize, usize)> = ideal_sizes let mut overweight: Vec<(usize, usize)> = ideal_sizes
.iter() .iter()
.map(|v| self.orientation.get(v)) .map(|v| self.orientation.get(v))
.zip( .zip(min_sizes.iter().map(|v| self.orientation.get(v)))
min_sizes
.iter()
.map(|v| self.orientation.get(v)),
)
.map(|(a, b)| a.saturating_sub(b)) .map(|(a, b)| a.saturating_sub(b))
.enumerate() .enumerate()
.collect(); .collect();
@ -529,9 +510,7 @@ impl View for LinearLayout {
); );
let item = iterator.nth(self.focus).unwrap(); let item = iterator.nth(self.focus).unwrap();
let offset = self.orientation.make_vec(item.offset, 0); let offset = self.orientation.make_vec(item.offset, 0);
item.child item.child.view.on_event(event.relativized(offset))
.view
.on_event(event.relativized(offset))
}; };
match result { match result {
EventResult::Ignored => match event { EventResult::Ignored => match event {
@ -574,8 +553,7 @@ impl View for LinearLayout {
} }
fn call_on_any<'a>( fn call_on_any<'a>(
&mut self, selector: &Selector, &mut self, selector: &Selector, mut callback: AnyCb<'a>
mut callback: Box<FnMut(&mut Any) + 'a>,
) { ) {
for child in &mut self.children { for child in &mut self.children {
child child

View File

@ -2,9 +2,8 @@ use Cursive;
use Printer; use Printer;
use With; use With;
use direction; use direction;
use event::{Callback, Event, EventResult, Key, MouseButton, MouseEvent}; use event::{AnyCb, Callback, Event, EventResult, Key, MouseButton, MouseEvent};
use rect::Rect; use rect::Rect;
use std::any::Any;
use std::rc::Rc; use std::rc::Rc;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
use vec::Vec2; use vec::Vec2;
@ -94,10 +93,8 @@ impl ListView {
/// 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(ListChild::Row( self.children
label.to_string(), .push(ListChild::Row(label.to_string(), Box::new(view)));
Box::new(view),
));
} }
/// Removes all children from this view. /// Removes all children from this view.
@ -169,12 +166,7 @@ impl ListView {
} else { } else {
self.children.len() self.children.len()
}; };
Box::new( Box::new(self.children[..end].iter_mut().enumerate().rev())
self.children[..end]
.iter_mut()
.enumerate()
.rev(),
)
} }
} }
} }
@ -313,8 +305,7 @@ impl View for ListView {
fn layout(&mut self, size: Vec2) { fn layout(&mut self, size: Vec2) {
self.last_size = size; self.last_size = size;
self.scrollbase self.scrollbase.set_heights(size.y, self.children.len());
.set_heights(size.y, self.children.len());
// 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
@ -325,21 +316,14 @@ impl View for ListView {
.unwrap_or(0); .unwrap_or(0);
let spacing = 1; let spacing = 1;
let scrollbar_width = if self.children.len() > size.y { let scrollbar_width = if self.children.len() > size.y { 2 } else { 0 };
2
} else {
0
};
let available = size.x let available = size.x
.saturating_sub(label_width + spacing + scrollbar_width); .saturating_sub(label_width + spacing + scrollbar_width);
debug!("Available: {}", available); debug!("Available: {}", available);
for child in self.children for child in self.children.iter_mut().filter_map(ListChild::view) {
.iter_mut()
.filter_map(ListChild::view)
{
child.layout(Vec2::new(available, 1)); child.layout(Vec2::new(available, 1));
} }
} }
@ -358,8 +342,7 @@ impl View for ListView {
} if position } if position
.checked_sub(offset) .checked_sub(offset)
.map(|position| { .map(|position| {
self.scrollbase self.scrollbase.start_drag(position, self.last_size.x)
.start_drag(position, self.last_size.x)
}) })
.unwrap_or(false) => .unwrap_or(false) =>
{ {
@ -394,8 +377,7 @@ impl View for ListView {
if let ListChild::Row(_, ref mut view) = self.children[self.focus] { if let ListChild::Row(_, ref mut view) = self.children[self.focus] {
// If self.focus < self.scrollbase.start_line, it means the focus is not // If self.focus < self.scrollbase.start_line, it means the focus is not
// in view. Something's fishy, so don't send the event. // in view. Something's fishy, so don't send the event.
if let Some(y) = self.focus if let Some(y) = self.focus.checked_sub(self.scrollbase.start_line)
.checked_sub(self.scrollbase.start_line)
{ {
let offset = (labels_width + 1, y); let offset = (labels_width + 1, y);
let result = view.on_event(event.relativized(offset)); let result = view.on_event(event.relativized(offset));
@ -419,10 +401,12 @@ impl View for ListView {
Event::Key(Key::PageDown) => { Event::Key(Key::PageDown) => {
self.move_focus(10, direction::Direction::up()) self.move_focus(10, direction::Direction::up())
} }
Event::Key(Key::Home) | Event::Ctrl(Key::Home) => self.move_focus( Event::Key(Key::Home) | Event::Ctrl(Key::Home) => {
self.move_focus(
usize::max_value(), usize::max_value(),
direction::Direction::back(), direction::Direction::back(),
), )
}
Event::Key(Key::End) | Event::Ctrl(Key::End) => self.move_focus( Event::Key(Key::End) | Event::Ctrl(Key::End) => self.move_focus(
usize::max_value(), usize::max_value(),
direction::Direction::front(), direction::Direction::front(),
@ -472,13 +456,9 @@ impl View for ListView {
} }
fn call_on_any<'a>( fn call_on_any<'a>(
&mut self, selector: &Selector, &mut self, selector: &Selector, mut callback: AnyCb<'a>
mut callback: Box<FnMut(&mut Any) + 'a>,
) { ) {
for view in self.children for view in self.children.iter_mut().filter_map(ListChild::view) {
.iter_mut()
.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

@ -3,14 +3,15 @@ use view::View;
use view::ViewWrapper; use view::ViewWrapper;
/// Wrapper around a view that remembers its size. /// Wrapper around a view that remembers its size.
pub struct SizedView<T: View> { pub struct SizedView<T> {
/// Wrapped view. /// Wrapped view.
pub view: T, pub view: T,
/// Cached size from the last layout() call. /// Cached size from the last layout() call.
pub size: Vec2, pub size: Vec2,
} }
impl<T: View> SizedView<T> { impl<T> SizedView<T> {
/// Wraps the given view. /// Wraps the given view.
pub fn new(view: T) -> Self { pub fn new(view: T) -> Self {
SizedView { SizedView {

View File

@ -1,8 +1,7 @@
use Printer; use Printer;
use With; use With;
use direction::Direction; use direction::Direction;
use event::{Event, EventResult}; use event::{AnyCb, Event, EventResult};
use std::any::Any;
use std::cell; use std::cell;
use std::ops::Deref; use std::ops::Deref;
use theme::ColorStyle; use theme::ColorStyle;
@ -65,13 +64,9 @@ impl<T: View> ChildWrapper<T> {
fn unwrap(self) -> T { fn unwrap(self) -> T {
match self { match self {
// ShadowView::into_inner and Layer::into_inner can never fail. // ShadowView::into_inner and Layer::into_inner can never fail.
ChildWrapper::Shadow(shadow) => shadow ChildWrapper::Shadow(shadow) => {
.into_inner() shadow.into_inner().ok().unwrap().into_inner().ok().unwrap()
.ok() }
.unwrap()
.into_inner()
.ok()
.unwrap(),
ChildWrapper::Plain(layer) => layer.into_inner().ok().unwrap(), ChildWrapper::Plain(layer) => layer.into_inner().ok().unwrap(),
} }
} }
@ -134,9 +129,7 @@ impl<T: View> View for ChildWrapper<T> {
} }
} }
fn call_on_any<'a>( fn call_on_any<'a>(&mut self, selector: &Selector, callback: AnyCb<'a>) {
&mut self, selector: &Selector, callback: Box<FnMut(&mut Any) + 'a>
) {
match *self { match *self {
ChildWrapper::Shadow(ref mut v) => { ChildWrapper::Shadow(ref mut v) => {
v.call_on_any(selector, callback) v.call_on_any(selector, callback)
@ -216,9 +209,7 @@ impl StackView {
/// Returns a reference to the layer at the given position. /// Returns a reference to the layer at the given position.
pub fn get(&self, pos: LayerPosition) -> Option<&View> { pub fn get(&self, pos: LayerPosition) -> Option<&View> {
let i = self.get_index(pos); let i = self.get_index(pos);
self.layers self.layers.get(i).map(|child| child.view.get_inner())
.get(i)
.map(|child| child.view.get_inner())
} }
/// Returns a mutable reference to the layer at the given position. /// Returns a mutable reference to the layer at the given position.
@ -331,10 +322,7 @@ impl StackView {
/// Returns the size for each layer in this view. /// Returns the size for each layer in this view.
pub fn layer_sizes(&self) -> Vec<Vec2> { pub fn layer_sizes(&self) -> Vec<Vec2> {
self.layers self.layers.iter().map(|layer| layer.size).collect()
.iter()
.map(|layer| layer.size)
.collect()
} }
fn get_index(&self, pos: LayerPosition) -> usize { fn get_index(&self, pos: LayerPosition) -> usize {
@ -535,8 +523,7 @@ impl View for StackView {
} }
fn call_on_any<'a>( fn call_on_any<'a>(
&mut self, selector: &Selector, &mut self, selector: &Selector, mut callback: AnyCb<'a>
mut callback: Box<FnMut(&mut Any) + 'a>,
) { ) {
for layer in &mut self.layers { for layer in &mut self.layers {
layer layer