1pub use crate::{
2 border::*,
3 border_styles::*,
4 buffer, enums, get_aligned_position, handle_fill,
5 prelude::{self, Rect as R, Widget},
6 structs::{
7 self, border_segment, border_symbols,
8 border_symbols::SegmentSet as SS, gradient,
9 },
10 style::{Color, Style},
11 text::{self, Line},
12 types::{G, T},
13 widgets::{
14 self,
15 block::{self, title::Position},
16 Block, Borders, Paragraph, WidgetRef,
17 },
18};
19use std::rc::Rc;
20pub struct GradientBlock<'a> {
25 pub fill: Line<'a>,
26 pub titles: Vec<T<'a>>,
27 pub bg: Option<Color>,
28 pub border_segments: border_segment::BorderSegments,
29}
30
31impl Default for GradientBlock<'_> {
32 fn default() -> Self {
33 Self::new()
34 }
35}
36
37impl GradientBlock<'_> {
38 pub fn new() -> Self {
39 Self {
40 fill: Line::raw(""),
41 titles: Vec::new(),
42 bg: None,
43 border_segments: border_segment::BorderSegments::new(),
44 }
45 }
46 fn render_block(&self, area: Rc<R>, buf: &mut buffer::Buffer) {
48 if self.border_segments.left.should_be_rendered {
49 Self::render_left(self, *area, buf);
50 }
51 if self.border_segments.right.should_be_rendered {
52 Self::render_right(self, *area, buf);
53 }
54 if self.border_segments.top.should_be_rendered {
55 Self::render_top(self, *area, buf);
56 }
57 if self.border_segments.bottom.should_be_rendered {
58 Self::render_bottom(self, *area, buf);
59 }
60 }
61 fn render_top(&self, area: R, buf: &mut buffer::Buffer) {
74 self.border_segments.top.seg.render_ref(area, buf);
75 }
76
77 fn render_left(&self, area: R, buf: &mut buffer::Buffer) {
91 self.border_segments.left.seg.render_ref(area, buf);
92 }
93
94 fn render_bottom(&self, area: R, buf: &mut buffer::Buffer) {
107 self.border_segments.bottom.seg.render_ref(area, buf);
108 }
109
110 fn render_right(&self, area: R, buf: &mut buffer::Buffer) {
123 self.border_segments.right.seg.render_ref(area, buf);
124 }
125
126 fn render_titles(&self, area: Rc<R>, buf: &mut buffer::Buffer) {
128 for (title, pos) in &self.titles {
129 let padding = match pos {
130 Position::Top => self.border_segments.top.seg.padding,
131 Position::Bottom => {
132 self.border_segments.bottom.seg.padding
133 }
134 };
135 let marg = self.border_segments.top.seg.area_margin;
136 let x = get_aligned_position!(
137 *area,
138 title.alignment,
139 title.width() as u16,
140 padding.left,
141 padding.right
142 )
143 .saturating_add(marg.horizontal / 2);
144 let y = match pos {
145 Position::Top => area
146 .top()
147 .saturating_add(padding.top)
148 .saturating_add(marg.horizontal),
149
150 Position::Bottom => area
151 .bottom()
152 .saturating_sub(padding.bottom)
153 .saturating_sub(marg.vertical),
154 };
155
156 buf.set_line(x, y, title, area.width);
157 }
158 }
159
160 fn render_fill(&self, area: Rc<R>, buf: &mut buffer::Buffer) {
162 Paragraph::new(self.fill.clone())
163 .wrap(widgets::Wrap { trim: true })
164 .block(Block::default().borders(Borders::ALL))
165 .render(*area, buf);
166 }
167
168 pub fn main(
171 &self,
172 area: &prelude::Rect,
173 buf: &mut buffer::Buffer,
174 ) {
175 let area_rc = Rc::new(*area);
176 if !self.fill.spans.is_empty() {
177 self.render_fill(Rc::clone(&area_rc), buf);
178 }
179 self.render_block(Rc::clone(&area_rc), buf);
180 self.render_titles(Rc::clone(&area_rc), buf);
181 if let Some(bg) = self.bg {
182 buf.set_style(*(Rc::clone(&area_rc)), bg);
183 }
184 }
185}
186
187impl widgets::Widget for GradientBlock<'_> {
188 fn render(self, area: prelude::Rect, buf: &mut buffer::Buffer) {
190 self.render_ref(area, buf);
191 }
192}
193impl widgets::WidgetRef for GradientBlock<'_> {
194 fn render_ref(&self, area: R, buf: &mut buffer::Buffer) {
195 self.main(&area, buf);
196 }
197}