Add fullscreen layers to StackView

Fixes #87
This commit is contained in:
Alexandre Bury 2017-01-23 18:54:33 -08:00
parent 053544d192
commit f504ad8f0e
6 changed files with 104 additions and 25 deletions

View File

@ -15,7 +15,7 @@ fn main() {
// The text is too long to fit on a line, so the view will wrap lines, // The text is too long to fit on a line, so the view will wrap lines,
// and will adapt to the terminal size. // and will adapt to the terminal size.
siv.add_layer(Dialog::around(TextView::new(content)) siv.add_fullscreen_layer(Dialog::around(TextView::new(content))
.h_align(HAlign::Center) .h_align(HAlign::Center)
.button("Quit", |s| s.quit())); .button("Quit", |s| s.quit()));
// Show a popup on top of the view. // Show a popup on top of the view.

View File

@ -437,7 +437,7 @@ impl Cursive {
self.global_callbacks.insert(event.into(), Callback::from_fn(cb)); self.global_callbacks.insert(event.into(), Callback::from_fn(cb));
} }
/// Convenient method to add a layer to the current screen. /// Add a layer to the current screen.
/// ///
/// # Examples /// # Examples
/// ///
@ -454,6 +454,15 @@ impl Cursive {
self.screen_mut().add_layer(view); self.screen_mut().add_layer(view);
} }
/// Adds a new full-screen layer to the current screen.
///
/// Fullscreen layers have no shadow.
pub fn add_fullscreen_layer<T>(&mut self, view: T)
where T: 'static + View
{
self.screen_mut().add_fullscreen_layer(view);
}
/// Convenient method to remove a layer from the current screen. /// Convenient method to remove a layer from the current screen.
pub fn pop_layer(&mut self) { pub fn pop_layer(&mut self) {
self.screen_mut().pop_layer(); self.screen_mut().pop_layer();

31
src/views/layer.rs Normal file
View File

@ -0,0 +1,31 @@
use Printer;
use view::{View, ViewWrapper};
/// Wrapper view that fills the background.
///
/// Used as layer in the [`StackView`].
///
/// [`StackView`]: struct.StackView.html
pub struct Layer<T: View> {
view: T,
}
impl <T: View> Layer<T> {
/// Wraps the given view.
pub fn new(view: T) -> Self {
Layer {
view: view,
}
}
}
impl<T: View> ViewWrapper for Layer<T> {
wrap_impl!(self.view: T);
fn wrap_draw(&self, printer: &Printer) {
for y in 0..printer.size.y {
printer.print_hline((0, y), printer.size.x, " ");
}
self.view.draw(printer);
}
}

View File

@ -1,5 +1,6 @@
//! Various views to use when creating the layout. //! Various views to use when creating the layout.
/// A macro to help with creating toggleable views.
macro_rules! impl_enabled { macro_rules! impl_enabled {
(self.$x:ident) => { (self.$x:ident) => {
@ -42,6 +43,7 @@ mod dummy;
mod edit_view; mod edit_view;
mod id_view; mod id_view;
mod key_event_view; mod key_event_view;
mod layer;
mod linear_layout; mod linear_layout;
mod list_view; mod list_view;
mod menubar; mod menubar;
@ -66,6 +68,7 @@ pub use self::dummy::DummyView;
pub use self::edit_view::EditView; pub use self::edit_view::EditView;
pub use self::id_view::IdView; pub use self::id_view::IdView;
pub use self::key_event_view::KeyEventView; pub use self::key_event_view::KeyEventView;
pub use self::layer::Layer;
pub use self::linear_layout::LinearLayout; pub use self::linear_layout::LinearLayout;
pub use self::list_view::ListView; pub use self::list_view::ListView;
pub use self::menu_popup::MenuPopup; pub use self::menu_popup::MenuPopup;

View File

@ -70,16 +70,6 @@ impl<T: View> ViewWrapper for ShadowView<T> {
let offset = Vec2::new(self.left_padding as usize, let offset = Vec2::new(self.left_padding as usize,
self.top_padding as usize); self.top_padding as usize);
let printer = &printer.offset(offset, true); let printer = &printer.offset(offset, true);
// Draw the view background
for y in 0..printer.size.y - 1 {
printer.print_hline((0, y), printer.size.x - 1, " ");
}
self.view.draw(&printer.sub_printer(Vec2::zero(),
printer.size - (1, 1),
true));
if printer.theme.shadow { if printer.theme.shadow {
let h = printer.size.y; let h = printer.size.y;
let w = printer.size.x; let w = printer.size.x;
@ -89,5 +79,10 @@ impl<T: View> ViewWrapper for ShadowView<T> {
printer.print_vline((w - 1, 1), h - 1, " "); printer.print_vline((w - 1, 1), h - 1, " ");
}); });
} }
// Draw the view background
let printer =
printer.sub_printer(Vec2::zero(), printer.size - (1, 1), true);
self.view.draw(&printer);
} }
} }

View File

@ -6,20 +6,44 @@ use std::any::Any;
use theme::ColorStyle; use theme::ColorStyle;
use vec::Vec2; use vec::Vec2;
use view::{Offset, Position, Selector, View}; use view::{Offset, Position, Selector, View};
use views::ShadowView; use views::{Layer, ShadowView};
/// Simple stack of views. /// Simple stack of views.
/// Only the top-most view is active and can receive input. /// Only the top-most view is active and can receive input.
pub struct StackView { pub struct StackView {
layers: Vec<Layer>, layers: Vec<Child>,
last_size: Vec2, last_size: Vec2,
} }
struct Layer { enum Placement {
Floating(Position),
Fullscreen,
}
impl Placement {
pub fn compute_offset<S, A, P>(&self, size: S, available: A, parent: P)
-> Vec2
where S: Into<Vec2>,
A: Into<Vec2>,
P: Into<Vec2>
{
match *self {
Placement::Floating(ref position) => {
position.compute_offset(size, available, parent)
}
Placement::Fullscreen => Vec2::zero(),
}
}
}
struct Child {
view: Box<View>, view: Box<View>,
size: Vec2, size: Vec2,
position: Position, placement: Placement,
// Has it received the gift yet?
// We cannot call `take_focus` until we've called `layout()`
// So we want to call `take_focus` right after the first call
// to `layout`; this flag remembers when we've done that.
virgin: bool, virgin: bool,
} }
@ -34,21 +58,38 @@ impl StackView {
} }
} }
/// Adds a new full-screen layer on top of the stack.
///
/// Fullscreen layers have no shadow.
pub fn add_fullscreen_layer<T>(&mut self, view: T)
where T: 'static + View
{
self.layers.push(Child {
view: Box::new(Layer::new(view)),
size: Vec2::zero(),
placement: Placement::Fullscreen,
virgin: true,
});
}
/// Adds new view on top of the stack in the center of the screen. /// Adds new view on top of the stack in the center of the screen.
pub fn add_layer<T: 'static + View>(&mut self, view: T) { pub fn add_layer<T>(&mut self, view: T)
where T: 'static + View
{
self.add_layer_at(Position::center(), view); self.add_layer_at(Position::center(), view);
} }
/// Adds a view on top of the stack. /// Adds a view on top of the stack.
pub fn add_layer_at<T: 'static + View>(&mut self, position: Position, pub fn add_layer_at<T>(&mut self, position: Position, view: T)
view: T) { where T: 'static + View
self.layers.push(Layer { {
self.layers.push(Child {
// Skip padding for absolute/parent-placed views // Skip padding for absolute/parent-placed views
view: Box::new(ShadowView::new(view) view: Box::new(ShadowView::new(Layer::new(view))
.top_padding(position.y == Offset::Center) .top_padding(position.y == Offset::Center)
.left_padding(position.x == Offset::Center)), .left_padding(position.x == Offset::Center)),
size: Vec2::new(0, 0), size: Vec2::new(0, 0),
position: position, placement: Placement::Floating(position),
virgin: true, virgin: true,
}); });
} }
@ -62,7 +103,7 @@ impl StackView {
pub fn offset(&self) -> Vec2 { pub fn offset(&self) -> Vec2 {
let mut previous = Vec2::zero(); let mut previous = Vec2::zero();
for layer in &self.layers { for layer in &self.layers {
let offset = layer.position let offset = layer.placement
.compute_offset(layer.size, self.last_size, previous); .compute_offset(layer.size, self.last_size, previous);
previous = offset; previous = offset;
} }
@ -83,7 +124,7 @@ impl View for StackView {
for (i, v) in self.layers.iter().enumerate() { for (i, v) in self.layers.iter().enumerate() {
// Place the view // Place the view
// Center the view // Center the view
let offset = v.position let offset = v.placement
.compute_offset(v.size, printer.size, previous); .compute_offset(v.size, printer.size, previous);
previous = offset; previous = offset;