1use crate::_private::NonExhaustive;
5use ratatui::buffer::Buffer;
6use ratatui::layout::Rect;
7use ratatui::style::Style;
8use ratatui::widgets::StatefulWidget;
9
10#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
12pub enum ShadowDirection {
13 #[default]
14 BottomRight,
15 BottomLeft,
16 TopRight,
17 TopLeft,
18}
19
20#[derive(Debug, Default, Clone)]
28pub struct Shadow {
29 style: Style,
30 dir: ShadowDirection,
31}
32
33impl Shadow {
34 pub fn new() -> Self {
35 Self::default()
36 }
37
38 pub fn styles(mut self, styles: ShadowStyle) -> Self {
39 self.style = styles.style;
40 self.dir = styles.dir;
41 self
42 }
43
44 pub fn style(mut self, style: Style) -> Self {
45 self.style = style;
46 self
47 }
48
49 pub fn direction(mut self, direction: ShadowDirection) -> Self {
50 self.dir = direction;
51 self
52 }
53}
54
55#[derive(Debug, Clone)]
56pub struct ShadowStyle {
57 pub style: Style,
58 pub dir: ShadowDirection,
59 pub non_exhaustive: NonExhaustive,
60}
61
62impl Default for ShadowStyle {
63 fn default() -> Self {
64 Self {
65 style: Default::default(),
66 dir: Default::default(),
67 non_exhaustive: NonExhaustive,
68 }
69 }
70}
71
72impl StatefulWidget for &Shadow {
73 type State = ();
74
75 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
76 render_ref(self, area, buf, state);
77 }
78}
79
80impl StatefulWidget for Shadow {
81 type State = ();
82
83 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
84 render_ref(&self, area, buf, state);
85 }
86}
87
88fn render_ref(widget: &Shadow, area: Rect, buf: &mut Buffer, _state: &mut ()) {
89 match widget.dir {
90 ShadowDirection::BottomRight => {
91 for y in area.top() + 1..area.bottom() + 1 {
92 if let Some(cell) = buf.cell_mut((area.right(), y)) {
93 cell.set_style(widget.style);
94 }
95 }
96 for x in area.left() + 1..area.right() {
97 if let Some(cell) = buf.cell_mut((x, area.bottom())) {
98 cell.set_style(widget.style);
99 }
100 }
101 }
102 ShadowDirection::BottomLeft => {
103 if area.left() > 0 {
104 for y in area.top() + 1..area.bottom() + 1 {
105 if let Some(cell) = buf.cell_mut((area.left() - 1, y)) {
106 cell.set_style(widget.style);
107 }
108 }
109 }
110 for x in area.left()..area.right().saturating_sub(1) {
111 if let Some(cell) = buf.cell_mut((x, area.bottom())) {
112 cell.set_style(widget.style);
113 }
114 }
115 }
116 ShadowDirection::TopRight => {
117 for y in area.top().saturating_sub(1)..area.bottom().saturating_sub(1) {
118 if let Some(cell) = buf.cell_mut((area.right(), y)) {
119 cell.set_style(widget.style);
120 }
121 }
122 if area.top() > 0 {
123 for x in area.left() + 1..area.right() {
124 if let Some(cell) = buf.cell_mut((x, area.top() - 1)) {
125 cell.set_style(widget.style);
126 }
127 }
128 }
129 }
130 ShadowDirection::TopLeft => {
131 if area.left() > 0 {
132 for y in area.top().saturating_sub(1)..area.bottom().saturating_sub(1) {
133 if let Some(cell) = buf.cell_mut((area.left() - 1, y)) {
134 cell.set_style(widget.style);
135 }
136 }
137 }
138 if area.top() > 0 {
139 for x in area.left()..area.right().saturating_sub(1) {
140 if let Some(cell) = buf.cell_mut((x, area.top() - 1)) {
141 cell.set_style(widget.style);
142 }
143 }
144 }
145 }
146 }
147}