Skip to main content

ratatui_kit/render/
drawer.rs

1use ratatui::{
2    buffer::Buffer,
3    layout::Rect,
4    widgets::{StatefulWidget, Widget},
5};
6
7pub struct ComponentDrawer<'a, 'b: 'a> {
8    pub area: ratatui::layout::Rect,
9    pub frame: &'a mut ratatui::Frame<'b>,
10    // 滚动缓冲栈:每个 ScrollView 进入子绘制前 push 自己的内容缓冲,退出后 pop。
11    // 用栈(而非单槽)才能正确支持 ScrollView 嵌套——内层 pop 后 `buffer_mut`
12    // 自动回到外层缓冲,外层不会因内层 take 走而拿到 None。
13    pub scroll_buffers: Vec<Buffer>,
14}
15
16impl<'a, 'b> ComponentDrawer<'a, 'b> {
17    pub fn new(frame: &'a mut ratatui::Frame<'b>, area: ratatui::layout::Rect) -> Self {
18        Self {
19            area,
20            frame,
21            scroll_buffers: Vec::new(),
22        }
23    }
24
25    pub fn buffer_mut(&mut self) -> &mut ratatui::buffer::Buffer {
26        if let Some(scroll_buffer) = self.scroll_buffers.last_mut() {
27            scroll_buffer
28        } else {
29            self.frame.buffer_mut()
30        }
31    }
32
33    /// Push a fresh content buffer for a `ScrollView` about to draw its children.
34    pub fn push_scroll_buffer(&mut self, buffer: Buffer) {
35        self.scroll_buffers.push(buffer);
36    }
37
38    /// Pop this `ScrollView`'s content buffer after its children have drawn.
39    /// Returns `None` if there is nothing to pop (guards against nesting bugs).
40    pub fn pop_scroll_buffer(&mut self) -> Option<Buffer> {
41        self.scroll_buffers.pop()
42    }
43
44    pub fn render_widget<W: Widget>(&mut self, widget: W, area: Rect) {
45        widget.render(area, self.buffer_mut());
46    }
47
48    pub fn render_stateful_widget<W: StatefulWidget>(
49        &mut self,
50        widget: W,
51        area: Rect,
52        state: &mut W::State,
53    ) {
54        widget.render(area, self.buffer_mut(), state);
55    }
56}