use cursive_core::align::{Align, HAlign, VAlign};
use cursive_core::event::{Event, EventResult};
use cursive_core::view::{View, ViewWrapper};
use cursive_core::{Printer, Rect, Vec2};
pub trait Alignable: View + Sized {
fn align_top_left(self) -> AlignedView<Self> {
AlignedView::with_top_left(self)
}
fn align_top_center(self) -> AlignedView<Self> {
AlignedView::with_top_center(self)
}
fn align_top_right(self) -> AlignedView<Self> {
AlignedView::with_top_right(self)
}
fn align_center_left(self) -> AlignedView<Self> {
AlignedView::with_center_left(self)
}
fn align_center(self) -> AlignedView<Self> {
AlignedView::with_center(self)
}
fn align_center_right(self) -> AlignedView<Self> {
AlignedView::with_center_right(self)
}
fn align_bottom_left(self) -> AlignedView<Self> {
AlignedView::with_bottom_left(self)
}
fn align_bottom_center(self) -> AlignedView<Self> {
AlignedView::with_bottom_center(self)
}
fn align_bottom_right(self) -> AlignedView<Self> {
AlignedView::with_bottom_right(self)
}
}
impl<T: View> Alignable for T {}
pub struct AlignedView<T> {
view: T,
alignment: Align,
last_size: Vec2,
offset: Vec2,
needs_relayout: bool,
}
impl<T: View> AlignedView<T> {
pub fn new(view: T, alignment: Align) -> Self {
Self {
view,
alignment,
last_size: Vec2::new(0, 0),
offset: Vec2::new(0, 0),
needs_relayout: false,
}
}
pub fn with_top_left(view: T) -> Self {
Self::new(view, Align::new(HAlign::Left, VAlign::Top))
}
pub fn with_top_center(view: T) -> Self {
Self::new(view, Align::new(HAlign::Center, VAlign::Top))
}
pub fn with_top_right(view: T) -> Self {
Self::new(view, Align::new(HAlign::Right, VAlign::Top))
}
pub fn with_center_left(view: T) -> Self {
Self::new(view, Align::new(HAlign::Left, VAlign::Center))
}
pub fn with_center(view: T) -> Self {
Self::new(view, Align::new(HAlign::Center, VAlign::Center))
}
pub fn with_center_right(view: T) -> Self {
Self::new(view, Align::new(HAlign::Right, VAlign::Center))
}
pub fn with_bottom_left(view: T) -> Self {
Self::new(view, Align::new(HAlign::Left, VAlign::Bottom))
}
pub fn with_bottom_center(view: T) -> Self {
Self::new(view, Align::new(HAlign::Center, VAlign::Bottom))
}
pub fn with_bottom_right(view: T) -> Self {
Self::new(view, Align::new(HAlign::Right, VAlign::Bottom))
}
pub fn set_top_left(&mut self) {
self.alignment = Align::new(HAlign::Left, VAlign::Top);
self.needs_relayout = true;
}
pub fn set_top_center(&mut self) {
self.alignment = Align::new(HAlign::Center, VAlign::Top);
self.needs_relayout = true;
}
pub fn set_top_right(&mut self) {
self.alignment = Align::new(HAlign::Right, VAlign::Top);
self.needs_relayout = true;
}
pub fn set_center_left(&mut self) {
self.alignment = Align::new(HAlign::Left, VAlign::Center);
self.needs_relayout = true;
}
pub fn set_center(&mut self) {
self.alignment = Align::new(HAlign::Center, VAlign::Center);
self.needs_relayout = true;
}
pub fn set_center_right(&mut self) {
self.alignment = Align::new(HAlign::Right, VAlign::Center);
self.needs_relayout = true;
}
pub fn set_bottom_left(&mut self) {
self.alignment = Align::new(HAlign::Left, VAlign::Bottom);
self.needs_relayout = true;
}
pub fn set_bottom_center(&mut self) {
self.alignment = Align::new(HAlign::Center, VAlign::Bottom);
self.needs_relayout = true;
}
pub fn set_bottom_right(&mut self) {
self.alignment = Align::new(HAlign::Right, VAlign::Bottom);
self.needs_relayout = true;
}
pub fn alignment(&self) -> &Align {
&self.alignment
}
}
impl<T: View> ViewWrapper for AlignedView<T> {
cursive_core::wrap_impl!(self.view: T);
fn wrap_draw(&self, printer: &Printer) {
let offset_printer = printer.offset(self.offset).cropped(self.last_size);
self.view.draw(&offset_printer);
}
fn wrap_layout(&mut self, size: Vec2) {
self.offset = Vec2::new(
self.alignment.h.get_offset(self.last_size.x, size.x),
self.alignment.v.get_offset(self.last_size.y, size.y),
);
let x = std::cmp::min(size.x, self.last_size.x);
let y = std::cmp::min(size.y, self.last_size.y);
self.view.layout(Vec2::new(x, y));
self.needs_relayout = false;
}
fn wrap_needs_relayout(&self) -> bool {
self.needs_relayout || self.view.needs_relayout()
}
fn wrap_required_size(&mut self, constraint: Vec2) -> Vec2 {
self.last_size = self.view.required_size(constraint);
self.last_size
}
fn wrap_on_event(&mut self, ev: Event) -> EventResult {
self.view.on_event(ev.relativized(self.offset))
}
fn wrap_important_area(&self, _: Vec2) -> Rect {
self.view.important_area(self.last_size) + self.offset
}
}
#[cursive_core::blueprint(AlignedView::new(view, alignment))]
struct Blueprint {
view: cursive_core::views::BoxedView,
alignment: Align,
}
cursive_core::manual_blueprint!(with align, |config, context| {
let alignment = context.resolve(config)?;
Ok(move |view| AlignedView::new(view, alignment))
});
cursive_core::manual_blueprint!(with align_top_left, |_config, _context| {
Ok(|view| AlignedView::with_top_left(view))
});
cursive_core::manual_blueprint!(with align_top_center, |_config, _context| {
Ok(|view| AlignedView::with_top_center(view))
});
cursive_core::manual_blueprint!(with align_top_right, |_config, _context| {
Ok(|view| AlignedView::with_top_right(view))
});
cursive_core::manual_blueprint!(with align_center_left, |_config, _context| {
Ok(|view| AlignedView::with_center_left(view))
});
cursive_core::manual_blueprint!(with align_center, |_config, _context| {
Ok(|view| AlignedView::with_center(view))
});
cursive_core::manual_blueprint!(with align_center_right, |_config, _context| {
Ok(|view| AlignedView::with_center_right(view))
});
cursive_core::manual_blueprint!(with align_bottom_left, |_config, _context| {
Ok(|view| AlignedView::with_bottom_left(view))
});
cursive_core::manual_blueprint!(with align_bottom_center, |_config, _context| {
Ok(|view| AlignedView::with_bottom_center(view))
});
cursive_core::manual_blueprint!(with align_bottom_right, |_config, _context| {
Ok(|view| AlignedView::with_bottom_right(view))
});