Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_tui/src/main.rs

7.5 KiB, 25 runs

created by r1870400018:4716, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1#![forbid(unsafe_code)]
2pub mod app;
3pub mod lib_tui;
4
5use crate::{
6 app::{
7 cfg::AppConfig,
8 constant,
9 log::AppLoggerConsole,
10 },
11 lib_tui::{
12 action::ActionData,
13 draw::window::WindowId,
14 event::AppFlow,
15 render::{
16 CrosstermRenderer,
17 DebugCrosstermRenderer,
18 Drawable,
19 Drawer,
20 Renderer,
21 Sink,
22 When,
23 },
24 text::typ::{
25 HighlightType,
26 TextType,
27 },
28 window::{
29 WindowManager,
30 WindowManagerConfig,
31 },
32 },
33};
34
35use oxedyne_fe2o3_core::{
36 prelude::*,
37 log::{
38 bot::FileConfig,
39 },
40};
41use oxedyne_fe2o3_geom::{
42 rect::AbsRect,
43};
44use oxedyne_fe2o3_text::{
45 Text,
46 lines::TextLines,
47};
48
49use std::{
50 sync::{
51 Arc,
52 RwLock,
53 },
54};
55
56use crossterm::event::{
57 Event,
58 KeyEvent,
59};
60
61
62#[derive(Clone, Debug, Default)]
63pub struct App<'a> {
64 pub cfg: AppConfig,
65 pub log: Arc<RwLock<TextLines<TextType, HighlightType>>>,
66 pub mouse: (u16, u16),
67 pub win_mgr: WindowManager<'a>,
68}
69
70impl App<'_> {
71
72 pub fn new(cfg: Option<AppConfig>) -> Outcome<Self> {
73 let cfg = match cfg {
74 Some(cfg) => cfg,
75 None => AppConfig::default(),
76 };
77 Ok(Self {
78 cfg: cfg.clone(),
79 log: Arc::new(RwLock::new(TextLines::new(vec![Text::new("Log line 1.", None)], None))),
80 win_mgr: res!(WindowManager::new(WindowManagerConfig::from(cfg))),
81 ..Default::default()
82 })
83 }
84
85 pub fn handle_key_press(
86 &mut self,
87 key: KeyEvent,
88 data: Option<ActionData>,
89 )
90 -> Outcome<AppFlow>
91 {
92 self.win_mgr.native_key_handler(key, data)
93 }
94}
95
96fn setup_log(log_level: LogLevel) -> Outcome<()> {
97 let mut log_cfg = log_get_config!();
98 log_cfg.level = log_level;
99 log_cfg.console = None;
100 let file_cfg = FileConfig::new(
101 res!(std::env::current_dir()),
102 "ironic".to_string(),
103 "log".to_string(),
104 0,
105 Some(1_048_576),
106 );
107 let log_path = file_cfg.path();
108 log_cfg.file = Some(file_cfg);
109 log_set_config!(log_cfg);
110 info!("Logging at {:?}", log_path);
111 Ok(())
112}
113
114fn main() -> Outcome<()> {
115
116 const NORMAL_LOG_THRESHOLD: LogLevel = LogLevel::Debug;
117
118 let log_level = res!(LogLevel::from_str("debug"));
119 res!(setup_log(log_level));
120
121 let mut app = res!(App::new(None));
122
123 loop {
124 match if log_level <= NORMAL_LOG_THRESHOLD {
125 let mut app_logger = AppLoggerConsole::new(app.log.clone());
126 let simplex_thread = app_logger.go();
127 set_log_out!(simplex_thread);
128 run(&mut app, CrosstermRenderer::new(std::io::stdout()))
129 } else {
130 run(&mut app, DebugCrosstermRenderer::new(std::io::stdout()))
131 } {
132 Ok(()) => {
133 break;
134 }
135 Err(e) => {
136 error!(e);
137 //if log_level > NORMAL_LOG_THRESHOLD {
138 break;
139 //}
140 }
141 }
142 }
143
144 log_finish_wait!();
145 Ok(())
146}
147
148fn run<S: Sink, R: Renderer<S>>(
149 app: &mut App,
150 renderer: R,
151)
152 -> Outcome<()>
153{
154 trace!("Enter run");
155 res!(app.make_windows(res!(renderer.size())));
156 res!(app.win_mgr.set_focus_by_id(&WindowId::Help));
157
158 let mut drawer = Drawer::new(renderer, app.win_mgr.style_lib.clone(), true);
159 res!(drawer.on());
160
161 let mut refresh_render = true;
162
163 //info!("Window list:");
164 //for (index, name) in app.win_mgr.list_windows() {
165 // info!("{}{}: {}", if index == app.win_mgr.focus { ">" } else { " " }, index, name);
166 //}
167
168 loop {
169
170 let term = AbsRect::from(res!(drawer.rend.size()));
171 let data = ActionData {
172 term: Some(term),
173 ..Default::default()
174 };
175
176 // Render, if we need to.
177 if refresh_render {
178 res!(drawer.rend.clear());
179 for window in app.win_mgr.iter_mut() {
180 if !window.focus {
181 res!(window.render(&mut drawer, When::Later));
182 }
183 }
184 // Display the focal window last.
185 let result = app.win_mgr.get_focal_window_mut();
186 let focal_window = res!(result);
187 res!(focal_window.render(&mut drawer, When::Later));
188
189 res!(app.win_mgr.draw_cursor(&mut drawer, When::Later));
190 res!(drawer.rend.flush());
191 refresh_render = false;
192 }
193
194 if res!(crossterm::event::poll(std::time::Duration::from_millis(
195 constant::MAIN_LOOP_WAIT_MILLIS
196 ))) {
197 match res!(crossterm::event::read()) {
198 Event::Mouse(mouse_event) => {
199 app.mouse = (mouse_event.column, mouse_event.row);
200 //res!(app.append_log(&fmt!("Mouse: ({}, {})", app.mouse.0, app.mouse.1)));
201 //app.windows[0].rect.top_left = Coord::new(app.mouse);
202 }
203 Event::Key(key_event) => {
204 match app.handle_key_press(key_event, Some(data)) {
205 Ok(AppFlow::Quit) => {
206 res!(drawer.off());
207 return Ok(());
208 }
209 Err(e) => {
210 res!(drawer.off());
211 return Err(e);
212 }
213 Ok(AppFlow::CursorOnly) => {
214 // Just update cursor position without full redraw.
215 let result = app.win_mgr.get_focal_window_text_box_mut();
216 if let Some(tbox) = res!(result) {
217 tbox.tview.update_cursor();
218 res!(drawer.rend.set_cursor(tbox.tview.term_cursor, When::Later));
219 if let Some(cursor_style) = tbox.cfg.cursor_style {
220 res!(drawer.rend.set_cursor_style(cursor_style, When::Later));
221 }
222 res!(app.win_mgr.draw_cursor(&mut drawer, When::Later));
223 res!(drawer.rend.flush());
224 }
225 }
226 Ok(AppFlow::FocalWindowRender) => {
227 let result = app.win_mgr.get_focal_window_mut();
228 let focal_window = res!(result);
229
230 //let term = AbsRect::from(res!(drawer.rend.size()));
231 //if let Some(win_rect) = focal_window.view.relative_to(term) {
232 // // win_view is within the terminal view.
233 // res!(drawer.rend.clear_rect(win_rect));
234 //};
235
236 res!(focal_window.render(&mut drawer, When::Later));
237 res!(app.win_mgr.draw_cursor(&mut drawer, When::Later));
238 res!(drawer.rend.flush());
239 }
240 Ok(AppFlow::FullScreenRender) => {
241 // This code is pulled out into the top of the loop so as to provide
242 // initialisation.
243 refresh_render = true;
244 }
245 _ => (),
246 }
247 }
248 _ => (),
249 }
250 }
251 }
252}