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;
|
extern crate cursive;
|
||||||
|
|
||||||
use cursive::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) {
|
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| {
|
.button("Change", |s| {
|
||||||
// Look for a view tagged "text". We _know_ it's there, so unwrap it.
|
// Look for a view tagged "text". We _know_ it's there, so unwrap it.
|
||||||
let view = s.find_id::<TextView>("text").unwrap();
|
let view = s.find_id::<TextView>("text").unwrap();
|
||||||
|
@ -2,6 +2,15 @@
|
|||||||
|
|
||||||
#[macro_use]mod view_wrapper;
|
#[macro_use]mod view_wrapper;
|
||||||
|
|
||||||
|
// Essentials components
|
||||||
|
mod position;
|
||||||
|
mod request;
|
||||||
|
mod view_path;
|
||||||
|
|
||||||
|
// Helper bases
|
||||||
|
mod scroll;
|
||||||
|
|
||||||
|
// Views
|
||||||
mod box_view;
|
mod box_view;
|
||||||
mod button;
|
mod button;
|
||||||
mod dialog;
|
mod dialog;
|
||||||
@ -10,14 +19,11 @@ mod full_view;
|
|||||||
mod id_view;
|
mod id_view;
|
||||||
mod key_event_view;
|
mod key_event_view;
|
||||||
mod linear_layout;
|
mod linear_layout;
|
||||||
mod request;
|
|
||||||
mod shadow_view;
|
mod shadow_view;
|
||||||
mod scroll;
|
|
||||||
mod select_view;
|
mod select_view;
|
||||||
mod sized_view;
|
mod sized_view;
|
||||||
mod stack_view;
|
mod stack_view;
|
||||||
mod text_view;
|
mod text_view;
|
||||||
mod view_path;
|
|
||||||
|
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
@ -26,6 +32,8 @@ use event::{Event, EventResult};
|
|||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
|
|
||||||
|
pub use self::position::{Position, Offset};
|
||||||
|
|
||||||
pub use self::request::{DimensionRequest, SizeRequest};
|
pub use self::request::{DimensionRequest, SizeRequest};
|
||||||
pub use self::scroll::ScrollBase;
|
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 std::any::Any;
|
||||||
|
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use view::{DimensionRequest, Selector, ShadowView, SizeRequest, View};
|
use view::{DimensionRequest, Selector, ShadowView, SizeRequest, View, Position};
|
||||||
use event::{Event, EventResult};
|
use event::{Event, EventResult};
|
||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
use theme::ColorStyle;
|
use theme::ColorStyle;
|
||||||
@ -15,6 +15,7 @@ pub struct StackView {
|
|||||||
struct Layer {
|
struct Layer {
|
||||||
view: Box<View>,
|
view: Box<View>,
|
||||||
size: Vec2,
|
size: Vec2,
|
||||||
|
position: Position,
|
||||||
// Has it received the gift yet?
|
// Has it received the gift yet?
|
||||||
virgin: bool,
|
virgin: bool,
|
||||||
}
|
}
|
||||||
@ -31,11 +32,17 @@ impl StackView {
|
|||||||
StackView { layers: Vec::new() }
|
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) {
|
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 {
|
self.layers.push(Layer {
|
||||||
view: Box::new(ShadowView::new(view)),
|
view: Box::new(ShadowView::new(view)),
|
||||||
size: Vec2::new(0, 0),
|
size: Vec2::new(0, 0),
|
||||||
|
position: position,
|
||||||
virgin: true,
|
virgin: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -49,13 +56,14 @@ impl StackView {
|
|||||||
impl View for StackView {
|
impl View for StackView {
|
||||||
fn draw(&mut self, printer: &Printer) {
|
fn draw(&mut self, printer: &Printer) {
|
||||||
let last = self.layers.len();
|
let last = self.layers.len();
|
||||||
|
let mut previous = Vec2::zero();
|
||||||
printer.with_color(ColorStyle::Primary, |printer| {
|
printer.with_color(ColorStyle::Primary, |printer| {
|
||||||
for (i, v) in self.layers.iter_mut().enumerate() {
|
for (i, v) in self.layers.iter_mut().enumerate() {
|
||||||
|
// Place the view
|
||||||
// Center the view
|
// Center the view
|
||||||
let size = v.size;
|
let offset = v.position.compute_offset(v.size, printer.size, previous);
|
||||||
let offset = (printer.size - size) / 2;
|
previous = offset;
|
||||||
// TODO: only draw focus for the top view
|
v.view.draw(&printer.sub_printer(offset, v.size, i + 1 == last));
|
||||||
v.view.draw(&printer.sub_printer(offset, size, i + 1 == last));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -68,14 +76,20 @@ impl View for StackView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn layout(&mut self, size: Vec2) {
|
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 {
|
let req = SizeRequest {
|
||||||
w: DimensionRequest::AtMost(size.x),
|
w: DimensionRequest::AtMost(size.x),
|
||||||
h: DimensionRequest::AtMost(size.y),
|
h: DimensionRequest::AtMost(size.y),
|
||||||
};
|
};
|
||||||
|
|
||||||
for layer in &mut self.layers {
|
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.size = Vec2::min(size, layer.view.get_min_size(req));
|
||||||
layer.view.layout(layer.size);
|
layer.view.layout(layer.size);
|
||||||
|
|
||||||
// We do it here instead of when adding a new layer because...?
|
// We do it here instead of when adding a new layer because...?
|
||||||
|
// (TODO: try to make it during layer addition)
|
||||||
if layer.virgin {
|
if layer.virgin {
|
||||||
layer.view.take_focus();
|
layer.view.take_focus();
|
||||||
layer.virgin = false;
|
layer.virgin = false;
|
||||||
|
Loading…
Reference in New Issue
Block a user