rust_kanban/ui/widgets/
mod.rs1use crate::{app::App, ui::theme::Theme};
2use close_button::CloseButtonWidget;
3use command_palette::CommandPaletteWidget;
4use date_time_picker::{CalenderType, DateTimePickerWidget};
5use ratatui::layout::Rect;
6use std::sync::Arc;
7use tag_picker::TagPickerWidget;
8use toast::ToastWidget;
9
10pub mod close_button;
11pub mod command_palette;
12pub mod date_time_picker;
13pub mod tag_picker;
14pub mod toast;
15
16trait Widget {
17 fn update(app: &mut App);
18}
19
20pub struct WidgetManager<'a> {
21 pub app: Arc<tokio::sync::Mutex<App<'a>>>,
22}
23
24impl WidgetManager<'_> {
25 pub fn new(app: Arc<tokio::sync::Mutex<App>>) -> WidgetManager {
26 WidgetManager { app }
27 }
28
29 pub async fn update(&mut self) {
30 let mut app = self.app.lock().await;
31 ToastWidget::update(&mut app);
32 CommandPaletteWidget::update(&mut app);
33 CloseButtonWidget::update(&mut app);
34 DateTimePickerWidget::update(&mut app);
35 TagPickerWidget::update(&mut app);
36 }
37}
38
39pub struct Widgets<'a> {
40 pub command_palette: CommandPaletteWidget,
41 pub close_button: CloseButtonWidget,
42 pub toast_widget: ToastWidget,
43 pub date_time_picker: DateTimePickerWidget<'a>,
44 pub tag_picker: TagPickerWidget,
45}
46
47impl<'a> Widgets<'a> {
48 pub fn new(theme: Theme, debug_mode: bool, calender_type: CalenderType) -> Self {
49 Self {
50 command_palette: CommandPaletteWidget::new(debug_mode),
51 close_button: CloseButtonWidget::new(theme.general_style),
52 toast_widget: ToastWidget::default(),
53 date_time_picker: DateTimePickerWidget::new(calender_type),
54 tag_picker: TagPickerWidget::default(),
55 }
56 }
57}
58
59#[derive(Debug)]
60enum WidgetAnimState {
61 Closed,
62 Closing,
63 Open,
64 Opening,
65}
66
67impl WidgetAnimState {
68 fn complete_current_stage(&self) -> Self {
69 match self {
70 Self::Closed => Self::Closed,
71 Self::Closing => Self::Closed,
72 Self::Open => Self::Open,
73 Self::Opening => Self::Open,
74 }
75 }
76}
77
78pub trait SelfViewportCorrection {
79 fn get_anchor(&self) -> Option<(u16, u16)>;
80 fn get_last_anchor(&self) -> Option<(u16, u16)>;
81 fn get_viewport_corrected_anchor(&self) -> Option<(u16, u16)>;
82 fn get_last_corrected_viewport(&self) -> Option<Rect>;
83 fn get_current_viewport(&self) -> Option<Rect>;
84 fn set_anchor(&mut self, anchor: Option<(u16, u16)>);
85 fn set_last_anchor(&mut self, anchor: Option<(u16, u16)>);
86 fn set_viewport_corrected_anchor(&mut self, anchor: Option<(u16, u16)>);
87 fn set_last_corrected_viewport(&mut self, anchor: Option<Rect>);
88 fn set_current_viewport(&mut self, anchor: Option<Rect>);
89 fn self_correct(&mut self, target_height: u16, target_width: u16) {
90 if self.get_current_viewport().is_some()
91 && self.get_anchor().is_some()
92 && (self.get_last_corrected_viewport() != self.get_current_viewport()
93 || self.get_last_anchor() != self.get_anchor())
94 {
95 if let (Some(anchor), Some(viewport)) = (self.get_anchor(), self.get_current_viewport())
96 {
97 let mut viewport_corrected_anchor = anchor;
98 if anchor.1 + target_height > viewport.height {
99 viewport_corrected_anchor.1 = viewport_corrected_anchor
100 .1
101 .saturating_sub((anchor.1 + target_height).saturating_sub(viewport.height));
102 }
103 if anchor.0 + target_width > viewport.width {
104 viewport_corrected_anchor.0 = viewport_corrected_anchor
105 .0
106 .saturating_sub((anchor.0 + target_width).saturating_sub(viewport.width));
107 }
108 self.set_viewport_corrected_anchor(Some(viewport_corrected_anchor));
109 self.set_last_corrected_viewport(Some(viewport));
110 }
111 }
112 }
113}