diff --git a/Cargo.toml b/Cargo.toml index 85bc834..abe3288 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] authors = ["Alexandre Bury "] build = "build.rs" +categories = ["command-line-interface", "gui"] description = "A TUI (Text User Interface) library focused on ease-of-use." documentation = "https://gyscos.github.io/Cursive/cursive/index.html" exclude = ["doc", "assets"] keywords = ["ncurses", "TUI", "UI"] -categories = ["command-line-interface", "gui"] license = "MIT" name = "cursive" readme = "Readme.md" @@ -13,7 +13,11 @@ repository = "https://github.com/gyscos/Cursive" version = "0.4.0" [badges] -travis-ci = { repository = "gyscos/Cursive" } + +[badges.travis-ci] +repository = "gyscos/Cursive" + +[build-dependencies] [build-dependencies.skeptic] optional = true @@ -23,18 +27,19 @@ version = "0.6" chan = "0.1.18" num = "0.1" odds = "0.2" +owning_ref = "0.2.4" toml = "0.2" unicode-segmentation = "1.0" unicode-width = "0.1" -[dependencies.chan-signal] -optional = true -version = "0.1" - [dependencies.bear-lib-terminal] optional = true version = "1.3.1" +[dependencies.chan-signal] +optional = true +version = "0.1" + [dependencies.ncurses] features = ["wide"] optional = true @@ -55,8 +60,8 @@ skeptic = "0.6" [features] default = ["ncurses"] -termion-backend = ["termion", "chan-signal"] pancurses-backend = ["pancurses"] +termion-backend = ["termion", "chan-signal"] [lib] name = "cursive" diff --git a/src/lib.rs b/src/lib.rs index 3c868ef..cda5d79 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,6 +64,7 @@ extern crate unicode_segmentation; extern crate unicode_width; extern crate odds; extern crate num; +extern crate owning_ref; #[macro_use] extern crate chan; diff --git a/src/views/mod.rs b/src/views/mod.rs index 074de54..0a01478 100644 --- a/src/views/mod.rs +++ b/src/views/mod.rs @@ -52,6 +52,7 @@ mod menu_popup; mod panel; mod progress_bar; mod radio; +mod refcell_view; mod select_view; mod slider_view; mod shadow_view; @@ -78,6 +79,7 @@ pub use self::menubar::Menubar; pub use self::panel::Panel; pub use self::progress_bar::{Counter, ProgressBar}; pub use self::radio::{RadioGroup, RadioButton}; +pub use self::refcell_view::{RefCellView, ViewRef}; pub use self::select_view::SelectView; pub use self::shadow_view::ShadowView; pub use self::sized_view::SizedView; diff --git a/src/views/refcell_view.rs b/src/views/refcell_view.rs new file mode 100644 index 0000000..e412310 --- /dev/null +++ b/src/views/refcell_view.rs @@ -0,0 +1,49 @@ + + +use owning_ref::{RcRef, OwningHandle}; + +use std::cell::{RefCell, RefMut}; +use std::rc::Rc; +use view::{View, ViewWrapper}; + +/// Wrapper around a view to provide interior mutability. +pub struct RefCellView { + view: Rc>, +} + +/// Mutable reference to a view. +pub type ViewRef = OwningHandle>, RefMut<'static, V>>; + +impl RefCellView { + /// Wraps `view` in a new `RefCellView`. + pub fn new(view: V) -> Self { + RefCellView { view: Rc::new(RefCell::new(view)) } + } + + /// Gets mutable access to the inner view. + pub fn get_mut(&mut self) -> ViewRef { + // TODO: return a standalone item (not tied to our lifetime) + // that bundles `self.view.clone()` and allow mutable reference to + // the inner view. + let cell_ref = RcRef::new(self.view.clone()); + + OwningHandle::new(cell_ref, + |x| unsafe { x.as_ref() }.unwrap().borrow_mut()) + } +} + +impl ViewWrapper for RefCellView { + type V = T; + + fn with_view(&self, f: F) -> R + where F: FnOnce(&Self::V) -> R + { + f(&*self.view.borrow()) + } + + fn with_view_mut(&mut self, f: F) -> R + where F: FnOnce(&mut Self::V) -> R + { + f(&mut *self.view.borrow_mut()) + } +}