morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
components.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4#include <expected>
5#include <functional>
6#include <memory>
7#include <string>
8#include <vector>
9
10class QQmlComponent;
11class QQmlEngine;
12class QUrl;
13
14/// @file
15/// @brief `morph::qt_quick::Components`: the application's own QML components, by name, and the restyle map.
16///
17/// Specified in `docs/spec/qt_quick/backend.md`, "Components".
18
19namespace morph::qt_quick {
20
21/// @brief Why a component could not be loaded; reported once per component and reason.
23 /// @brief The component's name, or the kind a restyle names.
24 std::string name;
25 /// @brief What went wrong, for a person to read.
26 std::string reason;
27
28 /// @brief Memberwise equality.
29 /// @return Whether name and reason match.
30 bool operator==(ComponentFailure const&) const = default;
31};
32
33/// @brief The QML components a client renders beside the built-in kinds (spec 5 §10).
34///
35/// - A **host component** is QML the client carries, registered by name and version. It loads into the backend's
36/// own engine, so it may import the application's other modules.
37/// - A **bundle component** is QML text delivered in the application's bundle and named by its SHA-256 digest. It
38/// loads only when the text matches the digest, and compiles in a dedicated engine whose root context holds
39/// nothing, so it sees nothing but what is set on it.
40/// - The **restyle map** names a component for a built-in kind, or for a part a built-in component draws (`tableRow`,
41/// a table row's background; `tableHeader`, a table's header background; `scrollBar`, a scroll area's bar;
42/// `splitterHandle`, a splitter's handle). The component must declare every property and function of its `MorphUi`
43/// base; one that does not is refused when it is mapped.
44///
45/// Each component reports its events through `host.fire(event, payload)`, `host` being a `var` property it declares
46/// and the renderer sets. A component that fails to load is reported once, through the callback, and the caller
47/// renders its fallback. Neither copyable nor movable; it outlives every backend that uses it.
49public:
50 /// @brief An empty set.
51 /// @param report Called once for each component that fails to load, or restyle that is refused; may be empty.
52 explicit Components(std::function<void(ComponentFailure const&)> report = {});
53 /// @brief Releases the compiled components and the contained engine.
55 Components(Components const&) = delete;
56 Components& operator=(Components const&) = delete;
57 Components(Components&&) = delete;
58 Components& operator=(Components&&) = delete;
59
60 /// @brief Registers a host component, replacing one of the same name.
61 /// @param name The name a document uses.
62 /// @param version The version the client carries; a document asking for a later one gets the fallback.
63 /// @param source The QML file, such as a `qrc:` URL.
64 void addHost(std::string name, int version, QUrl const& source);
65
66 /// @brief Registers a bundle component, replacing one of the same name.
67 /// @param name The name a document uses.
68 /// @param qml The QML text, as the bundle delivered it.
69 /// @param digest Its SHA-256, as the bundle names it: `sha256:` followed by 64 hexadecimal digits.
70 // NOLINTNEXTLINE(bugprone-easily-swappable-parameters): a name, its text and its digest, as the bundle lists them.
71 void addBundle(std::string name, std::string qml, std::string digest);
72
73 /// @brief Maps a built-in kind to a registered component, checking that the component declares every property
74 /// and function of the kind's `MorphUi` component.
75 /// @param engine The engine the backend renders with. Borrowed for the call.
76 /// @param kind The kind as a document names it (`button`, `textInput`, `checkbox`, `select`, …), the
77 /// multi-line input (`textArea`), or a part kind (`tableRow`).
78 /// @param component The registered component's name.
79 /// @return Nothing, or why the mapping is refused; a refusal is also reported, and the kind keeps its
80 /// `MorphUi` component.
81 // NOLINTNEXTLINE(bugprone-easily-swappable-parameters): a kind, then what restyles it, as the bundle maps them.
82 [[nodiscard]] std::expected<void, ComponentFailure> restyle(QQmlEngine& engine, std::string const& kind,
83 std::string const& component);
84
85 /// @brief The compiled component a restyle maps a `MorphUi` type to, for a backend to instantiate.
86 /// @param engine The backend's engine. Borrowed for the call.
87 /// @param type The `MorphUi` type, such as `MorphButton`.
88 /// @return The component, or null when the type is not restyled.
89 [[nodiscard]] std::unique_ptr<QQmlComponent> restyled(QQmlEngine& engine, std::string const& type);
90
91 /// @brief Compiles a registered component, or says why it cannot be used.
92 /// @param engine The backend's engine, which host components load into. Borrowed for the call.
93 /// @param name The component's name.
94 /// @param minVersion The lowest host component version that will do.
95 /// @return The compiled component, owned by this set, or the failure, which is also reported once.
96 [[nodiscard]] std::expected<QQmlComponent*, ComponentFailure> load(QQmlEngine& engine, std::string const& name,
97 int minVersion = 0);
98
99 /// @brief Reports a failure, once per name and reason.
100 /// @param failure The failure.
101 void report(ComponentFailure const& failure);
102
103 /// @brief Every failure reported so far, oldest first.
104 /// @return They.
105 [[nodiscard]] std::vector<ComponentFailure> const& failures() const noexcept;
106
107private:
108 struct State;
109 std::unique_ptr<State> _state;
110};
111
112} // namespace morph::qt_quick
~Components()
Releases the compiled components and the contained engine.
std::vector< ComponentFailure > const & failures() const noexcept
Every failure reported so far, oldest first.
std::expected< QQmlComponent *, ComponentFailure > load(QQmlEngine &engine, std::string const &name, int minVersion=0)
Compiles a registered component, or says why it cannot be used.
void addBundle(std::string name, std::string qml, std::string digest)
Registers a bundle component, replacing one of the same name.
void report(ComponentFailure const &failure)
Reports a failure, once per name and reason.
std::unique_ptr< QQmlComponent > restyled(QQmlEngine &engine, std::string const &type)
The compiled component a restyle maps a MorphUi type to, for a backend to instantiate.
std::expected< void, ComponentFailure > restyle(QQmlEngine &engine, std::string const &kind, std::string const &component)
Maps a built-in kind to a registered component, checking that the component declares every property a...
Components(std::function< void(ComponentFailure const &)> report={})
An empty set.
void addHost(std::string name, int version, QUrl const &source)
Registers a host component, replacing one of the same name.
Why a component could not be loaded; reported once per component and reason.
bool operator==(ComponentFailure const &) const =default
Memberwise equality.
std::string reason
What went wrong, for a person to read.
std::string name
The component's name, or the kind a restyle names.