diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 137 |
1 files changed, 111 insertions, 26 deletions
diff --git a/src/main.rs b/src/main.rs index a9ea9b1..3d819d2 100644 --- a/src/main.rs +++ b/src/main.rs | |||
@@ -5,8 +5,8 @@ use std::f64; | |||
5 | 5 | ||
6 | use cursive::direction::Direction; | 6 | use cursive::direction::Direction; |
7 | use cursive::event::{Event, EventResult, Key}; | 7 | use cursive::event::{Event, EventResult, Key}; |
8 | use cursive::view::View; | 8 | use cursive::view::{View, ViewWrapper}; |
9 | use cursive::views::{Dialog, EditView, LinearLayout, ListView, SelectView}; | 9 | //use cursive::views::{Dialog, EditView, LinearLayout, ListView, SelectView}; |
10 | use cursive::Cursive; | 10 | use cursive::Cursive; |
11 | use cursive::{Printer, Vec2}; | 11 | use cursive::{Printer, Vec2}; |
12 | 12 | ||
@@ -27,9 +27,9 @@ enum ViewMode { | |||
27 | 27 | ||
28 | struct App { | 28 | struct App { |
29 | habits: Vec<HabitView>, | 29 | habits: Vec<HabitView>, |
30 | status: String, | ||
31 | view_mode: ViewMode, | 30 | view_mode: ViewMode, |
32 | focus: usize, | 31 | focus: usize, |
32 | grid_width: usize, | ||
33 | 33 | ||
34 | padding: usize, | 34 | padding: usize, |
35 | } | 35 | } |
@@ -38,27 +38,55 @@ impl App { | |||
38 | fn new() -> Self { | 38 | fn new() -> Self { |
39 | return App { | 39 | return App { |
40 | habits: vec![], | 40 | habits: vec![], |
41 | status: "".to_string(), | ||
42 | view_mode: ViewMode::Day, | 41 | view_mode: ViewMode::Day, |
43 | focus: 0, | 42 | focus: 0, |
44 | padding: 2, | 43 | grid_width: 3, |
44 | padding: 12, | ||
45 | }; | 45 | }; |
46 | } | 46 | } |
47 | fn add_habit(&mut self, h: HabitView) -> &mut Self { | 47 | fn add_habit(mut self, h: HabitView) -> Self { |
48 | self.habits.push(h); | 48 | self.habits.push(h); |
49 | return self; | 49 | return self; |
50 | } | 50 | } |
51 | fn set_mode(&mut self, set_mode: ViewMode) -> &mut Self { | 51 | fn set_mode(mut self, set_mode: ViewMode) -> Self { |
52 | if set_mode != self.view_mode { | 52 | if set_mode != self.view_mode { |
53 | self.view_mode = set_mode | 53 | self.view_mode = set_mode |
54 | } | 54 | } |
55 | return self; | 55 | return self; |
56 | } | 56 | } |
57 | } | 57 | fn focus_right(&mut self) { |
58 | 58 | if self.focus != self.habits.len() - 1 { | |
59 | impl View for App { | 59 | self.focus += 1; |
60 | fn draw(&self, printer: &Printer) { | 60 | } |
61 | let grid_width = 3; | 61 | } |
62 | fn focus_left(&mut self) { | ||
63 | if self.focus != 0 { | ||
64 | self.focus -= 1; | ||
65 | } | ||
66 | } | ||
67 | fn focus_down(&mut self) { | ||
68 | if self.focus + self.grid_width < self.habits.len() - 1 { | ||
69 | self.focus += self.grid_width; | ||
70 | } else { | ||
71 | self.focus = self.habits.len() - 1; | ||
72 | } | ||
73 | } | ||
74 | fn focus_up(&mut self) { | ||
75 | if self.focus as isize - self.grid_width as isize >= 0 { | ||
76 | self.focus -= self.grid_width; | ||
77 | } else { | ||
78 | self.focus = 0; | ||
79 | } | ||
80 | } | ||
81 | fn status(&self) -> String { | ||
82 | return format!( | ||
83 | "{} total, {} remaining", | ||
84 | self.habits.iter().map(|h| h.total()).sum::<u32>(), | ||
85 | self.habits.iter().map(|h| h.remaining()).sum::<u32>() | ||
86 | ); | ||
87 | } | ||
88 | fn max_size(&self) -> Vec2 { | ||
89 | let grid_width = self.grid_width; | ||
62 | let width = { | 90 | let width = { |
63 | if self.habits.len() > 0 { | 91 | if self.habits.len() > 0 { |
64 | grid_width * self.habits[0].get_size().x | 92 | grid_width * self.habits[0].get_size().x |
@@ -68,27 +96,77 @@ impl View for App { | |||
68 | }; | 96 | }; |
69 | let height = { | 97 | let height = { |
70 | if self.habits.len() > 0 { | 98 | if self.habits.len() > 0 { |
71 | (self.habits[0].get_size().y as f64 / grid_width as f64).ceil() as usize | 99 | (self.habits[0].get_size().y as f64 |
100 | * (self.habits.len() as f64 / grid_width as f64).ceil()) | ||
101 | as usize | ||
72 | } else { | 102 | } else { |
73 | 0 | 103 | 0 |
74 | } | 104 | } |
75 | }; | 105 | }; |
76 | let mut offset = Vec2::new(width + self.padding, height + self.padding); | 106 | Vec2::new(width, height) |
107 | } | ||
108 | } | ||
109 | |||
110 | impl cursive::view::View for App { | ||
111 | fn draw(&self, printer: &Printer) { | ||
112 | let grid_width = self.grid_width; | ||
113 | let mut offset = Vec2::zero(); | ||
77 | for (idx, i) in self.habits.iter().enumerate() { | 114 | for (idx, i) in self.habits.iter().enumerate() { |
115 | if idx >= grid_width && idx % grid_width == 0 { | ||
116 | offset = offset.map_y(|y| y + i.get_size().y).map_x(|_| 0); | ||
117 | } | ||
78 | i.draw(&printer.offset(offset).focused(self.focus == idx)); | 118 | i.draw(&printer.offset(offset).focused(self.focus == idx)); |
79 | offset = offset.saturating_add(i.get_size()); | 119 | offset = offset.map_x(|x| x + i.get_size().x); |
80 | } | 120 | } |
121 | offset = offset.map_x(|_| 0).map_y(|_| self.max_size().y - 2); | ||
122 | printer.print(offset, &self.status()); | ||
81 | } | 123 | } |
124 | |||
82 | fn required_size(&mut self, _: Vec2) -> Vec2 { | 125 | fn required_size(&mut self, _: Vec2) -> Vec2 { |
83 | todo!() | 126 | let grid_width = self.grid_width; |
127 | let width = { | ||
128 | if self.habits.len() > 0 { | ||
129 | grid_width * self.habits[0].get_size().x | ||
130 | } else { | ||
131 | 0 | ||
132 | } | ||
133 | }; | ||
134 | let height = { | ||
135 | if self.habits.len() > 0 { | ||
136 | (self.habits[0].get_size().y as f64 | ||
137 | * (self.habits.len() as f64 / grid_width as f64).ceil()) | ||
138 | as usize | ||
139 | } else { | ||
140 | 0 | ||
141 | } | ||
142 | }; | ||
143 | Vec2::new(width, height) | ||
84 | } | 144 | } |
85 | 145 | ||
86 | fn take_focus(&mut self, _: Direction) -> bool { | 146 | fn take_focus(&mut self, _: Direction) -> bool { |
87 | todo!() | 147 | false |
88 | } | 148 | } |
89 | 149 | ||
90 | fn on_event(&mut self, e: Event) -> EventResult { | 150 | fn on_event(&mut self, e: Event) -> EventResult { |
91 | todo!() | 151 | match e { |
152 | Event::Key(Key::Right) | Event::Key(Key::Tab) | Event::Char('l') => { | ||
153 | self.focus_right(); | ||
154 | return EventResult::Consumed(None); | ||
155 | } | ||
156 | Event::Key(Key::Left) | Event::Shift(Key::Tab) | Event::Char('h') => { | ||
157 | self.focus_left(); | ||
158 | return EventResult::Consumed(None); | ||
159 | } | ||
160 | Event::Key(Key::Up) | Event::Char('k') => { | ||
161 | self.focus_up(); | ||
162 | return EventResult::Consumed(None); | ||
163 | } | ||
164 | Event::Key(Key::Down) | Event::Char('j') => { | ||
165 | self.focus_down(); | ||
166 | return EventResult::Consumed(None); | ||
167 | } | ||
168 | _ => self.habits[self.focus].on_event(e), | ||
169 | } | ||
92 | } | 170 | } |
93 | } | 171 | } |
94 | 172 | ||
@@ -109,18 +187,25 @@ fn main() { | |||
109 | reading.insert_entry(NaiveDate::from_ymd(2020, 2, 14), HabitType::Bit(false)); | 187 | reading.insert_entry(NaiveDate::from_ymd(2020, 2, 14), HabitType::Bit(false)); |
110 | reading.insert_entry(NaiveDate::from_ymd(2020, 2, 15), HabitType::Bit(true)); | 188 | reading.insert_entry(NaiveDate::from_ymd(2020, 2, 15), HabitType::Bit(true)); |
111 | 189 | ||
112 | let gym_title = gymming.get_name(); | 190 | let mut walking = Habit::new("walk", HabitType::Bit(true)); |
113 | let gym_view = HabitView::new(gymming); | 191 | walking.insert_entry(NaiveDate::from_ymd(2020, 2, 11), HabitType::Bit(true)); |
192 | walking.insert_entry(NaiveDate::from_ymd(2020, 2, 12), HabitType::Bit(false)); | ||
193 | walking.insert_entry(NaiveDate::from_ymd(2020, 2, 13), HabitType::Bit(true)); | ||
194 | walking.insert_entry(NaiveDate::from_ymd(2020, 2, 14), HabitType::Bit(false)); | ||
195 | walking.insert_entry(NaiveDate::from_ymd(2020, 2, 15), HabitType::Bit(true)); | ||
114 | 196 | ||
115 | let read_title = reading.get_name(); | 197 | let gym_view = HabitView::new(gymming); |
116 | let read_view = HabitView::new(reading); | 198 | let read_view = HabitView::new(reading); |
199 | let walk_view = HabitView::new(walking); | ||
117 | 200 | ||
118 | s.add_global_callback('q', |a| a.quit()); | 201 | s.add_global_callback('q', |a| a.quit()); |
119 | s.add_layer( | 202 | let app = App::new() |
120 | LinearLayout::horizontal() | 203 | .add_habit(gym_view) |
121 | .child(Dialog::around(gym_view).title(gym_title)) | 204 | .add_habit(read_view) |
122 | .child(Dialog::around(read_view).title(read_title)), | 205 | .add_habit(walk_view) |
123 | ); | 206 | .set_mode(ViewMode::Month); |
207 | |||
208 | s.add_layer(app); | ||
124 | 209 | ||
125 | s.set_theme(theme::theme_gen()); | 210 | s.set_theme(theme::theme_gen()); |
126 | s.run(); | 211 | s.run(); |