mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Add position parameter to stack view layers
Can be centered, absolute or relative to the previous layer. Can be set independently for each axis.
This commit is contained in:
parent
985009e51c
commit
87cd1ce23f
@ -1,11 +1,14 @@
|
||||
extern crate cursive;
|
||||
|
||||
use cursive::Cursive;
|
||||
use cursive::view::{IdView, TextView, Dialog, KeyEventView};
|
||||
use cursive::view::{IdView, TextView, Dialog, KeyEventView, Position, Offset};
|
||||
|
||||
fn show_popup(siv: &mut Cursive) {
|
||||
|
||||
siv.add_layer(Dialog::new(TextView::new("Tak!"))
|
||||
// Let's center the popup horizontally, but offset it down a few rows
|
||||
siv.screen_mut()
|
||||
.add_layer_at(Position::new(Offset::Center, Offset::Parent(3)),
|
||||
Dialog::new(TextView::new("Tak!"))
|
||||
.button("Change", |s| {
|
||||
// Look for a view tagged "text". We _know_ it's there, so unwrap it.
|
||||
let view = s.find_id::<TextView>("text").unwrap();
|
||||
|
@ -2,6 +2,15 @@
|
||||
|
||||
#[macro_use]mod view_wrapper;
|
||||
|
||||
// Essentials components
|
||||
mod position;
|
||||
mod request;
|
||||
mod view_path;
|
||||
|
||||
// Helper bases
|
||||
mod scroll;
|
||||
|
||||
// Views
|
||||
mod box_view;
|
||||
mod button;
|
||||
mod dialog;
|
||||
@ -10,14 +19,11 @@ mod full_view;
|
||||
mod id_view;
|
||||
mod key_event_view;
|
||||
mod linear_layout;
|
||||
mod request;
|
||||
mod shadow_view;
|
||||
mod scroll;
|
||||
mod select_view;
|
||||
mod sized_view;
|
||||
mod stack_view;
|
||||
mod text_view;
|
||||
mod view_path;
|
||||
|
||||
|
||||
use std::any::Any;
|
||||
@ -26,6 +32,8 @@ use event::{Event, EventResult};
|
||||
use vec::Vec2;
|
||||
use printer::Printer;
|
||||
|
||||
pub use self::position::{Position, Offset};
|
||||
|
||||
pub use self::request::{DimensionRequest, SizeRequest};
|
||||
pub use self::scroll::ScrollBase;
|
||||
|
||||
|
57
src/view/position.rs
Normal file
57
src/view/position.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use ::vec::{ToVec2, Vec2};
|
||||
|
||||
/// Location of the view on screen
|
||||
pub struct Position {
|
||||
pub x: Offset,
|
||||
pub y: Offset,
|
||||
}
|
||||
|
||||
impl Position {
|
||||
pub fn new(x: Offset, y: Offset) -> Self {
|
||||
Position {
|
||||
x: x,
|
||||
y: y,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn center() -> Self {
|
||||
Position::new(Offset::Center, Offset::Center)
|
||||
}
|
||||
|
||||
pub fn absolute<T: ToVec2>(offset: T) -> Self {
|
||||
let offset = offset.to_vec2();
|
||||
Position::new(Offset::Absolute(offset.x), Offset::Absolute(offset.y))
|
||||
}
|
||||
|
||||
pub fn parent<T: ToVec2>(offset: T) -> Self {
|
||||
let offset = offset.to_vec2();
|
||||
Position::new(Offset::Parent(offset.x), Offset::Parent(offset.y))
|
||||
}
|
||||
|
||||
pub fn compute_offset(&self, size: Vec2, available: Vec2, parent: Vec2) -> Vec2 {
|
||||
Vec2::new(self.x.compute_offset(size.x, available.x, parent.x),
|
||||
self.y.compute_offset(size.y, available.y, parent.y))
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Offset {
|
||||
/// In the center of the screen
|
||||
Center,
|
||||
/// Place top-left corner at the given absolute coordinates
|
||||
Absolute(usize),
|
||||
|
||||
/// Place top-left corner at the given offset from the previous layer's top-left corner.
|
||||
///
|
||||
/// If this is the first layer, behaves like `Absolute`.
|
||||
Parent(usize), // TODO: use a signed vec for negative offset?
|
||||
}
|
||||
|
||||
impl Offset {
|
||||
pub fn compute_offset(&self, size: usize, available: usize, parent: usize) -> usize {
|
||||
match *self {
|
||||
Offset::Center => (available - size) / 2,
|
||||
Offset::Absolute(offset) => offset,
|
||||
Offset::Parent(offset) => parent + offset,
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
use std::any::Any;
|
||||
|
||||
use vec::Vec2;
|
||||
use view::{DimensionRequest, Selector, ShadowView, SizeRequest, View};
|
||||
use view::{DimensionRequest, Selector, ShadowView, SizeRequest, View, Position};
|
||||
use event::{Event, EventResult};
|
||||
use printer::Printer;
|
||||
use theme::ColorStyle;
|
||||
@ -15,6 +15,7 @@ pub struct StackView {
|
||||
struct Layer {
|
||||
view: Box<View>,
|
||||
size: Vec2,
|
||||
position: Position,
|
||||
// Has it received the gift yet?
|
||||
virgin: bool,
|
||||
}
|
||||
@ -31,11 +32,17 @@ impl StackView {
|
||||
StackView { layers: Vec::new() }
|
||||
}
|
||||
|
||||
/// Add new view on top of the stack.
|
||||
/// 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) {
|
||||
self.add_layer_at(Position::center(), view);
|
||||
}
|
||||
|
||||
/// Adds a view on top of the stack.
|
||||
pub fn add_layer_at<T: 'static + View>(&mut self, position: Position, view: T) {
|
||||
self.layers.push(Layer {
|
||||
view: Box::new(ShadowView::new(view)),
|
||||
size: Vec2::new(0, 0),
|
||||
position: position,
|
||||
virgin: true,
|
||||
});
|
||||
}
|
||||
@ -49,13 +56,14 @@ impl StackView {
|
||||
impl View for StackView {
|
||||
fn draw(&mut self, printer: &Printer) {
|
||||
let last = self.layers.len();
|
||||
let mut previous = Vec2::zero();
|
||||
printer.with_color(ColorStyle::Primary, |printer| {
|
||||
for (i, v) in self.layers.iter_mut().enumerate() {
|
||||
// Place the view
|
||||
// Center the view
|
||||
let size = v.size;
|
||||
let offset = (printer.size - size) / 2;
|
||||
// TODO: only draw focus for the top view
|
||||
v.view.draw(&printer.sub_printer(offset, size, i + 1 == last));
|
||||
let offset = v.position.compute_offset(v.size, printer.size, previous);
|
||||
previous = offset;
|
||||
v.view.draw(&printer.sub_printer(offset, v.size, i + 1 == last));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -68,14 +76,20 @@ impl View for StackView {
|
||||
}
|
||||
|
||||
fn layout(&mut self, size: Vec2) {
|
||||
// The call has been made, we can't ask for more space anymore.
|
||||
// Let's make do with what we have.
|
||||
let req = SizeRequest {
|
||||
w: DimensionRequest::AtMost(size.x),
|
||||
h: DimensionRequest::AtMost(size.y),
|
||||
};
|
||||
|
||||
for layer in &mut self.layers {
|
||||
// Give each guy what he asks for, within the budget constraints.
|
||||
layer.size = Vec2::min(size, layer.view.get_min_size(req));
|
||||
layer.view.layout(layer.size);
|
||||
|
||||
// We do it here instead of when adding a new layer because...?
|
||||
// (TODO: try to make it during layer addition)
|
||||
if layer.virgin {
|
||||
layer.view.take_focus();
|
||||
layer.virgin = false;
|
||||
|
Loading…
Reference in New Issue
Block a user