View::focus_view: replace () with zero-sized ViewNotFound

This commit is contained in:
Alexandre Bury 2020-12-20 10:58:57 -08:00
parent 759a7e8b49
commit c352e4c54a
15 changed files with 155 additions and 95 deletions

View File

@ -12,7 +12,7 @@ use crate::{
event::{Event, EventResult}, event::{Event, EventResult},
printer::Printer, printer::Printer,
theme, theme,
view::{self, Finder, IntoBoxedView, Position, View}, view::{self, Finder, IntoBoxedView, Position, View, ViewNotFound},
views::{self, LayerPosition}, views::{self, LayerPosition},
Dump, Vec2, Dump, Vec2,
}; };
@ -616,18 +616,21 @@ impl Cursive {
/// Moves the focus to the view identified by `name`. /// Moves the focus to the view identified by `name`.
/// ///
/// Convenient method to call `focus` with a [`view::Selector::Name`]. /// Convenient method to call `focus` with a [`view::Selector::Name`].
pub fn focus_name(&mut self, name: &str) -> Result<(), ()> { pub fn focus_name(&mut self, name: &str) -> Result<(), ViewNotFound> {
self.focus(&view::Selector::Name(name)) self.focus(&view::Selector::Name(name))
} }
/// Same as [`focus_name`](Cursive::focus_name). /// Same as [`focus_name`](Cursive::focus_name).
#[deprecated(note = "`focus_id` is being renamed to `focus_name`")] #[deprecated(note = "`focus_id` is being renamed to `focus_name`")]
pub fn focus_id(&mut self, id: &str) -> Result<(), ()> { pub fn focus_id(&mut self, id: &str) -> Result<(), ViewNotFound> {
self.focus(&view::Selector::Name(id)) self.focus(&view::Selector::Name(id))
} }
/// Moves the focus to the view identified by `sel`. /// Moves the focus to the view identified by `sel`.
pub fn focus(&mut self, sel: &view::Selector<'_>) -> Result<(), ()> { pub fn focus(
&mut self,
sel: &view::Selector<'_>,
) -> Result<(), ViewNotFound> {
self.root.focus_view(sel) self.root.focus_view(sel)
} }

View File

@ -117,7 +117,7 @@ pub use self::scrollable::Scrollable;
pub use self::size_cache::SizeCache; pub use self::size_cache::SizeCache;
pub use self::size_constraint::SizeConstraint; pub use self::size_constraint::SizeConstraint;
pub use self::view_path::ViewPath; pub use self::view_path::ViewPath;
pub use self::view_trait::View; pub use self::view_trait::{View, ViewNotFound};
pub use self::view_wrapper::ViewWrapper; pub use self::view_wrapper::ViewWrapper;
#[deprecated(note = "`Boxable` is being renamed to `Resizable`")] #[deprecated(note = "`Boxable` is being renamed to `Resizable`")]

View File

@ -6,7 +6,7 @@ use crate::{
printer::Printer, printer::Printer,
rect::Rect, rect::Rect,
theme::ColorStyle, theme::ColorStyle,
view::{ScrollStrategy, Selector, SizeCache}, view::{ScrollStrategy, Selector, SizeCache, ViewNotFound},
with::With, with::With,
Vec2, XY, Vec2, XY,
}; };
@ -282,9 +282,9 @@ impl Core {
&mut self, &mut self,
selector: &Selector<'_>, selector: &Selector<'_>,
inner_focus_view: F, inner_focus_view: F,
) -> Result<(), ()> ) -> Result<(), ViewNotFound>
where where
F: FnOnce(&Selector) -> Result<(), ()>, F: FnOnce(&Selector) -> Result<(), ViewNotFound>,
{ {
inner_focus_view(selector) inner_focus_view(selector)
} }

View File

@ -6,6 +6,18 @@ use crate::Printer;
use crate::Vec2; use crate::Vec2;
use std::any::Any; use std::any::Any;
/// Error indicating a view was not found.
#[derive(Debug)]
pub struct ViewNotFound;
impl std::fmt::Display for ViewNotFound {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "View could not be found")
}
}
impl std::error::Error for ViewNotFound {}
/// Main trait defining a view behaviour. /// Main trait defining a view behaviour.
/// ///
/// This is what you should implement to define a custom View. /// This is what you should implement to define a custom View.
@ -90,8 +102,8 @@ pub trait View: Any + AnyView {
/// Returns `Ok(())` if the view was found and selected. /// Returns `Ok(())` if the view was found and selected.
/// ///
/// Default implementation simply returns `Err(())`. /// Default implementation simply returns `Err(())`.
fn focus_view(&mut self, _: &Selector<'_>) -> Result<(), ()> { fn focus_view(&mut self, _: &Selector<'_>) -> Result<(), ViewNotFound> {
Err(()) Err(ViewNotFound)
} }
/// This view is offered focus. Will it take it? /// This view is offered focus. Will it take it?

View File

@ -1,9 +1,10 @@
use crate::direction::Direction; use crate::{
use crate::event::{AnyCb, Event, EventResult}; direction::Direction,
use crate::rect::Rect; event::{AnyCb, Event, EventResult},
use crate::view::{Selector, View}; rect::Rect,
use crate::Printer; view::{Selector, View, ViewNotFound},
use crate::Vec2; Printer, Vec2,
};
/// Generic wrapper around a view. /// Generic wrapper around a view.
/// ///
@ -84,9 +85,12 @@ pub trait ViewWrapper: 'static {
} }
/// Wraps the `focus_view` method. /// Wraps the `focus_view` method.
fn wrap_focus_view(&mut self, selector: &Selector<'_>) -> Result<(), ()> { fn wrap_focus_view(
&mut self,
selector: &Selector<'_>,
) -> Result<(), ViewNotFound> {
self.with_view_mut(|v| v.focus_view(selector)) self.with_view_mut(|v| v.focus_view(selector))
.unwrap_or(Err(())) .unwrap_or(Err(ViewNotFound))
} }
/// Wraps the `needs_relayout` method. /// Wraps the `needs_relayout` method.
@ -135,7 +139,10 @@ impl<T: ViewWrapper> View for T {
self.wrap_needs_relayout() self.wrap_needs_relayout()
} }
fn focus_view(&mut self, selector: &Selector<'_>) -> Result<(), ()> { fn focus_view(
&mut self,
selector: &Selector<'_>,
) -> Result<(), ViewNotFound> {
self.wrap_focus_view(selector) self.wrap_focus_view(selector)
} }

View File

@ -1,10 +1,10 @@
use crate::direction::Direction; use crate::{
use crate::event::{AnyCb, Event, EventResult}; direction::Direction,
use crate::rect::Rect; event::{AnyCb, Event, EventResult},
use crate::view::{Selector, View}; rect::Rect,
use crate::Printer; view::{Selector, View, ViewNotFound},
use crate::Vec2; Printer, Vec2, With,
use crate::With; };
// Define this type separately to appease the Clippy god // Define this type separately to appease the Clippy god
type CallOnAny<T> = Box<dyn for<'a> FnMut(&mut T, &Selector, AnyCb<'a>)>; type CallOnAny<T> = Box<dyn for<'a> FnMut(&mut T, &Selector, AnyCb<'a>)>;
@ -51,7 +51,7 @@ pub struct Canvas<T> {
layout: Box<dyn FnMut(&mut T, Vec2)>, layout: Box<dyn FnMut(&mut T, Vec2)>,
take_focus: Box<dyn FnMut(&mut T, Direction) -> bool>, take_focus: Box<dyn FnMut(&mut T, Direction) -> bool>,
needs_relayout: Box<dyn Fn(&T) -> bool>, needs_relayout: Box<dyn Fn(&T) -> bool>,
focus_view: Box<dyn FnMut(&mut T, &Selector) -> Result<(), ()>>, focus_view: Box<dyn FnMut(&mut T, &Selector) -> Result<(), ViewNotFound>>,
call_on_any: CallOnAny<T>, call_on_any: CallOnAny<T>,
important_area: Box<dyn Fn(&T, Vec2) -> Rect>, important_area: Box<dyn Fn(&T, Vec2) -> Rect>,
} }
@ -85,7 +85,7 @@ 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(())), focus_view: Box::new(|_, _| Err(ViewNotFound)),
call_on_any: Box::new(|_, _, _| ()), call_on_any: Box::new(|_, _, _| ()),
important_area: Box::new(|_, size| { important_area: Box::new(|_, size| {
Rect::from_corners((0, 0), size) Rect::from_corners((0, 0), size)
@ -245,7 +245,7 @@ impl<T> Canvas<T> {
/// Sets the closure for `focus_view()`. /// Sets the closure for `focus_view()`.
pub fn set_focus_view<F>(&mut self, f: F) pub fn set_focus_view<F>(&mut self, f: F)
where where
F: 'static + FnMut(&mut T, &Selector<'_>) -> Result<(), ()>, F: 'static + FnMut(&mut T, &Selector<'_>) -> Result<(), ViewNotFound>,
{ {
self.focus_view = Box::new(f); self.focus_view = Box::new(f);
} }
@ -255,7 +255,7 @@ impl<T> Canvas<T> {
/// Chainable variant. /// Chainable variant.
pub fn with_focus_view<F>(self, f: F) -> Self pub fn with_focus_view<F>(self, f: F) -> Self
where where
F: 'static + FnMut(&mut T, &Selector<'_>) -> Result<(), ()>, F: 'static + FnMut(&mut T, &Selector<'_>) -> Result<(), ViewNotFound>,
{ {
self.with(|s| s.set_focus_view(f)) self.with(|s| s.set_focus_view(f))
} }
@ -286,7 +286,10 @@ impl<T: 'static> View for Canvas<T> {
(self.needs_relayout)(&self.state) (self.needs_relayout)(&self.state)
} }
fn focus_view(&mut self, selector: &Selector<'_>) -> Result<(), ()> { fn focus_view(
&mut self,
selector: &Selector<'_>,
) -> Result<(), ViewNotFound> {
(self.focus_view)(&mut self.state, selector) (self.focus_view)(&mut self.state, selector)
} }

View File

@ -1,14 +1,14 @@
use crate::align::*; use crate::{
use crate::direction::{Absolute, Direction, Relative}; align::*,
use crate::event::{AnyCb, Event, EventResult, Key}; direction::{Absolute, Direction, Relative},
use crate::rect::Rect; event::{AnyCb, Event, EventResult, Key},
use crate::theme::ColorStyle; rect::Rect,
use crate::view::{IntoBoxedView, Margins, Selector, View}; theme::ColorStyle,
use crate::views::{BoxedView, Button, DummyView, LastSizeView, TextView}; utils::markup::StyledString,
use crate::Cursive; view::{IntoBoxedView, Margins, Selector, View, ViewNotFound},
use crate::Printer; views::{BoxedView, Button, DummyView, LastSizeView, TextView},
use crate::Vec2; Cursive, Printer, Vec2, With,
use crate::{utils::markup::StyledString, With}; };
use std::cell::Cell; use std::cell::Cell;
use std::cmp::max; use std::cmp::max;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
@ -764,7 +764,10 @@ impl View for Dialog {
self.content.call_on_any(selector, callback); self.content.call_on_any(selector, callback);
} }
fn focus_view(&mut self, selector: &Selector<'_>) -> Result<(), ()> { fn focus_view(
&mut self,
selector: &Selector<'_>,
) -> Result<(), ViewNotFound> {
self.content.focus_view(selector) self.content.focus_view(selector)
} }

View File

@ -2,7 +2,7 @@ use crate::{
direction::{Absolute, Direction, Relative}, direction::{Absolute, Direction, Relative},
event::{AnyCb, Event, EventResult, Key}, event::{AnyCb, Event, EventResult, Key},
rect::Rect, rect::Rect,
view::{IntoBoxedView, Selector}, view::{IntoBoxedView, Selector, ViewNotFound},
{Printer, Vec2, View, With}, {Printer, Vec2, View, With},
}; };
@ -72,7 +72,10 @@ impl FixedLayout {
/// ///
/// Returns `Err(())` if `index >= self.len()`, or if the view at the /// Returns `Err(())` if `index >= self.len()`, or if the view at the
/// given index does not accept focus. /// given index does not accept focus.
pub fn set_focus_index(&mut self, index: usize) -> Result<(), ()> { pub fn set_focus_index(
&mut self,
index: usize,
) -> Result<(), ViewNotFound> {
if self if self
.children .children
.get_mut(index) .get_mut(index)
@ -82,7 +85,7 @@ impl FixedLayout {
self.focus = index; self.focus = index;
Ok(()) Ok(())
} else { } else {
Err(()) Err(ViewNotFound)
} }
} }
@ -352,7 +355,10 @@ impl View for FixedLayout {
} }
} }
fn focus_view(&mut self, selector: &Selector<'_>) -> Result<(), ()> { fn focus_view(
&mut self,
selector: &Selector<'_>,
) -> Result<(), ViewNotFound> {
for (i, child) in self.children.iter_mut().enumerate() { for (i, child) in self.children.iter_mut().enumerate() {
if child.view.focus_view(selector).is_ok() { if child.view.focus_view(selector).is_ok() {
self.focus = i; self.focus = i;
@ -360,6 +366,6 @@ impl View for FixedLayout {
} }
} }
Err(()) Err(ViewNotFound)
} }
} }

View File

@ -1,11 +1,10 @@
use crate::direction; use crate::{
use crate::event::{AnyCb, Event, EventResult, Key}; direction,
use crate::rect::Rect; event::{AnyCb, Event, EventResult, Key},
use crate::view::{IntoBoxedView, Selector, SizeCache, View}; rect::Rect,
use crate::Printer; view::{IntoBoxedView, Selector, SizeCache, View, ViewNotFound},
use crate::Vec2; Printer, Vec2, With, XY,
use crate::With; };
use crate::XY;
use log::debug; use log::debug;
use std::cmp::min; use std::cmp::min;
use std::ops::Deref; use std::ops::Deref;
@ -228,7 +227,10 @@ impl LinearLayout {
/// ///
/// Returns `Err(())` if `index >= self.len()`, or if the view at the /// Returns `Err(())` if `index >= self.len()`, or if the view at the
/// given index does not accept focus. /// given index does not accept focus.
pub fn set_focus_index(&mut self, index: usize) -> Result<(), ()> { pub fn set_focus_index(
&mut self,
index: usize,
) -> Result<(), ViewNotFound> {
if self if self
.children .children
.get_mut(index) .get_mut(index)
@ -238,7 +240,7 @@ impl LinearLayout {
self.focus = index; self.focus = index;
Ok(()) Ok(())
} else { } else {
Err(()) Err(ViewNotFound)
} }
} }
@ -713,7 +715,10 @@ impl View for LinearLayout {
} }
} }
fn focus_view(&mut self, selector: &Selector<'_>) -> Result<(), ()> { fn focus_view(
&mut self,
selector: &Selector<'_>,
) -> Result<(), ViewNotFound> {
for (i, child) in self.children.iter_mut().enumerate() { for (i, child) in self.children.iter_mut().enumerate() {
if child.view.focus_view(selector).is_ok() { if child.view.focus_view(selector).is_ok() {
self.focus = i; self.focus = i;
@ -721,7 +726,7 @@ impl View for LinearLayout {
} }
} }
Err(()) Err(ViewNotFound)
} }
fn important_area(&self, _: Vec2) -> Rect { fn important_area(&self, _: Vec2) -> Rect {

View File

@ -1,11 +1,10 @@
use crate::direction; use crate::{
use crate::event::{AnyCb, Callback, Event, EventResult, Key}; direction,
use crate::rect::Rect; event::{AnyCb, Callback, Event, EventResult, Key},
use crate::view::{IntoBoxedView, Selector, View}; rect::Rect,
use crate::Cursive; view::{IntoBoxedView, Selector, View, ViewNotFound},
use crate::Printer; Cursive, Printer, Vec2, With,
use crate::Vec2; };
use crate::With;
use log::debug; use log::debug;
use std::rc::Rc; use std::rc::Rc;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
@ -435,7 +434,10 @@ impl View for ListView {
} }
} }
fn focus_view(&mut self, selector: &Selector<'_>) -> Result<(), ()> { fn focus_view(
&mut self,
selector: &Selector<'_>,
) -> Result<(), ViewNotFound> {
if let Some(i) = self if let Some(i) = self
.children .children
.iter_mut() .iter_mut()
@ -447,7 +449,7 @@ impl View for ListView {
self.focus = i; self.focus = i;
Ok(()) Ok(())
} else { } else {
Err(()) Err(ViewNotFound)
} }
} }

View File

@ -1,5 +1,7 @@
use crate::event::AnyCb; use crate::{
use crate::view::{Selector, View, ViewWrapper}; event::AnyCb,
view::{Selector, View, ViewNotFound, ViewWrapper},
};
use owning_ref::{OwningHandle, RcRef}; use owning_ref::{OwningHandle, RcRef};
use std::cell::{RefCell, RefMut}; use std::cell::{RefCell, RefMut};
use std::ops::DerefMut; use std::ops::DerefMut;
@ -106,7 +108,10 @@ impl<T: View + 'static> ViewWrapper for NamedView<T> {
} }
} }
fn wrap_focus_view(&mut self, selector: &Selector<'_>) -> Result<(), ()> { fn wrap_focus_view(
&mut self,
selector: &Selector<'_>,
) -> Result<(), ViewNotFound> {
match selector { match selector {
#[allow(deprecated)] #[allow(deprecated)]
&Selector::Name(name) | &Selector::Id(name) &Selector::Name(name) | &Selector::Id(name)
@ -117,7 +122,7 @@ impl<T: View + 'static> ViewWrapper for NamedView<T> {
s => self s => self
.view .view
.try_borrow_mut() .try_borrow_mut()
.map_err(|_| ()) .map_err(|_| ViewNotFound)
.and_then(|mut v| v.deref_mut().focus_view(s)), .and_then(|mut v| v.deref_mut().focus_view(s)),
} }
} }

View File

@ -1,7 +1,8 @@
use crate::event::AnyCb; use crate::{
use crate::view::Selector; event::AnyCb,
use crate::views::BoxedView; view::{Selector, View, ViewNotFound},
use crate::View; views::BoxedView,
};
/// Identifies a screen in the cursive root. /// Identifies a screen in the cursive root.
pub type ScreenId = usize; pub type ScreenId = usize;
@ -129,7 +130,10 @@ where
} }
} }
fn wrap_focus_view(&mut self, selector: &Selector<'_>) -> Result<(), ()> { fn wrap_focus_view(
&mut self,
selector: &Selector<'_>,
) -> Result<(), ViewNotFound> {
for (i, child) in self.screens.iter_mut().enumerate() { for (i, child) in self.screens.iter_mut().enumerate() {
if child.focus_view(selector).is_ok() { if child.focus_view(selector).is_ok() {
self.active_screen = i; self.active_screen = i;
@ -137,6 +141,6 @@ where
} }
} }
Err(()) Err(ViewNotFound)
} }
} }

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
direction::Direction, direction::Direction,
event::{AnyCb, Event, EventResult}, event::{AnyCb, Event, EventResult},
view::{scroll, ScrollStrategy, Selector, View}, view::{scroll, ScrollStrategy, Selector, View, ViewNotFound},
Cursive, Printer, Rect, Vec2, With, Cursive, Printer, Rect, Vec2, With,
}; };
@ -361,7 +361,10 @@ where
self.inner.call_on_any(selector, cb) self.inner.call_on_any(selector, cb)
} }
fn focus_view(&mut self, selector: &Selector<'_>) -> Result<(), ()> { fn focus_view(
&mut self,
selector: &Selector<'_>,
) -> Result<(), ViewNotFound> {
self.inner.focus_view(selector).map(|()| { self.inner.focus_view(selector).map(|()| {
self.scroll_to_important_area(); self.scroll_to_important_area();
}) })

View File

@ -1,13 +1,14 @@
use crate::direction::Direction; use crate::{
use crate::event::{AnyCb, Event, EventResult}; direction::Direction,
use crate::theme::ColorStyle; event::{AnyCb, Event, EventResult},
use crate::view::{ theme::ColorStyle,
IntoBoxedView, Offset, Position, Selector, View, ViewWrapper, view::{
IntoBoxedView, Offset, Position, Selector, View, ViewNotFound,
ViewWrapper,
},
views::{BoxedView, CircularFocus, Layer, ShadowView},
Printer, Vec2, With,
}; };
use crate::views::{BoxedView, CircularFocus, Layer, ShadowView};
use crate::Printer;
use crate::Vec2;
use crate::With;
use std::cell; use std::cell;
use std::ops::Deref; use std::ops::Deref;
@ -189,7 +190,10 @@ impl<T: View> View for ChildWrapper<T> {
} }
} }
fn focus_view(&mut self, selector: &Selector<'_>) -> Result<(), ()> { fn focus_view(
&mut self,
selector: &Selector<'_>,
) -> Result<(), ViewNotFound> {
match *self { match *self {
ChildWrapper::Shadow(ref mut v) => v.focus_view(selector), ChildWrapper::Shadow(ref mut v) => v.focus_view(selector),
ChildWrapper::Backfilled(ref mut v) => v.focus_view(selector), ChildWrapper::Backfilled(ref mut v) => v.focus_view(selector),
@ -680,14 +684,17 @@ impl View for StackView {
} }
} }
fn focus_view(&mut self, selector: &Selector<'_>) -> Result<(), ()> { fn focus_view(
&mut self,
selector: &Selector<'_>,
) -> Result<(), ViewNotFound> {
for layer in &mut self.layers { for layer in &mut self.layers {
if layer.view.focus_view(selector).is_ok() { if layer.view.focus_view(selector).is_ok() {
return Ok(()); return Ok(());
} }
} }
Err(()) Err(ViewNotFound)
} }
} }

View File

@ -203,7 +203,7 @@ impl Backend {
} }
// Is it a UTF-8 starting point? // Is it a UTF-8 starting point?
let event = if 32 <= ch && ch <= 255 && ch != 127 { let event = if (32..=255).contains(&ch) && ch != 127 {
utf8::read_char(ch as u8, || Some(ncurses::getch() as u8)) utf8::read_char(ch as u8, || Some(ncurses::getch() as u8))
.map(Event::Char) .map(Event::Char)
.unwrap_or_else(|e| { .unwrap_or_else(|e| {