rat_widget/
shadow.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//!
//! Draw a shadow around a widget.
//!
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::style::Style;
use ratatui::widgets::StatefulWidget;
#[cfg(feature = "unstable-widget-ref")]
use ratatui::widgets::StatefulWidgetRef;

/// Direction of the shadow.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum ShadowDirection {
    #[default]
    BottomRight,
    BottomLeft,
    TopRight,
    TopLeft,
}

/// Draw a shadow around a widget.
///
/// render is called with the area of the original widget,
/// and this renders just outside of it.
/// It sets the style of the cells to the given style
/// but leaves the text-content untouched.
///
#[derive(Debug, Default, Clone)]
pub struct Shadow {
    style: Style,
    dir: ShadowDirection,
}

impl Shadow {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn style(mut self, style: Style) -> Self {
        self.style = style;
        self
    }

    pub fn direction(mut self, direction: ShadowDirection) -> Self {
        self.dir = direction;
        self
    }
}

// todo: style

#[cfg(feature = "unstable-widget-ref")]
impl StatefulWidgetRef for Shadow {
    type State = ();

    fn render_ref(&self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
        render_ref(&self, area, buf, state);
    }
}

impl StatefulWidget for Shadow {
    type State = ();

    fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
        render_ref(&self, area, buf, state);
    }
}

fn render_ref(widget: &Shadow, area: Rect, buf: &mut Buffer, _state: &mut ()) {
    match widget.dir {
        ShadowDirection::BottomRight => {
            for y in area.top() + 1..area.bottom() + 1 {
                if let Some(cell) = buf.cell_mut((area.right(), y)) {
                    cell.set_style(widget.style);
                }
            }
            for x in area.left() + 1..area.right() {
                if let Some(cell) = buf.cell_mut((x, area.bottom())) {
                    cell.set_style(widget.style);
                }
            }
        }
        ShadowDirection::BottomLeft => {
            if area.left() > 0 {
                for y in area.top() + 1..area.bottom() + 1 {
                    if let Some(cell) = buf.cell_mut((area.left() - 1, y)) {
                        cell.set_style(widget.style);
                    }
                }
            }
            for x in area.left()..area.right().saturating_sub(1) {
                if let Some(cell) = buf.cell_mut((x, area.bottom())) {
                    cell.set_style(widget.style);
                }
            }
        }
        ShadowDirection::TopRight => {
            for y in area.top().saturating_sub(1)..area.bottom().saturating_sub(1) {
                if let Some(cell) = buf.cell_mut((area.right(), y)) {
                    cell.set_style(widget.style);
                }
            }
            if area.top() > 0 {
                for x in area.left() + 1..area.right() {
                    if let Some(cell) = buf.cell_mut((x, area.top() - 1)) {
                        cell.set_style(widget.style);
                    }
                }
            }
        }
        ShadowDirection::TopLeft => {
            if area.left() > 0 {
                for y in area.top().saturating_sub(1)..area.bottom().saturating_sub(1) {
                    if let Some(cell) = buf.cell_mut((area.left() - 1, y)) {
                        cell.set_style(widget.style);
                    }
                }
            }
            if area.top() > 0 {
                for x in area.left()..area.right().saturating_sub(1) {
                    if let Some(cell) = buf.cell_mut((x, area.top() - 1)) {
                        cell.set_style(widget.style);
                    }
                }
            }
        }
    }
}