use crate::{
pure::{geometry::Rect, Stack},
stack, Xid,
};
use std::{fmt, mem::swap};
mod messages;
mod transformers;
#[doc(inline)]
pub use messages::{IntoMessage, Message};
#[doc(inline)]
pub use transformers::LayoutTransformer;
pub trait Layout {
fn name(&self) -> String;
fn boxed_clone(&self) -> Box<dyn Layout>;
#[allow(clippy::type_complexity)]
fn layout_workspace(
&mut self,
_tag: &str,
stack: &Option<Stack<Xid>>,
r: Rect,
) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>) {
match stack {
Some(s) => self.layout(s, r),
None => self.layout_empty(r),
}
}
#[allow(clippy::type_complexity)]
fn layout(&mut self, s: &Stack<Xid>, r: Rect) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>);
#[allow(clippy::type_complexity)]
fn layout_empty(&mut self, _r: Rect) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>) {
(None, vec![])
}
fn handle_message(&mut self, m: &Message) -> Option<Box<dyn Layout>>;
}
impl Clone for Box<dyn Layout> {
fn clone(&self) -> Self {
self.boxed_clone()
}
}
impl fmt::Debug for Box<dyn Layout> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Layout")
.field("name", &self.name())
.finish()
}
}
impl fmt::Display for Box<dyn Layout> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Layout({})", self.name())
}
}
pub type LayoutStack = Stack<Box<dyn Layout>>;
impl Default for LayoutStack {
fn default() -> Self {
stack!(Box::new(crate::builtin::layout::MainAndStack::default()))
}
}
impl LayoutStack {
pub fn run_and_replace<F>(&mut self, f: F) -> Vec<(Xid, Rect)>
where
F: FnOnce(&mut Box<dyn Layout>) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>),
{
let (new_focus, rs) = (f)(&mut self.focus);
if let Some(mut new) = new_focus {
self.swap_focus(&mut new);
}
rs
}
pub fn handle_message<M>(&mut self, m: M)
where
M: IntoMessage,
{
let m = m.into_message();
if let Some(mut new) = self.focus.handle_message(&m) {
swap(&mut self.focus, &mut new);
}
}
pub fn broadcast_message<M>(&mut self, m: M)
where
M: IntoMessage,
{
let m = m.into_message();
for l in self.iter_mut() {
if let Some(mut new) = l.handle_message(&m) {
swap(l, &mut new);
}
}
}
}
impl Layout for LayoutStack {
fn name(&self) -> String {
self.focus.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)>) {
(
None,
self.run_and_replace(|l| l.layout_workspace(tag, stack, r)),
)
}
fn layout(&mut self, s: &Stack<Xid>, r: Rect) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>) {
(None, self.run_and_replace(|l| l.layout(s, r)))
}
fn layout_empty(&mut self, r: Rect) -> (Option<Box<dyn Layout>>, Vec<(Xid, Rect)>) {
(None, self.run_and_replace(|l| l.layout_empty(r)))
}
fn handle_message(&mut self, m: &Message) -> Option<Box<dyn Layout>> {
let new_focus = self.focus.handle_message(m);
if let Some(mut new) = new_focus {
self.swap_focus(&mut new);
}
None
}
}