use crate::{
builtin::layout::{messages::UnwrapTransformer, Monocle},
core::layout::{messages::Message, Layout},
pure::{geometry::Rect, Stack},
Xid,
};
use std::mem::swap;
pub trait LayoutTransformer: Clone + Sized + 'static {
fn transformed_name(&self) -> String;
fn inner_mut(&mut self) -> &mut Box<dyn Layout>;
fn swap_inner(&mut self, mut new: Box<dyn Layout>) -> Box<dyn Layout> {
swap(self.inner_mut(), &mut new);
new
}
fn unwrap(&mut self) -> Box<dyn Layout> {
self.swap_inner(Box::new(Monocle))
}
fn transform_initial(&self, r: Rect) -> Rect {
r
}
fn transform_positions(&mut self, _r: Rect, positions: Vec<(Xid, Rect)>) -> Vec<(Xid, Rect)> {
positions
}
#[allow(clippy::type_complexity)]
fn run_transform<F>(&mut self, f: F, r: Rect) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>)
where
F: FnOnce(Rect, &mut Box<dyn Layout>) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>),
{
let r = self.transform_initial(r);
let (new, positions) = (f)(r, self.inner_mut());
let transformed = self.transform_positions(r, positions);
if let Some(l) = new {
self.swap_inner(l);
}
(None, transformed)
}
fn passthrough_message(&mut self, m: &Message) -> Option<Box<dyn Layout>> {
if let Some(new) = self.inner_mut().handle_message(m) {
self.swap_inner(new);
}
None
}
}
impl<LT> Layout for LT
where
LT: LayoutTransformer,
{
fn name(&self) -> String {
self.transformed_name()
}
fn boxed_clone(&self) -> Box<dyn Layout> {
Box::new(self.clone())
}
fn layout_workspace(
&mut self,
tag: &str,
stack: &Option<Stack<Xid>>,
r: Rect,
) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>) {
self.run_transform(|r, inner| inner.layout_workspace(tag, stack, r), r)
}
fn layout(&mut self, s: &Stack<Xid>, r: Rect) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>) {
self.run_transform(|r, inner| inner.layout(s, r), r)
}
fn layout_empty(&mut self, r: Rect) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>) {
self.run_transform(|r, inner| inner.layout_empty(r), r)
}
fn handle_message(&mut self, m: &Message) -> Option<Box<dyn Layout>> {
if let Some(&UnwrapTransformer) = m.downcast_ref() {
return Some(self.unwrap());
}
self.passthrough_message(m)
}
}
#[macro_export]
macro_rules! simple_transformer {
(
$(#[$struct_docs:meta])*
$t:ident,
$f:ident,
$prefix:expr
) => {
$(#[$struct_docs])*
#[derive(Debug, Clone)]
pub struct $t(Box<dyn $crate::core::layout::Layout>);
impl $t {
pub fn wrap(
layout: Box<dyn $crate::core::layout::Layout>,
) -> Box<dyn $crate::core::layout::Layout> {
Box::new(Self(layout))
}
}
impl $crate::core::layout::LayoutTransformer for $t {
fn transformed_name(&self) -> String {
format!("{}<{}>", $prefix, self.0.name())
}
fn inner_mut(&mut self) -> &mut Box<dyn $crate::core::layout::Layout> {
&mut self.0
}
fn transform_positions(
&mut self,
r: $crate::pure::geometry::Rect,
positions: Vec<($crate::core::Xid, $crate::pure::geometry::Rect)>,
) -> Vec<($crate::core::Xid, $crate::pure::geometry::Rect)> {
$f(r, positions)
}
}
};
}