libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
tuisubsystem.h
Go to the documentation of this file.
1
8#pragma once
9
10#include <chrono>
11#include <promeki/namespace.h>
12#include <promeki/application.h>
13#include <promeki/atomic.h>
14#include <promeki/terminal.h>
15#include <promeki/point.h>
16#include <promeki/eventloop.h>
17#include <promeki/tui/screen.h>
18#include <promeki/tui/palette.h>
20
21PROMEKI_NAMESPACE_BEGIN
22
23class TuiWidget;
24
58 public:
68
71
72 TuiSubsystem(const TuiSubsystem &) = delete;
73 TuiSubsystem &operator=(const TuiSubsystem &) = delete;
74
78 static TuiSubsystem *instance() { return _instance; }
79
84 void setRootWidget(TuiWidget *widget);
85
87 TuiWidget *rootWidget() const { return _rootWidget; }
88
90 TuiScreen &screen() { return _screen; }
91
93 Terminal &terminal() { return _terminal; }
94
103 bool isWindowFocused() const { return _windowFocused; }
104
106 const TuiPalette &palette() const { return _palette; }
107
109 TuiPalette &palette() { return _palette; }
110
112 void setPalette(const TuiPalette &palette) { _palette = palette; }
113
125 void setColorMode(Terminal::ColorSupport mode) {
126 _screen.setColorMode(mode);
127 updateAll();
128 }
129
134 Terminal::ColorSupport colorMode() const { return _screen.colorMode(); }
135
139 void updateAll();
140
146
148 TuiWidget *focusWidget() const { return _focusWidget; }
149
154 void focusNext(bool reverse = false);
155
166
173 void grabMouse(TuiWidget *widget) { _mouseGrab = widget; }
174
178 void releaseMouse() { _mouseGrab = nullptr; }
179
180 private:
181 static TuiSubsystem *_instance;
182
183 EventLoop *_eventLoop = nullptr;
184 Terminal _terminal;
185 TuiScreen _screen;
186 TuiPalette _palette;
187 TuiInputParser _inputParser;
188 // The terminal owns the single AnsiStream; we render through it
189 // rather than a second stream over stdout (which would be a
190 // separate, racing write path). Reference is bound from
191 // _terminal in the constructor — _terminal is declared first so
192 // it is fully constructed before this binds.
193 AnsiStream &_ansiStream;
194 TuiWidget *_rootWidget = nullptr;
195 TuiWidget *_focusWidget = nullptr;
196 TuiWidget *_mouseGrab = nullptr;
197 int _lastCols = 0;
198 int _lastRows = 0;
199 bool _windowFocused = true;
200 int _crashCleanupHandle = -1;
201
202 // Event-loop-driven input / resize / repaint state.
203 // - _stdinSourceHandle: IoSource handle for STDIN_FILENO.
204 // - _winchSubscription: SignalHandler subscription handle
205 // for SIGWINCH. The SignalHandler watcher thread
206 // invokes the subscriber callback, which in turn
207 // posts handleResize() onto the main EventLoop.
208 // - _repaintQueued: coalesces markNeedsRepaint() calls
209 // into a single pending postCallable — if a repaint
210 // is already queued we skip reposting.
211 int _stdinSourceHandle = -1;
212 int _winchSubscription = -1;
213 Atomic<bool> _repaintQueued;
214
215 // Double-click detection state
216 using Clock = std::chrono::steady_clock;
217 using TimePoint = Clock::time_point;
218 static constexpr int DoubleClickIntervalMs = 400;
219 TimePoint _lastClickTime{};
220 Point2Di32 _lastClickPos{-1, -1};
221 MouseEvent::Button _lastClickButton = MouseEvent::NoButton;
222
223 void setupEventSources();
224 void teardownEventSources();
225 void doPaint();
226 void processInput();
227 void paintWidgets();
228 void paintWidget(TuiWidget *widget);
229 void handleResize();
230 void dispatchKeyEvent(const TuiInputParser::ParsedEvent &ev);
231 void dispatchMouseEvent(const TuiInputParser::ParsedEvent &ev);
232 void dispatchPasteEvent(const TuiInputParser::ParsedEvent &ev);
233 void dispatchWindowFocusEvent(bool gained);
234
235 // Async-signal-safe CrashHandler hook (userdata is the Terminal*).
236 static void crashRestore(void *userdata);
237 void collectFocusable(TuiWidget *widget, List<TuiWidget *> &list);
238 TuiWidget *widgetAt(TuiWidget *widget, const Point2Di32 &globalPos);
239};
240
241PROMEKI_NAMESPACE_END
State machine for parsing terminal escape sequences into events.
Definition inputparser.h:29
Style palette for TUI widgets.
Definition palette.h:41
Double-buffered character cell grid for TUI rendering.
Definition screen.h:68
TUI subsystem installed alongside an Application.
Definition tuisubsystem.h:57
void releaseMouse()
Releases the mouse grab.
Definition tuisubsystem.h:178
const TuiPalette & palette() const
Returns the palette.
Definition tuisubsystem.h:106
void setColorMode(Terminal::ColorSupport mode)
Sets the color mode for the TUI screen.
Definition tuisubsystem.h:125
void setRootWidget(TuiWidget *widget)
Sets the top-level (root) widget.
void setFocusWidget(TuiWidget *widget)
Sets the focused widget.
void grabMouse(TuiWidget *widget)
Grabs mouse events for a widget.
Definition tuisubsystem.h:173
TuiScreen & screen()
Returns the screen.
Definition tuisubsystem.h:90
TuiSubsystem()
Installs the TUI on the current Application.
void updateAll()
Forces a full screen repaint.
void setPalette(const TuiPalette &palette)
Sets the palette.
Definition tuisubsystem.h:112
static TuiSubsystem * instance()
Returns the active TuiSubsystem instance.
Definition tuisubsystem.h:78
TuiWidget * focusWidget() const
Returns the currently focused widget.
Definition tuisubsystem.h:148
void focusNext(bool reverse=false)
Cycles focus to the next focusable widget.
bool isWindowFocused() const
Returns whether the terminal window currently has focus.
Definition tuisubsystem.h:103
~TuiSubsystem()
Destructor. Restores terminal state and releases I/O sources.
void markNeedsRepaint()
Marks the screen as needing a repaint.
Terminal::ColorSupport colorMode() const
Returns the current color mode.
Definition tuisubsystem.h:134
TuiPalette & palette()
Returns the palette for modification.
Definition tuisubsystem.h:109
Terminal & terminal()
Returns the terminal.
Definition tuisubsystem.h:93
TuiWidget * rootWidget() const
Returns the root widget.
Definition tuisubsystem.h:87
TUI-specific widget base class.
Definition widget.h:33