penrose/core/layout/
transformers.rs1use crate::{
2 builtin::layout::{messages::UnwrapTransformer, Monocle},
3 core::layout::{messages::Message, Layout},
4 pure::{geometry::Rect, Stack},
5 Xid,
6};
7use std::mem::swap;
8
9pub trait LayoutTransformer: Send + Sync + Clone + Sized + 'static {
12 fn transformed_name(&self) -> String;
14
15 fn inner_mut(&mut self) -> &mut Box<dyn Layout>;
17
18 fn swap_inner(&mut self, mut new: Box<dyn Layout>) -> Box<dyn Layout> {
20 swap(self.inner_mut(), &mut new);
21
22 new
23 }
24
25 fn unwrap(&mut self) -> Box<dyn Layout> {
33 self.swap_inner(Box::new(Monocle))
34 }
35
36 fn transform_initial(&self, r: Rect) -> Rect {
40 r
41 }
42
43 fn transform_positions(&mut self, _r: Rect, positions: Vec<(Xid, Rect)>) -> Vec<(Xid, Rect)> {
50 positions
51 }
52
53 #[allow(clippy::type_complexity)]
55 fn run_transform<F>(&mut self, f: F, r: Rect) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>)
56 where
57 F: FnOnce(Rect, &mut Box<dyn Layout>) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>),
58 {
59 let r = self.transform_initial(r);
60 let (new, positions) = (f)(r, self.inner_mut());
61 let transformed = self.transform_positions(r, positions);
62
63 if let Some(l) = new {
64 self.swap_inner(l);
65 }
66
67 (None, transformed)
68 }
69
70 fn passthrough_message(&mut self, m: &Message) -> Option<Box<dyn Layout>> {
75 if let Some(new) = self.inner_mut().handle_message(m) {
76 self.swap_inner(new);
77 }
78
79 None
80 }
81}
82
83impl<LT> Layout for LT
84where
85 LT: LayoutTransformer,
86{
87 fn name(&self) -> String {
88 self.transformed_name()
89 }
90
91 fn boxed_clone(&self) -> Box<dyn Layout> {
92 Box::new(self.clone())
93 }
94
95 fn layout_workspace(
96 &mut self,
97 tag: &str,
98 stack: &Option<Stack<Xid>>,
99 r: Rect,
100 ) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>) {
101 self.run_transform(|r, inner| inner.layout_workspace(tag, stack, r), r)
102 }
103
104 fn layout(&mut self, s: &Stack<Xid>, r: Rect) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>) {
105 self.run_transform(|r, inner| inner.layout(s, r), r)
106 }
107
108 fn layout_empty(&mut self, r: Rect) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>) {
109 self.run_transform(|r, inner| inner.layout_empty(r), r)
110 }
111
112 fn handle_message(&mut self, m: &Message) -> Option<Box<dyn Layout>> {
113 if let Some(&UnwrapTransformer) = m.downcast_ref() {
114 return Some(self.unwrap());
115 }
116
117 self.passthrough_message(m)
118 }
119}
120
121#[macro_export]
137macro_rules! simple_transformer {
138 (
139 $(#[$struct_docs:meta])*
140 $t:ident,
141 $f:ident,
142 $prefix:expr
143 ) => {
144 $(#[$struct_docs])*
145 #[derive(Debug, Clone)]
146 pub struct $t(Box<dyn $crate::core::layout::Layout>);
147
148 impl $t {
149 pub fn wrap(
151 layout: Box<dyn $crate::core::layout::Layout>,
152 ) -> Box<dyn $crate::core::layout::Layout> {
153 Box::new(Self(layout))
154 }
155 }
156
157 impl $crate::core::layout::LayoutTransformer for $t {
158 fn transformed_name(&self) -> String {
159 format!("{}<{}>", $prefix, self.0.name())
160 }
161
162 fn inner_mut(&mut self) -> &mut Box<dyn $crate::core::layout::Layout> {
163 &mut self.0
164 }
165
166 fn transform_positions(
167 &mut self,
168 r: $crate::pure::geometry::Rect,
169 positions: Vec<($crate::core::Xid, $crate::pure::geometry::Rect)>,
170 ) -> Vec<($crate::core::Xid, $crate::pure::geometry::Rect)> {
171 $f(r, positions)
172 }
173 }
174 };
175}