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 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 pub fn is_show(&self) -> bool {
79 self.layout().is_some()
80 }
81 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 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 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}