penrose_ui/
layout_viewer.rs1use crate::{Draw, Result};
3use penrose::{
4 Color, WinId,
5 builtin::layout::transformers::Gaps,
6 core::layout::Layout,
7 pure::{Stack, geometry::Rect},
8 x::{Atom, WinType, XConn},
9 x11rb::RustConn,
10};
11use std::{thread::sleep, time::Duration};
12
13const FONT: &str = "mono";
14
15#[derive(Debug)]
18pub struct LayoutViewer {
19 drw: Draw,
20 win: WinId,
21 r: Rect,
22 focused: Color,
23 unfocused: Color,
24 text: Color,
25}
26
27impl LayoutViewer {
28 pub fn new(
30 r: Rect,
31 bg: impl Into<Color>,
32 focused: impl Into<Color>,
33 unfocused: impl Into<Color>,
34 text: impl Into<Color>,
35 ) -> Result<Self> {
36 let mut conn = RustConn::new()?;
37 let screen_rects = conn.screen_details()?;
38 let r_screen = screen_rects.last().unwrap();
39
40 let mut drw = Draw::new(FONT, 14, bg)?;
41 let win = drw.new_window(
42 WinType::InputOutput(Atom::NetWindowTypeDock),
43 r.centered_in(r_screen).unwrap_or(r_screen.shrink_in(30)),
44 false,
45 )?;
46
47 Ok(Self {
48 drw,
49 win,
50 r,
51 focused: focused.into(),
52 unfocused: unfocused.into(),
53 text: text.into(),
54 })
55 }
56
57 pub fn render_layout_with_stack(
60 &mut self,
61 layout: &mut Box<dyn Layout>,
62 stack: &Stack<WinId>,
63 display_ms: u64,
64 ) -> Result<()> {
65 let focus = *stack.focused();
66 let (_, positions) = layout.layout(stack, self.r);
67
68 let mut ctx = self.drw.context_for(self.win)?;
69 ctx.fill_bg(self.r)?;
70
71 for (id, r_w) in positions {
72 let color = if id == focus {
73 self.focused
74 } else {
75 self.unfocused
76 };
77 ctx.fill_rect(r_w, color)?;
78
79 ctx.set_offset(r_w.x + r_w.w as i32 / 2, r_w.y + r_w.h as i32 / 2);
80 ctx.draw_text(&id.to_string(), 0, (0, 0), self.text)?;
81 ctx.reset_offset();
82 }
83
84 self.drw.flush(self.win)?;
85 sleep(Duration::from_millis(display_ms));
86
87 Ok(())
88 }
89
90 pub fn showcase_layouts(
93 &mut self,
94 mut s: Stack<WinId>,
95 layouts: &[Box<dyn Layout>],
96 gap_px: u32,
97 display_ms: u64,
98 ) -> Result<()> {
99 for l in layouts.iter() {
100 let mut l = Gaps::wrap(l.boxed_clone(), gap_px, gap_px);
101 for _ in 0..s.len() {
102 self.render_layout_with_stack(&mut l, &s, display_ms)?;
103 s.focus_down();
104 }
105 }
106
107 Ok(())
108 }
109}