matchmaker/ui/
preview.rs

1use log::{error};
2use ratatui::{
3    layout::Rect,
4    widgets::{Paragraph, Wrap},
5};
6
7use crate::{
8    config::{PreviewConfig, PreviewLayoutSetting},
9    preview::Preview,
10};
11
12#[derive(Debug)]
13pub struct PreviewUI {
14    pub view: Preview,
15    config: PreviewConfig,
16    pub layout_idx: usize,
17    pub area: Rect,
18    pub offset: u16,
19}
20
21impl PreviewUI {
22    pub fn new(view: Preview, config: PreviewConfig) -> Self {
23        Self {
24            view,
25            config,
26            layout_idx: 0,
27            offset: 0,
28            area: Rect::default()
29        }
30    }
31    pub fn update_dimensions(&mut self, area: &Rect) {
32        let mut height = area.height;
33        height -= self.config.border.height();
34        self.area.height = height;
35
36        let mut width = area.width;
37        width -= self.config.border.width();
38        self.area.width = width;
39    }
40
41    // -------- Layout -----------
42    // None if not show
43    pub fn layout(&self) -> Option<&PreviewLayoutSetting> {
44        if !self.config.show || self.config.layout.is_empty() {
45            None
46        } else {
47            let ret = &self.config.layout[self.layout_idx].layout;
48            if ret.max == 0 {
49                None
50            } else {
51                Some(ret)
52            }
53        }
54    }
55    pub fn command(&self) -> &str {
56        if self.config.layout.is_empty() {
57            ""
58        } else {
59            self.config.layout[self.layout_idx].command.as_str()
60        }
61    }
62    pub fn cycle_layout(&mut self) {
63        self.layout_idx = (self.layout_idx + 1) % self.config.layout.len()
64    }
65    pub fn set_idx(&mut self, idx: u8) -> bool {
66        let idx = idx as usize;
67        if idx <= self.config.layout.len() {
68            let changed = self.layout_idx != idx;
69            self.layout_idx = idx;
70            changed
71        } else {
72            error!("Layout idx {idx} out of bounds, ignoring.");
73            false
74        }
75    }
76
77    // ----- config ---------
78    pub fn is_show(&self) -> bool {
79        self.layout().is_some()
80    }
81    // cheap show toggle + change tracking
82    pub fn show<const SHOW: bool>(&mut self) -> bool {
83        let previous = self.config.show;
84        self.config.show = SHOW;
85        previous != SHOW
86    }
87    pub fn toggle_show(&mut self) {
88        self.config.show = !self.config.show;
89    }
90
91    pub fn wrap(&mut self, wrap: bool) {
92        self.config.wrap = wrap;
93    }
94    pub fn is_wrap(&self) -> bool {
95        self.config.wrap
96    }
97
98
99    // ----- actions --------
100    pub fn up(&mut self, n: u16) {
101        if self.offset >= n {
102            self.offset -= n;
103        } else if self.config.scroll_wrap {
104            let total_lines = self.view.len() as u16;
105            self.offset = total_lines.saturating_sub(n - self.offset);
106        } else {
107            self.offset = 0;
108        }
109    }
110    pub fn down(&mut self, n: u16) {
111        let total_lines = self.view.len() as u16;
112
113        if self.offset + n > total_lines {
114            if self.config.scroll_wrap {
115                self.offset = 0;
116            } else {
117                self.offset = total_lines;
118            }
119        } else {
120            self.offset += n;
121        }
122    }
123
124    pub fn make_preview(&self) -> Paragraph<'_> {
125        let results = self.view.results();
126        let height = self.area.height as usize;
127        let offset = self.offset as usize;
128
129        // todo: can we avoid cloning?
130        let visible_lines: Vec<_> = results
131        .iter()
132        .skip(offset)
133        .take(height)
134        .cloned()
135        .collect();
136
137        let mut preview = Paragraph::new(visible_lines);
138        preview = preview.block(self.config.border.as_block());
139        if self.config.wrap {
140            preview = preview.wrap(Wrap { trim: true });
141        }
142        preview
143    }
144}