atagen

monolith

public
Star0
Watch0
b2274115d1c6841c5e1c429f27c61a4528dc26bd
1
ssh://brewery@pls.lobotomise.me:33/atagen/monolith.git
crates/layout/src/scratchpad.rsRust97 lines3.3 KB
1
use crate::{Layout, Scratchpad, WindowId, centre_in, centred, translate};
2
3
impl Layout {
4
    /// Adds a window to a named scratchpad, creating it. Scratchpad windows
5
    /// float and are shown only by summoning.
6
    pub fn scratchpad_add(&mut self, w: WindowId, name: &str) {
7
        let Some(win) = self.windows.get(w) else {
8
            return;
9
        };
10
        if let Some(s) = win.scratchpad {
11
            self.leave_scratchpad(s, w);
12
        }
13
        self.unplace(w);
14
        let s = match self.scratchpads.iter().position(|sp| sp.name == name) {
15
            Some(s) => s,
16
            None => {
17
                self.scratchpads.push(Scratchpad {
18
                    name: name.into(),
19
                    windows: Vec::new(),
20
                    shown: None,
21
                    output: None,
22
                });
23
                self.scratchpads.len() - 1
24
            }
25
        };
26
        self.scratchpads[s].windows.push(w);
27
        let area = self.windows[w].output.map(|o| self.outputs[o].usable());
28
        let win = &mut self.windows[w];
29
        win.scratchpad = Some(s);
30
        win.floating = true;
31
        if win.float_rect.is_none() {
32
            win.float_rect = area.map(|a| centred(a, 0.6));
33
        }
34
    }
35
36
    /// Cycles a scratchpad through off, each window, and off again, on the
37
    /// active output.
38
    pub fn summon(&mut self, name: &str) -> Option<WindowId> {
39
        let s = self.scratchpads.iter().position(|sp| sp.name == name)?;
40
        let o = self.active?;
41
        let sp = &mut self.scratchpads[s];
42
        let mut next = sp.shown.map_or(0, |i| i + 1);
43
        while sp
44
            .windows
45
            .get(next)
46
            .is_some_and(|&w| self.windows[w].hidden)
47
        {
48
            next += 1;
49
        }
50
        if next >= sp.windows.len() {
51
            sp.shown = None;
52
            return None;
53
        }
54
        let from = sp.output.map(|f| self.outputs[f].usable());
55
        sp.shown = Some(next);
56
        sp.output = Some(o);
57
        let w = sp.windows[next];
58
        self.last_scratchpad = Some(s);
59
        let usable = self.outputs[o].usable();
60
        let win = &mut self.windows[w];
61
        if win.output != Some(o) {
62
            win.float_rect = match (from, win.float_rect) {
63
                (Some(from), Some(r)) => Some(translate(r, from, usable)),
64
                _ => Some(centred(usable, 0.6)),
65
            };
66
            win.output = Some(o);
67
        }
68
        win.float_rect = win.float_rect.map(|r| centre_in(usable, r.w, r.h));
69
        self.focus_unless_covered(w);
70
        Some(w)
71
    }
72
73
    /// Hides a scratchpad, by default the last one summoned.
74
    pub fn dismiss(&mut self, name: Option<&str>) {
75
        let s = match name {
76
            Some(name) => self.scratchpads.iter().position(|sp| sp.name == name),
77
            None => self.last_scratchpad,
78
        };
79
        if let Some(sp) = s.and_then(|s| self.scratchpads.get_mut(s)) {
80
            sp.shown = None;
81
        }
82
    }
83
84
    pub(crate) fn leave_scratchpad(&mut self, s: usize, w: WindowId) {
85
        let sp = &mut self.scratchpads[s];
86
        let Some(i) = sp.windows.iter().position(|&x| x == w) else {
87
            return;
88
        };
89
        sp.windows.remove(i);
90
        sp.shown = match sp.shown {
91
            Some(j) if j == i => None,
92
            Some(j) if j > i => Some(j - 1),
93
            other => other,
94
        };
95
        self.windows[w].scratchpad = None;
96
    }
97
}