cursive_extras/views/
mod.rs1use cursive_core::{
2 theme::{Color, ColorStyle, BaseColor},
3 views::{DummyView, ResizedView},
4 View,
5 Printer,
6 Vec2,
7 utils::markup::StyledString
8};
9use rust_utils::{encapsulated, new_default};
10use std::{
11 time::Instant,
12 fmt::Display
13};
14
15mod loading;
16pub use loading::LoadingAnimation;
17
18mod lazy_view;
19pub use lazy_view::LazyView;
20
21#[cfg(feature = "image_view")]
22mod image_view;
23
24#[cfg(feature = "image_view")]
25pub use image_view::ImageView;
26
27#[cfg(feature = "tabs")]
28mod tabs;
29
30#[cfg(feature = "tabs")]
31pub use tabs::*;
32
33#[cfg(feature = "advanced")]
34mod advanced;
35
36#[cfg(feature = "advanced")]
37pub use advanced::*;
38
39#[cfg(feature = "log_view")]
40mod log_view;
41
42#[cfg(feature = "log_view")]
43pub use log_view::*;
44
45use crate::SpannedStrExt;
46
47pub type Spacer = ResizedView<DummyView>;
51
52#[derive(Copy, Clone, Eq, PartialEq)]
55enum DividerSize {
56 Free,
57 Fixed(usize)
58}
59
60#[derive(Copy, Clone)]
87pub struct HDivider(DividerSize, usize);
88
89impl HDivider {
90 pub fn new() -> HDivider { HDivider(DividerSize::Free, 0) }
92
93 pub fn fixed(height: usize) -> HDivider {
95 HDivider(DividerSize::Fixed(height), height)
96 }
97
98 pub fn height(&self) -> usize {
99 self.1
100 }
101}
102
103impl View for HDivider {
104 fn draw(&self, printer: &Printer) {
105 let height = if let DividerSize::Fixed(height) = self.0 {
106 height
107 }
108 else { printer.size.y };
109
110 printer.with_high_border(false, |printer| printer.print_vline((0, 0), height, "│"));
111 }
112
113 fn required_size(&mut self, _bound: Vec2) -> Vec2 {
114 if let DividerSize::Fixed(height) = self.0 {
115 Vec2::new(1, height)
116 }
117 else {
118 Vec2::new(1, 1)
119 }
120 }
121
122 fn layout(&mut self, size: Vec2) {
123 if self.0 == DividerSize::Free {
124 self.1 = size.y;
125 }
126 }
127}
128
129new_default!(HDivider);
130
131#[derive(Copy, Clone)]
158pub struct VDivider(DividerSize, usize);
159
160impl VDivider {
161 pub fn new() -> VDivider { VDivider(DividerSize::Free, 0) }
163
164 pub fn fixed(width: usize) -> VDivider {
166 VDivider(DividerSize::Fixed(width), width)
167 }
168
169 pub fn width(&self) -> usize {
170 self.1
171 }
172}
173
174impl View for VDivider {
175 fn draw(&self, printer: &Printer) {
176 let width = if let DividerSize::Fixed(width) = self.0 {
177 width
178 }
179 else { printer.size.x };
180 printer.with_high_border(false, |printer| printer.print_hline((0, 0), width, "─"));
181 }
182
183 fn required_size(&mut self, _bound: Vec2) -> Vec2 {
184 if let DividerSize::Fixed(width) = self.0 {
185 Vec2::new(width, 1)
186 }
187 else {
188 Vec2::new(1, 1)
189 }
190 }
191
192 fn layout(&mut self, size: Vec2) {
193 if self.0 == DividerSize::Free {
194 self.1 = size.x;
195 }
196 }
197}
198
199new_default!(VDivider);
200
201#[derive(Clone)]
250#[encapsulated]
251pub struct StatusView {
252 #[setter(use_into_impl, doc = "Set the label of the [`StatusView`]")]
253 #[chainable(use_into_impl)]
254 label: StyledString,
255
256 cur_msg: StyledString,
257 time: Instant,
258 error: bool
259}
260
261impl StatusView {
262 pub fn new() -> StatusView {
264 StatusView {
265 label: StyledString::new(),
266 cur_msg: StyledString::new(),
267 time: Instant::now(),
268 error: false
269 }
270 }
271
272 pub fn report_error<T: Display>(&mut self, text: T) {
274 let err_style = ColorStyle::from(Color::Light(BaseColor::Red));
275 self.cur_msg = StyledString::styled(text.to_string(), err_style);
276 self.time = Instant::now();
277 self.error = true;
278 }
279
280 pub fn info<T: Into<StyledString>>(&mut self, text: T) {
282 self.cur_msg = text.into();
283 self.time = Instant::now();
284 }
285}
286
287impl Default for StatusView {
288 fn default() -> StatusView { StatusView::new() }
289}
290
291impl View for StatusView {
292 fn draw(&self, printer: &Printer) {
293 if printer.size.x == 0 && printer.size.y == 0 {
294 return;
295 }
296
297 if self.cur_msg.is_empty() {
298 if !self.label.is_empty() {
299 printer.print_styled((0, 0), self.label.as_spanned_str());
300 }
301 }
302 else {
303 printer.print_styled((0, 0), self.cur_msg.as_spanned_str());
304 }
305 }
306
307 fn required_size(&mut self, bound: Vec2) -> Vec2 {
308 let y = (!self.cur_msg.is_empty() || !self.label.is_empty()) as usize;
309 Vec2::new(bound.x, y)
310 }
311
312 fn layout(&mut self, _: Vec2) {
313 if self.time.elapsed().as_secs() >= 5 {
314 self.cur_msg = StyledString::new();
315 self.time = Instant::now();
316 self.error = false;
317 }
318 }
319}