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,
19 pub offset: u16,
20}
21
22impl PreviewUI {
23 pub fn new(view: Preview, config: PreviewConfig) -> Self {
24 Self {
25 view,
26 config,
27 layout_idx: 0,
28 offset: 0,
29 area: Rect::default(),
30 }
31 }
32 pub fn update_dimensions(&mut self, area: &Rect) {
33 let mut height = area.height;
34 height -= self.config.border.height();
35 self.area.height = height;
36
37 let mut width = area.width;
38 width -= self.config.border.width();
39 self.area.width = width;
40 }
41
42 pub fn layout(&self) -> Option<&PreviewLayoutSetting> {
45 if !self.config.show || self.config.layout.is_empty() {
46 None
47 } else {
48 let ret = &self.config.layout[self.layout_idx].layout;
49 if ret.max == 0 { None } else { Some(ret) }
50 }
51 }
52 pub fn command(&self) -> &str {
53 if self.config.layout.is_empty() {
54 ""
55 } else {
56 self.config.layout[self.layout_idx].command.as_str()
57 }
58 }
59 pub fn cycle_layout(&mut self) {
60 self.layout_idx = (self.layout_idx + 1) % self.config.layout.len()
61 }
62 pub fn set_idx(&mut self, idx: u8) -> bool {
63 let idx = idx as usize;
64 if idx <= self.config.layout.len() {
65 let changed = self.layout_idx != idx;
66 self.layout_idx = idx;
67 changed
68 } else {
69 error!("Layout idx {idx} out of bounds, ignoring.");
70 false
71 }
72 }
73
74 pub fn is_show(&self) -> bool {
76 self.layout().is_some()
77 }
78 pub fn show<const SHOW: bool>(&mut self) -> bool {
80 let previous = self.config.show;
81 self.config.show = SHOW;
82 previous != SHOW
83 }
84 pub fn toggle_show(&mut self) {
85 self.config.show = !self.config.show;
86 }
87
88 pub fn wrap(&mut self, wrap: bool) {
89 self.config.wrap = wrap;
90 }
91 pub fn is_wrap(&self) -> bool {
92 self.config.wrap
93 }
94
95 pub fn up(&mut self, n: u16) {
97 if self.offset >= n {
98 self.offset -= n;
99 } else if self.config.scroll_wrap {
100 let total_lines = self.view.len() as u16;
101 self.offset = total_lines.saturating_sub(n - self.offset);
102 } else {
103 self.offset = 0;
104 }
105 }
106 pub fn down(&mut self, n: u16) {
107 let total_lines = self.view.len() as u16;
108
109 if self.offset + n > total_lines {
110 if self.config.scroll_wrap {
111 self.offset = 0;
112 } else {
113 self.offset = total_lines;
114 }
115 } else {
116 self.offset += n;
117 }
118 }
119
120 pub fn make_preview(&self) -> Paragraph<'_> {
121 let results = self.view.results();
122 let height = self.area.height as usize;
123 let offset = self.offset as usize;
124
125 let visible_lines: Vec<_> = results.iter().skip(offset).take(height).cloned().collect();
127
128 let mut preview = Paragraph::new(visible_lines);
129 preview = preview.block(self.config.border.as_block());
130 if self.config.wrap {
131 preview = preview.wrap(Wrap { trim: true });
132 }
133 preview
134 }
135}