morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
frontend.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4#include <core/tui/MouseTracking.hpp>
5#include <core/tui/Terminal.hpp>
6#include <core/tui/runtime/InputSource.hpp>
7#include <expected>
8#include <functional>
9#include <memory>
10#include <string_view>
11
12#include "../ui/backend.hpp"
13#include "../ui/frontend.hpp"
14
15/// @file
16/// @brief `morph::tui::Frontend`: a morph application in a terminal.
17///
18/// Specified in `docs/spec/tui/frontend.md`.
19
20namespace morph::tui {
21
22/// @brief The exit code `Frontend::run` returns when Ctrl+C ended the run: the shell's 128 + SIGINT, so a script can
23/// tell a user abort from a normal quit.
24inline constexpr int kInterruptExitCode = 130;
25
26/// @brief Mounts the application's shell for what the source delivered, on the terminal's widgets.
27///
28/// `ui::ShellFactory` with the backend the shell's views mount on: a terminal frontend renders through retained
29/// widgets, so the shell needs them, where a frontend that generates its views does not. Called once, on the owner.
30using ShellFactory = std::function<std::unique_ptr<ui::MountedShell>(
31 ui::AppContext& context, ui::IViewBackend& backend, std::expected<ui::Bundle, ui::ConnectError> opened)>;
32
33/// @brief What a `tui::Frontend` runs on.
35 /// @brief Mounts the shell when the source is ready; it must not be empty.
37 /// @brief The terminal to draw on; null means the process's terminal. Either way the frontend sets its mouse
38 /// mode and initialises it; only the process's own terminal is put on the alternate screen and restored.
39 ::core::tui::Terminal* terminal = nullptr;
40 /// @brief Where input comes from; null means the terminal's own input. A test passes a scripted source.
41 ::core::tui::runtime::InputSource* input = nullptr;
42 /// @brief How much mouse input to ask the terminal for: `Drag` reports presses, releases and motion while a
43 /// button is held, which drag-and-drop needs; while it is on, a plain click-drag no longer selects
44 /// terminal text (Shift+drag still does in most terminals).
45 ::core::tui::MouseTracking mouse = ::core::tui::MouseTracking::Drag;
46};
47
48/// @brief Runs a morph application in a terminal, on one thread.
49///
50/// `run` builds a caller-driven `exec::IoLoop`, a `LoopExecutor` on it (the reactive runtime's owner and every
51/// bridge handler's callback executor), the runtime, a `core::tui::Screen` and a `TuiRuntime`, then runs the source
52/// through `ui::runApp`: it opens the source, mounts the shell through `FrontendConfig::mountShell` when the source is
53/// ready, and pumps input until `AppContext::quit()` or the end of input. Sockets, timers,
54/// bridge callbacks and input all run on the thread that called `run`. Tab and Shift+Tab move the focus (inside
55/// an open dialog only, while one is open); Esc ends a drag wherever the focus is; Ctrl+C quits; a resize re-fits
56/// the view. Each input event is followed by a frame before the next one is handled, and redraws are coalesced to
57/// one per loop turn.
58class Frontend final : public ui::Frontend {
59public:
60 /// @param config The terminal, the input and the mouse mode; the defaults use the process's terminal.
61 explicit Frontend(FrontendConfig config = {});
62
63 /// @brief The name `--ui=` and `MORPH_UI` select this frontend by.
64 /// @return `"tui"`.
65 [[nodiscard]] std::string_view name() const override;
66
67 /// @brief Runs the application the source opens on the calling thread until it quits or the input ends.
68 /// @param source Opened once the runtime exists, and closed before it is destroyed.
69 /// @return The exit code given to `AppContext::quit()`; `kInterruptExitCode` (130) when Ctrl+C ended the run,
70 /// 0 when the end of input did.
71 /// @throws std::runtime_error when the terminal cannot be initialised; std::invalid_argument when
72 /// `FrontendConfig::mountShell` is empty; whatever the source or the shell factory throws.
73 int run(ui::AppSource& source) override;
74
75private:
76 FrontendConfig _config;
77};
78
79/// @brief The TUI's entry for `ui::selectFrontend`.
80/// @param config Handed to every `Frontend` the option makes.
81/// @return An option named `"tui"`, usable when standard input is a terminal.
83
84} // namespace morph::tui
std::string_view name() const override
The name --ui= and MORPH_UI select this frontend by.
int run(ui::AppSource &source) override
Runs the application the source opens on the calling thread until it quits or the input ends.
Frontend(FrontendConfig config={})
What a frontend lends the source it opens and the screens it mounts.
Definition frontend.hpp:50
Where the screens and the models are: a server (remote) or the application linked in-process (local).
Definition frontend.hpp:137
A frontend: owns an event loop and a renderer, and runs one source's screens.
Definition frontend.hpp:175
Makes widgets. Each factory appends the new widget to parent, or makes a root when it is null,...
Definition backend.hpp:810
What a tui::Frontend runs on.
Definition frontend.hpp:34
::core::tui::Terminal * terminal
The terminal to draw on; null means the process's terminal. Either way the frontend sets its mouse mo...
Definition frontend.hpp:39
ShellFactory mountShell
Mounts the shell when the source is ready; it must not be empty.
Definition frontend.hpp:36
::core::tui::runtime::InputSource * input
Where input comes from; null means the terminal's own input. A test passes a scripted source.
Definition frontend.hpp:41
::core::tui::MouseTracking mouse
How much mouse input to ask the terminal for: Drag reports presses, releases and motion while a butto...
Definition frontend.hpp:45
One frontend a binary was built with.
Definition frontend.hpp:201
std::function< std::unique_ptr< ui::MountedShell >( ui::AppContext &context, ui::IViewBackend &backend, std::expected< ui::Bundle, ui::ConnectError > opened)> ShellFactory
Mounts the application's shell for what the source delivered, on the terminal's widgets.
Definition frontend.hpp:30
ui::FrontendOption frontendOption(FrontendConfig config={})
The TUI's entry for ui::selectFrontend.
constexpr int kInterruptExitCode
The exit code Frontend::run returns when Ctrl+C ended the run: the shell's 128 + SIGINT,...
Definition frontend.hpp:24
The backend contract: the retained widgets a mount drives, and the factory that makes them.
The frontend seam: main picks a frontend at runtime, and the frontend runs whatever an AppSource open...