oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
4,376 bytes raw
1
use super::{Overlay, OverlayBase};
2
use crate::bar::font::Font;
3
use crate::errors::X11Error;
4
use x11rb::connection::Connection;
5
use x11rb::protocol::xproto::*;
6
use x11rb::rust_connection::RustConnection;
7
8
const PADDING: i16 = 20;
9
const LINE_SPACING: i16 = 5;
10
const BORDER_WIDTH: u16 = 2;
11
const BORDER_COLOR: u32 = 0xff5555;
12
13
pub struct ErrorOverlay {
14
    base: OverlayBase,
15
    lines: Vec<String>,
16
}
17
18
impl ErrorOverlay {
19
    pub fn new(
20
        connection: &RustConnection,
21
        screen: &Screen,
22
        screen_num: usize,
23
        display: *mut x11::xlib::Display,
24
        _font: &Font,
25
        _max_width: u16,
26
    ) -> Result<Self, X11Error> {
27
        let base = OverlayBase::new(
28
            connection,
29
            screen,
30
            screen_num,
31
            display,
32
            400,
33
            200,
34
            BORDER_WIDTH,
35
            BORDER_COLOR,
36
            0x1a1a1a,
37
            0xffffff,
38
        )?;
39
40
        Ok(ErrorOverlay {
41
            base,
42
            lines: Vec::new(),
43
        })
44
    }
45
46
    pub fn show_error(
47
        &mut self,
48
        connection: &RustConnection,
49
        font: &Font,
50
        error_text: &str,
51
        monitor_x: i16,
52
        monitor_y: i16,
53
        screen_width: u16,
54
        screen_height: u16,
55
    ) -> Result<(), X11Error> {
56
        let max_line_width = (screen_width as i16 / 2 - PADDING * 4).max(300) as u16;
57
        let error_with_instruction = format!("{}\n\nFix the config file and reload.", error_text);
58
        self.lines = self.wrap_text(&error_with_instruction, font, max_line_width);
59
60
        let mut content_width = 0u16;
61
        for line in &self.lines {
62
            let line_width = font.text_width(line);
63
            if line_width > content_width {
64
                content_width = line_width;
65
            }
66
        }
67
68
        let width = content_width + (PADDING as u16 * 2);
69
        let line_height = font.height() + LINE_SPACING as u16;
70
        let height = (self.lines.len() as u16 * line_height) + (PADDING as u16 * 2);
71
72
        let x = monitor_x + ((screen_width - width) / 2) as i16;
73
        let y = monitor_y + ((screen_height - height) / 2) as i16;
74
75
        self.base.configure(connection, x, y, width, height)?;
76
        self.base.is_visible = true;
77
        self.draw(connection, font)?;
78
        self.base.show(connection)?;
79
        Ok(())
80
    }
81
82
    fn wrap_text(&self, text: &str, font: &Font, max_width: u16) -> Vec<String> {
83
        let mut lines = Vec::new();
84
        for paragraph in text.lines() {
85
            if paragraph.trim().is_empty() {
86
                lines.push(String::new());
87
                continue;
88
            }
89
90
            let words: Vec<&str> = paragraph.split_whitespace().collect();
91
            let mut current_line = String::new();
92
93
            for word in words {
94
                let test_line = if current_line.is_empty() {
95
                    word.to_string()
96
                } else {
97
                    format!("{} {}", current_line, word)
98
                };
99
                if font.text_width(&test_line) <= max_width {
100
                    current_line = test_line;
101
                } else {
102
                    if !current_line.is_empty() {
103
                        lines.push(current_line);
104
                    }
105
                    current_line = word.to_string();
106
                }
107
            }
108
            if !current_line.is_empty() {
109
                lines.push(current_line);
110
            }
111
        }
112
        lines
113
    }
114
}
115
116
impl Overlay for ErrorOverlay {
117
    fn window(&self) -> Window {
118
        self.base.window
119
    }
120
121
    fn is_visible(&self) -> bool {
122
        self.base.is_visible
123
    }
124
125
    fn hide(&mut self, connection: &RustConnection) -> Result<(), X11Error> {
126
        self.base.hide(connection)?;
127
        self.lines.clear();
128
        Ok(())
129
    }
130
131
    fn draw(&self, connection: &RustConnection, font: &Font) -> Result<(), X11Error> {
132
        if !self.base.is_visible {
133
            return Ok(());
134
        }
135
        self.base.draw_background(connection)?;
136
        let line_height = font.height() + LINE_SPACING as u16;
137
        let mut y = PADDING + font.ascent();
138
        for line in &self.lines {
139
            self.base
140
                .font_draw
141
                .draw_text(font, self.base.foreground_color, PADDING, y, line);
142
            y += line_height as i16;
143
        }
144
        connection.flush()?;
145
        self.base.font_draw.sync();
146
        Ok(())
147
    }
148
}