1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! Basic MinUI example showing window creation and input handling.
//!
//! This example demonstrates the basic concepts of MinUI's app runner pattern:
//! - Creating a terminal window and initializing the application
//! - Handling keyboard events in the event loop
//! - Rendering UI elements to the window
//! - Separating update logic from drawing logic
//!
//! # The App Runner Pattern
//!
//! MinUI uses an **App runner** to manage the main event loop for you. Instead of manually
//! handling terminal setup, event polling, and frame rendering, you provide two closures:
//!
//! 1. **Update closure**: Called for each input event. Your job is to update application state
//! based on the event and return `true` to continue running or `false` to exit.
//!
//! 2. **Draw closure**: Called after the update closure. Your job is to render the current
//! state to the window.
//!
//! This separation of concerns makes it easy to build responsive, event-driven TUI applications.
//!
//! # Example Structure
//!
//! ```ignore
//! let mut app = App::new(initial_state)?; // Create app with state
//!
//! app.run(
//! |state, event| { // Update: handle events
//! // Modify state based on event
//! // Return false to exit
//! true
//! },
//! |state, window| { // Draw: render UI
//! // Use state to draw UI elements
//! Ok(())
//! }
//! )?;
//! ```
//!
//! # State Management
//!
//! The state type is passed to `App::new()`. In this example, we use `()` (unit type)
//! since we don't need to track any state. For more complex applications, you would define
//! a struct and pass an instance of it.
//!
//! The state is available to both the update and draw closures, allowing you to:
//! - Modify state in response to events (update closure)
//! - Use the current state to render the UI (draw closure)
//!
//! # Event Handling
//!
//! The update closure receives an `Event` which can be:
//! - **Keyboard events**: `Event::Character`, `Event::KeyUp`, `Event::KeyDown`, etc.
//! - **Mouse events**: `Event::MouseClick`, `Event::MouseMove`, `Event::MouseScroll`, etc.
//! - **System events**: `Event::Resize`, `Event::Frame` (when using a fixed frame rate)
//!
//! Return `false` from the update closure to exit the application.
//!
//! # Drawing
//!
//! The draw closure receives a mutable reference to the window. You can:
//! - Create widgets like `Label`, `Panel`, `Container`
//! - Call `.draw(window)?` to render them
//! - Use low-level window methods like `window.write_str()` for custom rendering
//!
//! # Timed Updates (Optional)
//!
//! By default, the app runs in **event-driven mode** - the update closure is only called
//! when there's input. For animations or realtime-style apps, you can enable a fixed frame rate:
//!
//! ```ignore
//! let mut app = App::new(state)?.with_frame_rate(Duration::from_millis(16)); // ~60 FPS
//! ```
//!
//! When using a fixed frame rate, you'll also receive `Event::Frame` events at regular intervals.
use *;