mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-09 10:50:40 +00:00
Add Cursive::dump
This commit is contained in:
parent
9bc1cd04c3
commit
28cd51c265
@ -6,14 +6,15 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use crossbeam_channel::{self, Receiver, Sender};
|
use crossbeam_channel::{self, Receiver, Sender};
|
||||||
|
|
||||||
use crate::backend;
|
use crate::{
|
||||||
use crate::direction;
|
backend, direction,
|
||||||
use crate::event::{Event, EventResult};
|
event::{Event, EventResult},
|
||||||
use crate::printer::Printer;
|
printer::Printer,
|
||||||
use crate::theme;
|
theme,
|
||||||
use crate::view::{self, Finder, IntoBoxedView, Position, View};
|
view::{self, Finder, IntoBoxedView, Position, View},
|
||||||
use crate::views::{self, LayerPosition};
|
views::{self, LayerPosition},
|
||||||
use crate::Vec2;
|
Dump, Vec2,
|
||||||
|
};
|
||||||
|
|
||||||
static DEBUG_VIEW_NAME: &str = "_cursive_debug_view";
|
static DEBUG_VIEW_NAME: &str = "_cursive_debug_view";
|
||||||
|
|
||||||
@ -1035,6 +1036,49 @@ impl Cursive {
|
|||||||
pub fn backend_name(&self) -> &str {
|
pub fn backend_name(&self) -> &str {
|
||||||
self.backend.name()
|
self.backend.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Dump the current state of the Cursive root.
|
||||||
|
///
|
||||||
|
/// This will stop the backend and clean up the terminal.
|
||||||
|
///
|
||||||
|
/// It will save everything, including:
|
||||||
|
/// * The view tree
|
||||||
|
/// * Callbacks
|
||||||
|
/// * Menubar
|
||||||
|
/// * User data
|
||||||
|
/// * Callback sink
|
||||||
|
pub fn dump(mut self) -> crate::Dump {
|
||||||
|
Dump {
|
||||||
|
cb_sink: self.cb_sink.clone(),
|
||||||
|
cb_source: self.cb_source.clone(),
|
||||||
|
fps: self.fps,
|
||||||
|
menubar: std::mem::take(&mut self.menubar),
|
||||||
|
root_view: std::mem::take(&mut self.root),
|
||||||
|
theme: self.theme.clone(),
|
||||||
|
user_data: std::mem::replace(&mut self.user_data, Box::new(())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Restores the state from a previous dump.
|
||||||
|
///
|
||||||
|
/// This will discard everything from this `Cursive` instance.
|
||||||
|
/// In particular:
|
||||||
|
/// * All current views will be dropped, replaced by the dump.
|
||||||
|
/// * All callbacks will be replaced.
|
||||||
|
/// * Menubar will be replaced.
|
||||||
|
/// * User Data will be replaced.
|
||||||
|
/// * The callback channel will be replaced - any previous call to
|
||||||
|
/// `cb_sink` on this instance will be disconnected.
|
||||||
|
pub fn restore(&mut self, dump: Dump) {
|
||||||
|
self.cb_sink = dump.cb_sink;
|
||||||
|
self.cb_source = dump.cb_source;
|
||||||
|
self.fps = dump.fps;
|
||||||
|
self.menubar = dump.menubar;
|
||||||
|
self.root = dump.root_view;
|
||||||
|
self.theme = dump.theme;
|
||||||
|
self.user_data = dump.user_data;
|
||||||
|
self.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Cursive {
|
impl Drop for Cursive {
|
||||||
|
22
cursive-core/src/dump.rs
Normal file
22
cursive-core/src/dump.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use crate::{theme::Theme, views, Cursive};
|
||||||
|
use crossbeam_channel::{Receiver, Sender};
|
||||||
|
use std::any::Any;
|
||||||
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
|
/// Represents a dump of everything from a `Cursive` instance.
|
||||||
|
///
|
||||||
|
/// See [`Cursive::dump()`](../cursive.html#method.dump)
|
||||||
|
pub struct Dump {
|
||||||
|
pub(crate) cb_sink: Sender<Box<dyn FnOnce(&mut Cursive) + Send>>,
|
||||||
|
pub(crate) cb_source: Receiver<Box<dyn FnOnce(&mut Cursive) + Send>>,
|
||||||
|
|
||||||
|
pub(crate) fps: Option<NonZeroU32>,
|
||||||
|
|
||||||
|
pub(crate) menubar: views::Menubar,
|
||||||
|
pub(crate) root_view:
|
||||||
|
views::OnEventView<views::ScreensView<views::StackView>>,
|
||||||
|
|
||||||
|
pub(crate) theme: Theme,
|
||||||
|
|
||||||
|
pub(crate) user_data: Box<dyn Any>,
|
||||||
|
}
|
@ -17,13 +17,21 @@ macro_rules! new_default(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($c:ty) => {
|
($c:ident) => {
|
||||||
impl Default for $c {
|
impl Default for $c {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
($c:ident<$t:ident: Default>) => {
|
||||||
|
impl <$t> Default for $c<$t>
|
||||||
|
where $t: Default {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new($t::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
);
|
);
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -44,6 +52,7 @@ pub mod traits;
|
|||||||
pub mod vec;
|
pub mod vec;
|
||||||
|
|
||||||
mod cursive;
|
mod cursive;
|
||||||
|
mod dump;
|
||||||
mod printer;
|
mod printer;
|
||||||
mod rect;
|
mod rect;
|
||||||
mod with;
|
mod with;
|
||||||
@ -52,6 +61,7 @@ mod xy;
|
|||||||
mod div;
|
mod div;
|
||||||
|
|
||||||
pub use self::cursive::{CbSink, Cursive, ScreenId};
|
pub use self::cursive::{CbSink, Cursive, ScreenId};
|
||||||
|
pub use self::dump::Dump;
|
||||||
pub use self::printer::Printer;
|
pub use self::printer::Printer;
|
||||||
pub use self::rect::Rect;
|
pub use self::rect::Rect;
|
||||||
pub use self::vec::Vec2;
|
pub use self::vec::Vec2;
|
||||||
|
@ -31,6 +31,8 @@ pub struct EnableableView<V> {
|
|||||||
enabled: bool,
|
enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_default!(EnableableView<V: Default>);
|
||||||
|
|
||||||
impl<V> EnableableView<V> {
|
impl<V> EnableableView<V> {
|
||||||
/// Creates a new `EnableableView` around `view`.
|
/// Creates a new `EnableableView` around `view`.
|
||||||
///
|
///
|
||||||
|
@ -17,6 +17,8 @@ pub struct HideableView<V> {
|
|||||||
invalidated: bool,
|
invalidated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_default!(HideableView<V: Default>);
|
||||||
|
|
||||||
impl<V> HideableView<V> {
|
impl<V> HideableView<V> {
|
||||||
/// Creates a new HideableView around `view`.
|
/// Creates a new HideableView around `view`.
|
||||||
///
|
///
|
||||||
|
@ -10,6 +10,8 @@ pub struct LastSizeView<T> {
|
|||||||
pub size: Vec2,
|
pub size: Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_default!(LastSizeView<V: Default>);
|
||||||
|
|
||||||
impl<T> LastSizeView<T> {
|
impl<T> LastSizeView<T> {
|
||||||
/// Wraps the given view.
|
/// Wraps the given view.
|
||||||
pub fn new(view: T) -> Self {
|
pub fn new(view: T) -> Self {
|
||||||
|
@ -8,12 +8,14 @@ use crate::Printer;
|
|||||||
///
|
///
|
||||||
/// [`StackView`]: crate::views::StackView
|
/// [`StackView`]: crate::views::StackView
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Layer<T: View> {
|
pub struct Layer<T> {
|
||||||
view: T,
|
view: T,
|
||||||
color: ColorStyle,
|
color: ColorStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: View> Layer<T> {
|
new_default!(Layer<T: Default>);
|
||||||
|
|
||||||
|
impl<T> Layer<T> {
|
||||||
/// Wraps the given view.
|
/// Wraps the given view.
|
||||||
pub fn new(view: T) -> Self {
|
pub fn new(view: T) -> Self {
|
||||||
Self::with_color(view, ColorStyle::primary())
|
Self::with_color(view, ColorStyle::primary())
|
||||||
|
@ -10,7 +10,7 @@ use std::rc::Rc;
|
|||||||
/// This lets other views refer to this one using a string identifier.
|
/// This lets other views refer to this one using a string identifier.
|
||||||
///
|
///
|
||||||
/// See [`Identifiable`](crate::view::Identifiable) for an easy way to wrap any view with it.
|
/// See [`Identifiable`](crate::view::Identifiable) for an easy way to wrap any view with it.
|
||||||
pub struct NamedView<V: View> {
|
pub struct NamedView<V> {
|
||||||
view: Rc<RefCell<V>>,
|
view: Rc<RefCell<V>>,
|
||||||
id: String,
|
id: String,
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@ pub struct NamedView<V: View> {
|
|||||||
/// [`RefMut`]: std::cell::RefMut
|
/// [`RefMut`]: std::cell::RefMut
|
||||||
pub type ViewRef<V> = OwningHandle<RcRef<RefCell<V>>, RefMut<'static, V>>;
|
pub type ViewRef<V> = OwningHandle<RcRef<RefCell<V>>, RefMut<'static, V>>;
|
||||||
|
|
||||||
impl<V: View> NamedView<V> {
|
impl<V> NamedView<V> {
|
||||||
/// Wraps `view` in a new `NamedView`.
|
/// Wraps `view` in a new `NamedView`.
|
||||||
pub fn new<S: Into<String>>(id: S, view: V) -> Self {
|
pub fn new<S: Into<String>>(id: S, view: V) -> Self {
|
||||||
NamedView {
|
NamedView {
|
||||||
|
@ -38,11 +38,13 @@ use std::rc::Rc;
|
|||||||
/// .on_event('q', |s| s.quit())
|
/// .on_event('q', |s| s.quit())
|
||||||
/// .on_event(event::Key::Esc, |s| s.quit());
|
/// .on_event(event::Key::Esc, |s| s.quit());
|
||||||
/// ```
|
/// ```
|
||||||
pub struct OnEventView<T: View> {
|
pub struct OnEventView<T> {
|
||||||
view: T,
|
view: T,
|
||||||
callbacks: Vec<(EventTrigger, Action<T>)>,
|
callbacks: Vec<(EventTrigger, Action<T>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_default!(OnEventView<T: Default>);
|
||||||
|
|
||||||
type InnerCallback<T> = Rc<Box<dyn Fn(&mut T, &Event) -> Option<EventResult>>>;
|
type InnerCallback<T> = Rc<Box<dyn Fn(&mut T, &Event) -> Option<EventResult>>>;
|
||||||
|
|
||||||
struct Action<T> {
|
struct Action<T> {
|
||||||
@ -65,7 +67,7 @@ enum TriggerPhase {
|
|||||||
AfterChild,
|
AfterChild,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: View> OnEventView<T> {
|
impl<T> OnEventView<T> {
|
||||||
/// Wraps the given view in a new OnEventView.
|
/// Wraps the given view in a new OnEventView.
|
||||||
pub fn new(view: T) -> Self {
|
pub fn new(view: T) -> Self {
|
||||||
OnEventView {
|
OnEventView {
|
||||||
@ -83,7 +85,6 @@ impl<T: View> OnEventView<T> {
|
|||||||
self.callbacks
|
self.callbacks
|
||||||
.retain(move |&(ref trigger, _)| !trigger.has_tag(&event));
|
.retain(move |&(ref trigger, _)| !trigger.has_tag(&event));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a callback when the given event is ignored by the child.
|
/// Registers a callback when the given event is ignored by the child.
|
||||||
///
|
///
|
||||||
/// Chainable variant.
|
/// Chainable variant.
|
||||||
|
@ -25,7 +25,7 @@ pub struct PaddedView<V> {
|
|||||||
margins: Margins,
|
margins: Margins,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: View> PaddedView<V> {
|
impl<V> PaddedView<V> {
|
||||||
/// Wraps `view` in a new `PaddedView` with the given margins.
|
/// Wraps `view` in a new `PaddedView` with the given margins.
|
||||||
pub fn new(margins: Margins, view: V) -> Self {
|
pub fn new(margins: Margins, view: V) -> Self {
|
||||||
PaddedView { view, margins }
|
PaddedView { view, margins }
|
||||||
|
@ -10,7 +10,7 @@ use unicode_width::UnicodeWidthStr;
|
|||||||
|
|
||||||
/// Draws a border around a wrapped view.
|
/// Draws a border around a wrapped view.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Panel<V: View> {
|
pub struct Panel<V> {
|
||||||
// Inner view
|
// Inner view
|
||||||
view: V,
|
view: V,
|
||||||
|
|
||||||
@ -24,7 +24,9 @@ pub struct Panel<V: View> {
|
|||||||
invalidated: bool,
|
invalidated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: View> Panel<V> {
|
new_default!(Panel<V: Default>);
|
||||||
|
|
||||||
|
impl<V> Panel<V> {
|
||||||
/// Creates a new panel around the given view.
|
/// Creates a new panel around the given view.
|
||||||
pub fn new(view: V) -> Self {
|
pub fn new(view: V) -> Self {
|
||||||
Panel {
|
Panel {
|
||||||
|
@ -23,7 +23,7 @@ use crate::XY;
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// See also [`Boxable`](crate::view::Boxable) for an easy way to wrap any view.
|
/// See also [`Boxable`](crate::view::Boxable) for an easy way to wrap any view.
|
||||||
pub struct ResizedView<T: View> {
|
pub struct ResizedView<T> {
|
||||||
/// Constraint on each axis
|
/// Constraint on each axis
|
||||||
size: XY<SizeConstraint>,
|
size: XY<SizeConstraint>,
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ pub struct ResizedView<T: View> {
|
|||||||
view: T,
|
view: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: View> ResizedView<T> {
|
impl<T> ResizedView<T> {
|
||||||
/// Creates a new `ResizedView` with the given width and height requirements.
|
/// Creates a new `ResizedView` with the given width and height requirements.
|
||||||
///
|
///
|
||||||
/// `None` values will use the wrapped view's preferences.
|
/// `None` values will use the wrapped view's preferences.
|
||||||
|
@ -17,12 +17,11 @@ pub struct ScrollView<V> {
|
|||||||
on_scroll: Rc<dyn Fn(&mut Self, Rect) -> EventResult>,
|
on_scroll: Rc<dyn Fn(&mut Self, Rect) -> EventResult>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_default!(ScrollView<V: Default>);
|
||||||
|
|
||||||
impl_scroller!(ScrollView<V>::core);
|
impl_scroller!(ScrollView<V>::core);
|
||||||
|
|
||||||
impl<V> ScrollView<V>
|
impl<V> ScrollView<V> {
|
||||||
where
|
|
||||||
V: View,
|
|
||||||
{
|
|
||||||
/// Creates a new ScrollView around `view`.
|
/// Creates a new ScrollView around `view`.
|
||||||
pub fn new(inner: V) -> Self {
|
pub fn new(inner: V) -> Self {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
@ -189,7 +188,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Programmatically scroll until the child's important area is in view.
|
/// Programmatically scroll until the child's important area is in view.
|
||||||
pub fn scroll_to_important_area(&mut self) -> EventResult {
|
pub fn scroll_to_important_area(&mut self) -> EventResult
|
||||||
|
where
|
||||||
|
V: View,
|
||||||
|
{
|
||||||
let important_area = self.inner.important_area(self.core.last_size());
|
let important_area = self.inner.important_area(self.core.last_size());
|
||||||
self.core.scroll_to_rect(important_area);
|
self.core.scroll_to_rect(important_area);
|
||||||
|
|
||||||
@ -256,6 +258,7 @@ where
|
|||||||
pub fn set_on_scroll_change_inner<F>(&mut self, on_scroll: F)
|
pub fn set_on_scroll_change_inner<F>(&mut self, on_scroll: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&mut Self, Rect) -> EventResult + 'static,
|
F: FnMut(&mut Self, Rect) -> EventResult + 'static,
|
||||||
|
V: 'static,
|
||||||
{
|
{
|
||||||
self.set_on_scroll_inner(Self::skip_unchanged(on_scroll, || {
|
self.set_on_scroll_inner(Self::skip_unchanged(on_scroll, || {
|
||||||
EventResult::Ignored
|
EventResult::Ignored
|
||||||
@ -266,6 +269,7 @@ where
|
|||||||
pub fn set_on_scroll_change<F>(&mut self, on_scroll: F)
|
pub fn set_on_scroll_change<F>(&mut self, on_scroll: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&mut Cursive, Rect) + 'static,
|
F: FnMut(&mut Cursive, Rect) + 'static,
|
||||||
|
V: 'static,
|
||||||
{
|
{
|
||||||
self.set_on_scroll(Self::skip_unchanged(on_scroll, || ()));
|
self.set_on_scroll(Self::skip_unchanged(on_scroll, || ()));
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,16 @@ use crate::Vec2;
|
|||||||
/// Wrapper view that adds a shadow.
|
/// Wrapper view that adds a shadow.
|
||||||
///
|
///
|
||||||
/// It reserves a 1 pixel border on each side.
|
/// It reserves a 1 pixel border on each side.
|
||||||
pub struct ShadowView<T: View> {
|
pub struct ShadowView<T> {
|
||||||
view: T,
|
view: T,
|
||||||
top_padding: bool,
|
top_padding: bool,
|
||||||
left_padding: bool,
|
left_padding: bool,
|
||||||
// TODO: invalidate if we change the padding? wrap_needs_relayout?
|
// TODO: invalidate if we change the padding? wrap_needs_relayout?
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: View> ShadowView<T> {
|
new_default!(ShadowView<T: Default>);
|
||||||
|
|
||||||
|
impl<T> ShadowView<T> {
|
||||||
/// Wraps the given view.
|
/// Wraps the given view.
|
||||||
pub fn new(view: T) -> Self {
|
pub fn new(view: T) -> Self {
|
||||||
ShadowView {
|
ShadowView {
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
use crate::view::{View, ViewWrapper};
|
use crate::view::{View, ViewWrapper};
|
||||||
use crate::views::NamedView;
|
|
||||||
use crate::Printer;
|
use crate::Printer;
|
||||||
use crate::Vec2;
|
use crate::Vec2;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
|
||||||
/// Wrapper around a view that remembers its position.
|
/// Wrapper around a view that remembers its position.
|
||||||
pub struct TrackedView<T: View> {
|
pub struct TrackedView<T> {
|
||||||
/// Wrapped view.
|
/// Wrapped view.
|
||||||
pub view: T,
|
pub view: T,
|
||||||
/// Last position the view was located.
|
/// Last position the view was located.
|
||||||
offset: Cell<Vec2>,
|
offset: Cell<Vec2>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: View> TrackedView<T> {
|
new_default!(TrackedView<T: Default>);
|
||||||
|
|
||||||
|
impl<T> TrackedView<T> {
|
||||||
/// Return the last offset at which the view was drawn.
|
/// Return the last offset at which the view was drawn.
|
||||||
pub fn offset(&self) -> Vec2 {
|
pub fn offset(&self) -> Vec2 {
|
||||||
self.offset.get()
|
self.offset.get()
|
||||||
@ -26,17 +27,6 @@ impl<T: View> TrackedView<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as [`with_name`](TrackedView::with_name)
|
|
||||||
#[deprecated(note = "`with_id` is being renamed to `with_name`")]
|
|
||||||
pub fn with_id(self, id: &str) -> NamedView<Self> {
|
|
||||||
self.with_name(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wraps itself in a `NamedView` for easy retrieval.
|
|
||||||
pub fn with_name(self, name: &str) -> NamedView<Self> {
|
|
||||||
NamedView::new(name, self)
|
|
||||||
}
|
|
||||||
|
|
||||||
inner_getters!(self.view: T);
|
inner_getters!(self.view: T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user