oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
4,231 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
        screen_width: u16,
52
        screen_height: u16,
53
    ) -> Result<(), X11Error> {
54
        let max_line_width = (screen_width as i16 / 2 - PADDING * 4).max(300) as u16;
55
        let error_with_instruction = format!("{}\n\nFix the config file and reload.", error_text);
56
        self.lines = self.wrap_text(&error_with_instruction, font, max_line_width);
57
58
        let mut content_width = 0u16;
59
        for line in &self.lines {
60
            let line_width = font.text_width(line);
61
            if line_width > content_width {
62
                content_width = line_width;
63
            }
64
        }
65
66
        let width = content_width + (PADDING as u16 * 2);
67
        let line_height = font.height() + LINE_SPACING as u16;
68
        let height = (self.lines.len() as u16 * line_height) + (PADDING as u16 * 2);
69
70
        let x = ((screen_width - width) / 2) as i16;
71
        let y = ((screen_height - height) / 2) as i16;
72
73
        self.base.configure(connection, x, y, width, height)?;
74
        self.base.show(connection)?;
75
        self.draw(connection, font)?;
76
        Ok(())
77
    }
78
79
    fn wrap_text(&self, text: &str, font: &Font, max_width: u16) -> Vec<String> {
80
        let mut lines = Vec::new();
81
        for paragraph in text.lines() {
82
            if paragraph.trim().is_empty() {
83
                lines.push(String::new());
84
                continue;
85
            }
86
87
            let words: Vec<&str> = paragraph.split_whitespace().collect();
88
            let mut current_line = String::new();
89
90
            for word in words {
91
                let test_line = if current_line.is_empty() {
92
                    word.to_string()
93
                } else {
94
                    format!("{} {}", current_line, word)
95
                };
96
                if font.text_width(&test_line) <= max_width {
97
                    current_line = test_line;
98
                } else {
99
                    if !current_line.is_empty() {
100
                        lines.push(current_line);
101
                    }
102
                    current_line = word.to_string();
103
                }
104
            }
105
            if !current_line.is_empty() {
106
                lines.push(current_line);
107
            }
108
        }
109
        lines
110
    }
111
}
112
113
impl Overlay for ErrorOverlay {
114
    fn window(&self) -> Window {
115
        self.base.window
116
    }
117
118
    fn is_visible(&self) -> bool {
119
        self.base.is_visible
120
    }
121
122
    fn hide(&mut self, connection: &RustConnection) -> Result<(), X11Error> {
123
        self.base.hide(connection)?;
124
        self.lines.clear();
125
        Ok(())
126
    }
127
128
    fn draw(&self, connection: &RustConnection, font: &Font) -> Result<(), X11Error> {
129
        if !self.base.is_visible {
130
            return Ok(());
131
        }
132
        self.base.draw_background(connection)?;
133
        let line_height = font.height() + LINE_SPACING as u16;
134
        let mut y = PADDING + font.ascent();
135
        for line in &self.lines {
136
            self.base
137
                .font_draw
138
                .draw_text(font, self.base.foreground_color, PADDING, y, line);
139
            y += line_height as i16;
140
        }
141
        connection.flush()?;
142
        Ok(())
143
    }
144
}