mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 09:25:01 +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 crate::backend;
|
||||
use crate::direction;
|
||||
use crate::event::{Event, EventResult};
|
||||
use crate::printer::Printer;
|
||||
use crate::theme;
|
||||
use crate::view::{self, Finder, IntoBoxedView, Position, View};
|
||||
use crate::views::{self, LayerPosition};
|
||||
use crate::Vec2;
|
||||
use crate::{
|
||||
backend, direction,
|
||||
event::{Event, EventResult},
|
||||
printer::Printer,
|
||||
theme,
|
||||
view::{self, Finder, IntoBoxedView, Position, View},
|
||||
views::{self, LayerPosition},
|
||||
Dump, Vec2,
|
||||
};
|
||||
|
||||
static DEBUG_VIEW_NAME: &str = "_cursive_debug_view";
|
||||
|
||||
@ -1035,6 +1036,49 @@ impl Cursive {
|
||||
pub fn backend_name(&self) -> &str {
|
||||
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 {
|
||||
|
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 {
|
||||
fn default() -> Self {
|
||||
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]
|
||||
@ -44,6 +52,7 @@ pub mod traits;
|
||||
pub mod vec;
|
||||
|
||||
mod cursive;
|
||||
mod dump;
|
||||
mod printer;
|
||||
mod rect;
|
||||
mod with;
|
||||
@ -52,6 +61,7 @@ mod xy;
|
||||
mod div;
|
||||
|
||||
pub use self::cursive::{CbSink, Cursive, ScreenId};
|
||||
pub use self::dump::Dump;
|
||||
pub use self::printer::Printer;
|
||||
pub use self::rect::Rect;
|
||||
pub use self::vec::Vec2;
|
||||
|
@ -31,6 +31,8 @@ pub struct EnableableView<V> {
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
new_default!(EnableableView<V: Default>);
|
||||
|
||||
impl<V> EnableableView<V> {
|
||||
/// Creates a new `EnableableView` around `view`.
|
||||
///
|
||||
|
@ -17,6 +17,8 @@ pub struct HideableView<V> {
|
||||
invalidated: bool,
|
||||
}
|
||||
|
||||
new_default!(HideableView<V: Default>);
|
||||
|
||||
impl<V> HideableView<V> {
|
||||
/// Creates a new HideableView around `view`.
|
||||
///
|
||||
|
@ -10,6 +10,8 @@ pub struct LastSizeView<T> {
|
||||
pub size: Vec2,
|
||||
}
|
||||
|
||||
new_default!(LastSizeView<V: Default>);
|
||||
|
||||
impl<T> LastSizeView<T> {
|
||||
/// Wraps the given view.
|
||||
pub fn new(view: T) -> Self {
|
||||
|
@ -8,12 +8,14 @@ use crate::Printer;
|
||||
///
|
||||
/// [`StackView`]: crate::views::StackView
|
||||
#[derive(Debug)]
|
||||
pub struct Layer<T: View> {
|
||||
pub struct Layer<T> {
|
||||
view: T,
|
||||
color: ColorStyle,
|
||||
}
|
||||
|
||||
impl<T: View> Layer<T> {
|
||||
new_default!(Layer<T: Default>);
|
||||
|
||||
impl<T> Layer<T> {
|
||||
/// Wraps the given view.
|
||||
pub fn new(view: T) -> Self {
|
||||
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.
|
||||
///
|
||||
/// 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>>,
|
||||
id: String,
|
||||
}
|
||||
@ -22,7 +22,7 @@ pub struct NamedView<V: View> {
|
||||
/// [`RefMut`]: std::cell::RefMut
|
||||
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`.
|
||||
pub fn new<S: Into<String>>(id: S, view: V) -> Self {
|
||||
NamedView {
|
||||
|
@ -38,11 +38,13 @@ use std::rc::Rc;
|
||||
/// .on_event('q', |s| s.quit())
|
||||
/// .on_event(event::Key::Esc, |s| s.quit());
|
||||
/// ```
|
||||
pub struct OnEventView<T: View> {
|
||||
pub struct OnEventView<T> {
|
||||
view: T,
|
||||
callbacks: Vec<(EventTrigger, Action<T>)>,
|
||||
}
|
||||
|
||||
new_default!(OnEventView<T: Default>);
|
||||
|
||||
type InnerCallback<T> = Rc<Box<dyn Fn(&mut T, &Event) -> Option<EventResult>>>;
|
||||
|
||||
struct Action<T> {
|
||||
@ -65,7 +67,7 @@ enum TriggerPhase {
|
||||
AfterChild,
|
||||
}
|
||||
|
||||
impl<T: View> OnEventView<T> {
|
||||
impl<T> OnEventView<T> {
|
||||
/// Wraps the given view in a new OnEventView.
|
||||
pub fn new(view: T) -> Self {
|
||||
OnEventView {
|
||||
@ -83,7 +85,6 @@ impl<T: View> OnEventView<T> {
|
||||
self.callbacks
|
||||
.retain(move |&(ref trigger, _)| !trigger.has_tag(&event));
|
||||
}
|
||||
|
||||
/// Registers a callback when the given event is ignored by the child.
|
||||
///
|
||||
/// Chainable variant.
|
||||
|
@ -25,7 +25,7 @@ pub struct PaddedView<V> {
|
||||
margins: Margins,
|
||||
}
|
||||
|
||||
impl<V: View> PaddedView<V> {
|
||||
impl<V> PaddedView<V> {
|
||||
/// Wraps `view` in a new `PaddedView` with the given margins.
|
||||
pub fn new(margins: Margins, view: V) -> Self {
|
||||
PaddedView { view, margins }
|
||||
|
@ -10,7 +10,7 @@ use unicode_width::UnicodeWidthStr;
|
||||
|
||||
/// Draws a border around a wrapped view.
|
||||
#[derive(Debug)]
|
||||
pub struct Panel<V: View> {
|
||||
pub struct Panel<V> {
|
||||
// Inner view
|
||||
view: V,
|
||||
|
||||
@ -24,7 +24,9 @@ pub struct Panel<V: View> {
|
||||
invalidated: bool,
|
||||
}
|
||||
|
||||
impl<V: View> Panel<V> {
|
||||
new_default!(Panel<V: Default>);
|
||||
|
||||
impl<V> Panel<V> {
|
||||
/// Creates a new panel around the given view.
|
||||
pub fn new(view: V) -> Self {
|
||||
Panel {
|
||||
|
@ -23,7 +23,7 @@ use crate::XY;
|
||||
/// ```
|
||||
///
|
||||
/// 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
|
||||
size: XY<SizeConstraint>,
|
||||
|
||||
@ -34,7 +34,7 @@ pub struct ResizedView<T: View> {
|
||||
view: T,
|
||||
}
|
||||
|
||||
impl<T: View> ResizedView<T> {
|
||||
impl<T> ResizedView<T> {
|
||||
/// Creates a new `ResizedView` with the given width and height requirements.
|
||||
///
|
||||
/// `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>,
|
||||
}
|
||||
|
||||
new_default!(ScrollView<V: Default>);
|
||||
|
||||
impl_scroller!(ScrollView<V>::core);
|
||||
|
||||
impl<V> ScrollView<V>
|
||||
where
|
||||
V: View,
|
||||
{
|
||||
impl<V> ScrollView<V> {
|
||||
/// Creates a new ScrollView around `view`.
|
||||
pub fn new(inner: V) -> Self {
|
||||
ScrollView {
|
||||
@ -189,7 +188,10 @@ where
|
||||
}
|
||||
|
||||
/// 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());
|
||||
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)
|
||||
where
|
||||
F: FnMut(&mut Self, Rect) -> EventResult + 'static,
|
||||
V: 'static,
|
||||
{
|
||||
self.set_on_scroll_inner(Self::skip_unchanged(on_scroll, || {
|
||||
EventResult::Ignored
|
||||
@ -266,6 +269,7 @@ where
|
||||
pub fn set_on_scroll_change<F>(&mut self, on_scroll: F)
|
||||
where
|
||||
F: FnMut(&mut Cursive, Rect) + 'static,
|
||||
V: 'static,
|
||||
{
|
||||
self.set_on_scroll(Self::skip_unchanged(on_scroll, || ()));
|
||||
}
|
||||
|
@ -8,14 +8,16 @@ use crate::Vec2;
|
||||
/// Wrapper view that adds a shadow.
|
||||
///
|
||||
/// It reserves a 1 pixel border on each side.
|
||||
pub struct ShadowView<T: View> {
|
||||
pub struct ShadowView<T> {
|
||||
view: T,
|
||||
top_padding: bool,
|
||||
left_padding: bool,
|
||||
// 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.
|
||||
pub fn new(view: T) -> Self {
|
||||
ShadowView {
|
||||
|
@ -1,18 +1,19 @@
|
||||
use crate::view::{View, ViewWrapper};
|
||||
use crate::views::NamedView;
|
||||
use crate::Printer;
|
||||
use crate::Vec2;
|
||||
use std::cell::Cell;
|
||||
|
||||
/// Wrapper around a view that remembers its position.
|
||||
pub struct TrackedView<T: View> {
|
||||
pub struct TrackedView<T> {
|
||||
/// Wrapped view.
|
||||
pub view: T,
|
||||
/// Last position the view was located.
|
||||
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.
|
||||
pub fn offset(&self) -> Vec2 {
|
||||
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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user