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