载入中...
搜索中...
未找到
UiThemeEditor.cpp
浏览该文件的文档.
2
3#include "ui/UIHost.h"
4#include "ui/UISystem.h"
5
6#include <utility>
7
8namespace eve::ui_editor {
9namespace {
10
11template <class T = void>
12ui_editing::Result<T> editorError(ui_editing::EditorStatus status, std::string rule, std::string message) {
13 return eve::editing::failed<T>(status, ui_editing::RuleId(std::move(rule)), std::move(message));
14}
15
16ui_editing::UiThemeBasePreset presetFromName(const std::string& name) {
17 if (name == "light") return ui_editing::UiThemeBasePreset::Light;
19}
20
21} // namespace
22
24 : target_(std::move(targetId)), authority_(&target_), transactions_(&authority_) {
25 auto previewed = refreshPreview();
26 if (!previewed.ok())
27 previewed.ignore("ui theme editor keeps an empty preview when the seeded catalog is rejected");
28}
29
31 editor::EditorWorkspace candidate = workspace;
32 struct Panel {
33 const char* id;
34 const char* title;
35 const char* region;
36 const char* context;
37 int order;
38 };
39 constexpr Panel panels[] = {
40 {"ui.themes", "Themes", "left", "list", 100},
41 {"ui.preview", "Theme Preview", "center", "preview", 100},
42 {"ui.inspector", "Theme Inspector", "right", "inspector", 100},
43 };
44 for (const auto& panel : panels) {
45 if (!candidate.registerPanel(panel.id, panel.title, panel.region, panel.order) ||
46 !candidate.setPanelCapability(panel.id, "ui.theme") ||
47 !candidate.setPanelContext(panel.id, panel.context))
48 return editorError(ui_editing::EditorStatus::Rejected, "editor.ui-theme.workspace-conflict",
49 "Could not install the UI theme workspace composition");
50 }
51 if (!candidate.activatePanel("ui.preview"))
52 return editorError(ui_editing::EditorStatus::Rejected, "editor.ui-theme.workspace-activate",
53 "Could not activate the UI theme preview panel");
54 workspace = std::move(candidate);
55 return eve::editing::applied<void>();
56}
57
58editor::SelectionSnapshot UiThemeEditor::selection() const {
60 snapshot.channel = "ui-theme";
62 item.domain = editor::SelectionDomain::Asset;
63 item.target = editor::TargetId(target_.targetId());
64 item.item = editor::StableId(selectedId_);
65 item.type = "ui.theme";
66 snapshot.items.push_back(item);
67 snapshot.primary = item;
68 return snapshot;
69}
70
71ui_editing::Result<void> UiThemeEditor::commit(
73 if (!operation.ok())
76 spec.id = editor::TransactionId("ui.theme.tx." + std::to_string(++txSequence_));
77 spec.label = std::move(label);
78 spec.target = editor::TargetId(target_.targetId());
79 spec.baseRevision = target_.revision();
80 auto begun = transactions_.begin(std::move(spec));
81 if (!begun.ok())
82 return editorError(begun.code(), "editor.ui-theme.begin", "Could not begin the theme transaction");
83 auto appended = transactions_.append(std::move(operation).takeValue());
84 if (!appended.ok()) {
85 auto discarded = transactions_.discard();
86 if (!discarded.ok()) discarded.ignore("pending theme transaction already inactive");
87 return ui_editing::Result<void>::failure(appended.status());
88 }
89 auto committed = transactions_.commit();
90 if (!committed.ok())
91 return ui_editing::Result<void>::failure(committed.status());
92 return refreshPreview();
93}
94
95ui_editing::Result<void> UiThemeEditor::refreshPreview() {
96 preview_ = previews_.build(target_, ui_editing::ObjectId(selectedId_), target_.revision());
97 if (preview_.status != ui_editing::EditorStatus::Applied)
98 return editorError(preview_.status, "editor.ui-theme.preview", "Could not rebuild the theme preview");
99 return eve::editing::applied<void>();
100}
101
103 auto asset = target_.theme(ui_editing::ObjectId(id));
104 if (!asset.ok()) return ui_editing::Result<void>::failure(asset.status());
105 selectedId_ = std::move(id);
106 return refreshPreview();
107}
108
109ui_editing::Result<void> UiThemeEditor::createFromPreset(std::string id, std::string name, std::string preset) {
110 if (preset != "dark" && preset != "light")
111 return editorError(ui_editing::EditorStatus::Rejected, "editor.ui-theme.preset-source",
112 "New themes must be created from dark or light");
113 auto created = commit(target_.makeCreateFromPreset(ui_editing::ObjectId(id), name, presetFromName(preset)),
114 "Create theme");
115 if (!created.ok()) return created;
116 selectedId_ = std::move(id);
117 return refreshPreview();
118}
119
121 auto duplicated =
122 commit(target_.makeDuplicate(ui_editing::ObjectId(selectedId_), ui_editing::ObjectId(id), std::move(name)),
123 "Duplicate theme");
124 if (!duplicated.ok()) return duplicated;
125 selectedId_ = std::move(id);
126 return refreshPreview();
127}
128
130 auto deleted = commit(target_.makeDelete(ui_editing::ObjectId(selectedId_)), "Delete theme");
131 if (!deleted.ok()) return deleted;
132 selectedId_ = target_.activeId().value();
133 if (selectedId_.empty() && !target_.themes().empty()) selectedId_ = target_.themes().front().id.value();
134 return refreshPreview();
135}
136
138 auto activated = commit(target_.makeSetActive(ui_editing::ObjectId(selectedId_)), "Activate theme");
139 if (!activated.ok()) return activated;
140 auto published = publisher_.publish(target_);
141 if (!published.ok()) return published;
142 return refreshPreview();
143}
144
146 return commit(target_.makeResetToBase(ui_editing::ObjectId(selectedId_)), "Reset theme");
147}
148
151 return commit(target_.makeSet(selection(), ui_editing::PropertyPath(path), value,
152 ui_editing::PropertySetMode::Absolute),
153 "Set theme token");
154}
155
157 auto undone = transactions_.undo();
158 if (!undone.ok()) return undone;
159 if (!target_.theme(ui_editing::ObjectId(selectedId_)).ok() && !target_.themes().empty())
160 selectedId_ = target_.themes().front().id.value();
161 auto previewed = refreshPreview();
162 if (!previewed.ok()) return ui_editing::Result<editor::TransactionReceipt>::failure(previewed.status());
163 return undone;
164}
165
167 auto redone = transactions_.redo();
168 if (!redone.ok()) return redone;
169 auto previewed = refreshPreview();
170 if (!previewed.ok()) return ui_editing::Result<editor::TransactionReceipt>::failure(previewed.status());
171 return redone;
172}
173
175 if (hostName.empty())
176 return editorError(ui_editing::EditorStatus::Rejected, "editor.ui-theme.host",
177 "Preview host name must not be empty");
178 if (preview_.status != ui_editing::EditorStatus::Applied || preview_.documentRevision != target_.revision()) {
179 auto previewed = refreshPreview();
180 if (!previewed.ok()) return previewed;
181 }
183 if (!host)
184 return editorError(ui_editing::EditorStatus::NotFound, "editor.ui-theme.host-missing",
185 "Preview UI host was not found: " + hostName);
186 host->get().setThemeOverride(preview_.theme);
187 return eve::editing::applied<void>();
188}
189
190const ui_editing::UiThemeAsset* UiThemeEditor::themeAt(int index) const {
191 if (index < 0 || static_cast<std::size_t>(index) >= target_.themes().size()) return nullptr;
192 return &target_.themes()[static_cast<std::size_t>(index)];
193}
194
195std::string UiThemeEditor::themeId(int index) const {
196 const auto* asset = themeAt(index);
197 return asset ? asset->id.value() : std::string{};
198}
199std::string UiThemeEditor::themeName(int index) const {
200 const auto* asset = themeAt(index);
201 return asset ? asset->name : std::string{};
202}
204 const auto* asset = themeAt(index);
205 return asset && asset->id.value() == selectedId_;
206}
208 const auto* asset = themeAt(index);
209 return asset && asset->id == target_.activeId();
210}
211
212float UiThemeEditor::getColorChannel(const std::string& path, int channel) const {
213 auto value = target_.read(selection(), ui_editing::PropertyPath(path));
214 if (value.state != ui_editing::PropertyReadState::Value) return 0.0f;
215 const auto* array = value.value.getIf<ui_editing::EditorValue::Array>();
216 if (!array || channel < 0 || static_cast<std::size_t>(channel) >= array->size()) return 0.0f;
217 const auto* number = (*array)[static_cast<std::size_t>(channel)].getIf<double>();
218 return number ? static_cast<float>(*number) : 0.0f;
219}
220
221float UiThemeEditor::getFloat(const std::string& path) const {
222 auto value = target_.read(selection(), ui_editing::PropertyPath(path));
223 if (value.state != ui_editing::PropertyReadState::Value) return 0.0f;
224 const auto* number = value.value.getIf<double>();
225 return number ? static_cast<float>(*number) : 0.0f;
226}
227
228} // namespace eve::ui_editor
ActionParameterOperation operation
double value
std::string title
std::string label
std::string message
wgpu::PopErrorScopeStatus status
std::string name
std::vector< std::int32_t > order
std::string path
Definition PlayHost.cpp:110
std::string id
Definition PlayHost.cpp:108
std::uint32_t targetId
double number
int created
UIHostHandle host
UI-neutral named Theme catalog editor: workspace, gallery preview, undo.
uint32_t index
const VegetationPresetContext & context
void ignore(std::string_view reason={}) const noexcept
Explicitly discard this result after documenting the reason.
Definition Result.h:537
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
std::uint64_t revision() const override
Return the current revision.
Dotted property path (layout.size) compared and persisted as text.
Definition EditingIds.h:78
Deterministic owning value tree shared by authoring hosts.
std::vector< Value > Array
const T * getIf() const
Return an immediately borrowed typed value.
Composition model shared by project-specific developer and runtime editors.
bool setPanelContext(const std::string &id, const std::string &context)
Attach a semantic input context such as scene, graph, or timeline.
Result< WorkspacePanelDescriptor > registerPanel(WorkspacePanelDescriptor descriptor)
Register a checked owning panel descriptor.
Result< WorkspacePanelDescriptor > activatePanel(const StableId &id)
Activate a visible panel with structured not-found/rejected results.
bool setPanelCapability(const std::string &id, const std::string &capability)
Attach a capability requirement used by the host when filtering panels.
Result< TransactionReceipt > commit() override
Preflight and commit all active operations through the authority.
Result< TransactionId > begin(TransactionSpec specification) override
Begin a transaction with a stable id and base revision.
Result< TransactionReceipt > undo() override
Compensate the most recent committed transaction.
Result< void > discard() override
Discard the active, not-yet-committed operation list.
Result< TransactionReceipt > redo() override
Reapply the most recently compensated transaction.
Result< void > append(DomainOperation operation) override
Append an operation to the active transaction without applying it.
static eve::OptionalRef< UIHost > resolve(UIHostHandle handle) noexcept
Resolves a UI host handle with ECS generation checking.
Definition UIHost.cpp:61
static UIHostHandle findHost(const std::string &name)
Lookup by Meta.name across the UIHost View.
Result< DomainOperation > makeDelete(const ObjectId &id) const
Make delete.
Definition UiTheme.cpp:276
Result< DomainOperation > makeSetActive(const ObjectId &id) const
Make set active.
Definition UiTheme.cpp:292
Result< DomainOperation > makeResetToBase(const ObjectId &id) const
Make reset to base.
Definition UiTheme.cpp:301
const ObjectId & activeId() const noexcept
Active publication id; empty only if the catalog failed to seed.
Definition UiTheme.h:93
TargetId targetId() const override
Target id.
Definition UiTheme.h:72
Result< UiThemeAsset > theme(const ObjectId &id) const
Copy one named theme, or NotFound.
Definition UiTheme.cpp:143
PropertyReadResult read(const SelectionSnapshot &selection, const PropertyPath &path) const override
Reads .
Result< DomainOperation > makeCreateFromPreset(const ObjectId &id, std::string name, UiThemeBasePreset preset) const
Make create from preset.
Definition UiTheme.cpp:212
Result< DomainOperation > makeSet(const SelectionSnapshot &selection, const PropertyPath &path, const EditorValue &value, PropertySetMode mode) const override
Make set.
const std::vector< UiThemeAsset > & themes() const noexcept
Borrow authored themes in catalog order.
Definition UiTheme.h:91
Result< DomainOperation > makeDuplicate(const ObjectId &source, const ObjectId &id, std::string name) const
Make duplicate.
Definition UiTheme.cpp:237
UiThemePreviewSnapshot build(const UiThemeCatalogTarget &catalog, const ObjectId &themeId, Revision expectedRevision) const
Copy tokens for themeId when expectedRevision matches the catalog.
Result< void > publish(const UiThemeCatalogTarget &catalog) const
Replace the process global theme with the catalog's active asset.
ui_editing::Result< void > duplicateSelected(std::string id, std::string name)
ui_editing::Result< void > deleteSelected()
std::string themeId(int index) const
Theme id.
ui_editing::Result< void > configureWorkspace(editor::EditorWorkspace &workspace) const
Install Themes / Preview / Inspector panels.
ui_editing::Result< void > setToken(const std::string &path, const ui_editing::EditorValue &value)
ui_editing::Result< void > setActiveSelected()
float getFloat(const std::string &path) const
Returns the float.
bool isThemeActive(int index) const
True when theme active.
ui_editing::Result< editor::TransactionReceipt > redo()
ui_editing::Result< void > applyPreviewHost(const std::string &hostName)
Copy the selected theme onto a live UIHost without changing globalTheme.
ui_editing::Result< void > createFromPreset(std::string id, std::string name, std::string preset)
UiThemeEditor(std::string targetId)
Construct a catalog seeded with built-in Dark and Light assets.
ui_editing::Result< void > resetSelectedToBase()
std::string themeName(int index) const
Theme name.
ui_editing::Result< editor::TransactionReceipt > undo()
float getColorChannel(const std::string &path, int channel) const
Returns the color channel.
bool isThemeSelected(int index) const
True when theme selected.
ui_editing::Result< void > selectTheme(std::string id)
eve::editing::StableId StableId
Definition EditorIds.h:36
eve::editing::TargetId TargetId
Definition EditorIds.h:29
eve::editing::TransactionId TransactionId
Definition EditorIds.h:34
UiThemeBasePreset
Base preset used when resetting a named theme asset.
Definition UiTheme.h:44
editing::Status EditorStatus
Definition UiDocument.h:43
SelectionItem public API.
SelectionSnapshot public API.
std::vector< SelectionItem > items
std::optional< SelectionItem > primary
TransactionSpec public API.
One named, fully snapshotted Theme asset.
Definition UiTheme.h:47