tui_gradient_block/
gradient_block.rs

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;
20/// A struct that represents a customizable block with gradient text, borders, and other visual elements.
21///
22/// This struct allows you to create and manage blocks that have a gradient color effect for text,
23/// customizable borders, and areas with specific alignments and fill styles.
24pub 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    /// Sets the border line segments based on the area and border symbols.
47    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    /// Renders the top segment of the border with an optional gradient
62    /// ## Visual Representation:
63    /// Without the function:
64    /// ```
65    /// +     +
66    /// |     |
67    /// |     |
68    /// +     +
69    /// |     |
70    /// |     |
71    /// +-----+
72    /// ```
73    fn render_top(&self, area: R, buf: &mut buffer::Buffer) {
74        self.border_segments.top.seg.render_ref(area, buf);
75    }
76
77    /// Renders the left segment of the border with an optional gradient
78    /// ## Visual Representation:
79    /// Without the function:
80    /// ```
81    /// +-----+
82    ///       |
83    ///       |
84    ///       |
85    ///       +
86    ///       |
87    ///       |
88    /// +-----+
89    /// ```
90    fn render_left(&self, area: R, buf: &mut buffer::Buffer) {
91        self.border_segments.left.seg.render_ref(area, buf);
92    }
93
94    /// Renders the bottom segment of the border with an optional gradient
95    /// ## Visual Representation:
96    /// Without the function:
97    /// ```
98    /// +--+--+
99    /// |     |
100    /// |     |
101    /// +     +
102    /// |     |
103    /// |     |
104    /// +     +
105    /// ````
106    fn render_bottom(&self, area: R, buf: &mut buffer::Buffer) {
107        self.border_segments.bottom.seg.render_ref(area, buf);
108    }
109
110    /// Renders the right segment of the border with an optional gradient
111    /// ## Visual Representation:
112    /// Without the function:
113    /// ```
114    /// +--+--+
115    /// |     
116    /// |     
117    /// +     
118    /// |     
119    /// |     
120    /// +--+--+
121    /// ```
122    fn render_right(&self, area: R, buf: &mut buffer::Buffer) {
123        self.border_segments.right.seg.render_ref(area, buf);
124    }
125
126    /// Renders the titles for the widget, with an optional gradient
127    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    /// Renders the fill for the widget, including optional gradient rendering.
161    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    /// Renders the `Gradientblock` widget, including optional fill and custom block rendering,
169    /// along with titles.
170    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    /// Renders the `Gradientblock` widget using the `main` function.
189    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}