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::rc::Rc;
use vec::Vec2;
use std::any::Any;
/// Callback is a function that can be triggered by an event.
/// It has a mutable access to the cursive root.
@ -24,6 +25,9 @@ use vec::Vec2;
pub struct Callback(Rc<Box<Fn(&mut Cursive)>>);
// 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 {
/// Wraps the given function into a `Callback` object.
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.
///
/// If `self` is a mouse event, adds `top_left` to its offset.

View File

@ -1,6 +1,6 @@
use Printer;
use direction::Direction;
use event::{Event, EventResult};
use event::{AnyCb, Event, EventResult};
use rect::Rect;
use std::any::Any;
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.
///
/// 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
}

View File

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

View File

@ -1,9 +1,10 @@
use Printer;
use With;
use direction::Direction;
use event::{Event, EventResult};
use event::{AnyCb, Event, EventResult};
use rect::Rect;
use vec::Vec2;
use view::View;
use view::{Selector, View};
/// A blank view that forwards calls to closures.
///
@ -17,6 +18,9 @@ pub struct Canvas<T> {
layout: Box<FnMut(&mut T, Vec2)>,
take_focus: Box<FnMut(&mut T, Direction) -> 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> {
@ -31,6 +35,9 @@ impl<T: 'static + View> Canvas<T> {
.with_layout(T::layout)
.with_take_focus(T::take_focus)
.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(|_, _| ()),
take_focus: Box::new(|_, _| false),
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))
}
/// 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> {
@ -192,4 +258,20 @@ impl<T: 'static> View for Canvas<T> {
fn take_focus(&mut self, source: Direction) -> bool {
(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 align::*;
use direction::Direction;
use event::*;
use event::{AnyCb, Event, EventResult, Key};
use rect::Rect;
use std::any::Any;
use std::cell::Cell;
use std::cmp::max;
use theme::ColorStyle;
@ -249,11 +248,7 @@ impl Dialog {
pub fn buttons_mut<'a>(
&'a mut self
) -> Box<'a + Iterator<Item = &'a mut Button>> {
Box::new(
self.buttons
.iter_mut()
.map(|b| &mut b.button.view),
)
Box::new(self.buttons.iter_mut().map(|b| &mut b.button.view))
}
/// Returns currently focused element
@ -566,9 +561,7 @@ impl View for Dialog {
}
}
fn call_on_any<'a>(
&mut self, selector: &Selector, callback: Box<FnMut(&mut Any) + 'a>
) {
fn call_on_any<'a>(&mut self, selector: &Selector, callback: AnyCb<'a>) {
self.content.call_on_any(selector, callback);
}

View File

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

View File

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

View File

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

View File

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