载入中...
搜索中...
未找到
EditorWorkspace.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <optional>
5#include <utility>
6
7namespace eve::editor {
8namespace {
9
10std::optional<WorkspaceRegion> parseWorkspaceRegion(const std::string& region) {
11 if (region == "left") return WorkspaceRegion::Left;
12 if (region == "right") return WorkspaceRegion::Right;
13 if (region == "top") return WorkspaceRegion::Top;
14 if (region == "bottom") return WorkspaceRegion::Bottom;
15 if (region == "center") return WorkspaceRegion::Center;
16 if (region == "floating") return WorkspaceRegion::Floating;
17 return std::nullopt;
18}
19
20} // namespace
21
22std::string_view workspaceRegionName(WorkspaceRegion region) {
23 switch (region) {
24 case WorkspaceRegion::Left: return "left";
25 case WorkspaceRegion::Right: return "right";
26 case WorkspaceRegion::Top: return "top";
27 case WorkspaceRegion::Bottom: return "bottom";
28 case WorkspaceRegion::Center: return "center";
29 case WorkspaceRegion::Floating: return "floating";
30 }
31 return "center";
32}
33
34EditorWorkspace::EditorWorkspace(std::string id, std::string title) : id_(std::move(id)), title_(std::move(title)) {}
35
36void EditorWorkspace::setTitle(const std::string& title) {
37 if (title_ == title) return;
38 title_ = title;
39 changed();
40}
41
42bool EditorWorkspace::registerPanel(const std::string& id, const std::string& title, const std::string& region,
43 int order) {
44 WorkspacePanelDescriptor descriptor{id, title, region, {}, {}, order, true, true};
45 return registerPanel(std::move(descriptor)).ok();
46}
47
49 if (descriptor.id.empty())
50 return eve::editing::failed<WorkspacePanelDescriptor>(
51 EditorStatus::Rejected, RuleId("editor.workspace.empty-panel-id"), "Workspace panel id must not be empty");
52 if (descriptor.title.empty())
53 return eve::editing::failed<WorkspacePanelDescriptor>(EditorStatus::Rejected,
54 RuleId("editor.workspace.empty-panel-title"),
55 "Workspace panel title must not be empty");
56 if (!parseWorkspaceRegion(descriptor.region))
57 return eve::editing::failed<WorkspacePanelDescriptor>(EditorStatus::Rejected,
58 RuleId("editor.workspace.invalid-region"),
59 "Workspace panel uses an unsupported dock region");
60 if (findPanel(descriptor.id))
61 return eve::editing::failed<WorkspacePanelDescriptor>(
62 EditorStatus::Conflict, RuleId("editor.workspace.duplicate-panel"),
63 "Workspace panel id is already registered: " + descriptor.id);
64 const std::string id = descriptor.id;
65 panels_.push_back(std::move(descriptor));
66 sortPanels();
67 if (activePanel_.empty()) activePanel_ = id;
68 changed();
69 return eve::editing::applied<WorkspacePanelDescriptor>(*findPanel(id));
70}
71
72bool EditorWorkspace::removePanel(const std::string& id) {
73 auto result = removePanel(StableId(id));
74 return result.code() == EditorStatus::Applied;
75}
76
78 const auto found = std::find_if(panels_.begin(), panels_.end(), [&](const auto& panel) { return panel.id == id.value(); });
79 if (found == panels_.end())
80 return eve::editing::failed<WorkspacePanelDescriptor>(EditorStatus::NotFound,
81 RuleId("editor.workspace.panel-not-found"),
82 "Workspace panel is not registered: " + id.value());
84 panels_.erase(found);
85 if (activePanel_ == id.value()) activePanel_ = panels_.empty() ? std::string{} : panels_.front().id;
86 changed();
87 return eve::editing::applied<WorkspacePanelDescriptor>(std::move(removed));
88}
89
91 if (panels_.empty()) return;
92 panels_.clear();
93 activePanel_.clear();
94 changed();
95}
96
97bool EditorWorkspace::movePanel(const std::string& id, const std::string& region, int order) {
98 const auto parsed = parseWorkspaceRegion(region);
99 return parsed && movePanel(StableId(id), *parsed, order).ok();
100}
101
103 int order) {
104 WorkspacePanelDescriptor* panel = findPanel(id.value());
105 if (!panel)
106 return eve::editing::failed<WorkspacePanelDescriptor>(EditorStatus::NotFound,
107 RuleId("editor.workspace.panel-not-found"),
108 "Workspace panel is not registered: " + id.value());
109 const std::string regionName(workspaceRegionName(region));
110 if (panel->region == regionName && panel->order == order) {
112 *panel, eve::Status::success(EditorStatus::NoOp));
113 }
114 panel->region = regionName;
115 panel->order = order;
116 sortPanels();
117 changed();
118 return eve::editing::applied<WorkspacePanelDescriptor>(*findPanel(id.value()));
119}
120
122 if (index >= panels_.size())
123 return eve::editing::failed<WorkspacePanelDescriptor>(
124 EditorStatus::NotFound, RuleId("editor.workspace.panel-index"), "Workspace panel index is out of range");
125 return eve::editing::applied<WorkspacePanelDescriptor>(panels_[index]);
126}
127
128bool EditorWorkspace::setPanelCapability(const std::string& id, const std::string& capability) {
129 WorkspacePanelDescriptor* panel = findPanel(id);
130 if (!panel) return false;
131 if (panel->capability == capability) return true;
132 panel->capability = capability;
133 changed();
134 return true;
135}
136
137bool EditorWorkspace::setPanelContext(const std::string& id, const std::string& context) {
138 WorkspacePanelDescriptor* panel = findPanel(id);
139 if (!panel) return false;
140 if (panel->context == context) return true;
141 panel->context = context;
142 changed();
143 return true;
144}
145
146bool EditorWorkspace::setPanelVisible(const std::string& id, bool visible) {
147 WorkspacePanelDescriptor* panel = findPanel(id);
148 if (!panel) return false;
149 if (panel->visible == visible) return true;
150 panel->visible = visible;
151 if (!visible && activePanel_ == id) activePanel_.clear();
152 changed();
153 return true;
154}
155
156bool EditorWorkspace::setPanelSingleton(const std::string& id, bool singleton) {
157 WorkspacePanelDescriptor* panel = findPanel(id);
158 if (!panel) return false;
159 if (panel->singleton == singleton) return true;
160 panel->singleton = singleton;
161 changed();
162 return true;
163}
164
165bool EditorWorkspace::activatePanel(const std::string& id) {
166 return activatePanel(StableId(id)).ok();
167}
168
170 const WorkspacePanelDescriptor* panel = findPanel(id.value());
171 if (!panel)
172 return eve::editing::failed<WorkspacePanelDescriptor>(EditorStatus::NotFound,
173 RuleId("editor.workspace.panel-not-found"),
174 "Workspace panel is not registered: " + id.value());
175 if (!panel->visible)
176 return eve::editing::failed<WorkspacePanelDescriptor>(EditorStatus::Rejected,
177 RuleId("editor.workspace.panel-hidden"),
178 "Hidden workspace panels cannot be activated");
179 if (activePanel_ == id.value()) {
181 *panel, eve::Status::success(EditorStatus::NoOp));
182 }
183 activePanel_ = id.value();
184 changed();
185 return eve::editing::applied<WorkspacePanelDescriptor>(*panel);
186}
187
188std::string EditorWorkspace::getPanelId(int index) const {
189 const auto* panel = panelAtUnchecked(index);
190 return panel ? panel->id : std::string{};
191}
192
193std::string EditorWorkspace::getPanelTitle(int index) const {
194 const auto* panel = panelAtUnchecked(index);
195 return panel ? panel->title : std::string{};
196}
197
199 const auto* panel = panelAtUnchecked(index);
200 return panel ? panel->region : std::string{};
201}
202
204 const auto* panel = panelAtUnchecked(index);
205 return panel ? panel->capability : std::string{};
206}
207
209 const auto* panel = panelAtUnchecked(index);
210 return panel ? panel->context : std::string{};
211}
212
214 const auto* panel = panelAtUnchecked(index);
215 return panel ? panel->order : 0;
216}
217
219 const auto* panel = panelAtUnchecked(index);
220 return panel && panel->visible;
221}
222
224 const auto* panel = panelAtUnchecked(index);
225 return panel && panel->singleton;
226}
227
228void EditorWorkspace::setRegionSize(const std::string& region, float pixels) {
229 dock_.setRegionSize(region, pixels);
230 changed();
231}
232
233void EditorWorkspace::layout(float width, float height) { dock_.layout(width, height); }
234
235float EditorWorkspace::getRegionX(const std::string& region) const { return dock_.getRegionX(region); }
236float EditorWorkspace::getRegionY(const std::string& region) const { return dock_.getRegionY(region); }
237float EditorWorkspace::getRegionW(const std::string& region) const { return dock_.getRegionW(region); }
238float EditorWorkspace::getRegionH(const std::string& region) const { return dock_.getRegionH(region); }
239
240bool EditorWorkspace::setMode(const std::string& mode) {
241 return setModeId(StableId(mode)).ok();
242}
243
245 if (mode.empty())
246 return eve::editing::failed<StableId>(EditorStatus::Rejected, RuleId("editor.workspace.empty-mode"),
247 "Workspace mode must not be empty");
248 if (mode_ == mode.value()) {
249 return Result<StableId>::success(std::move(mode), eve::Status::success(EditorStatus::NoOp));
250 }
251 mode_ = mode.value();
252 changed();
253 return eve::editing::applied<StableId>(std::move(mode));
254}
255
256bool EditorWorkspace::select(const std::string& channel, const std::string& domain, const std::string& target,
257 const std::string& item, const std::string& type, bool additive) {
258 SelectionDomain parsed;
259 if (channel.empty() || target.empty() || item.empty() || !parseDomain(domain, parsed)) return false;
260 return selectItem(channel, SelectionItem{parsed, TargetId(target), StableId(item), type}, additive).ok();
261}
262
264 bool additive) {
265 if (channel.empty() || selected.target.empty() || selected.item.empty())
266 return eve::editing::failed<SelectionSnapshot>(EditorStatus::Rejected,
267 RuleId("editor.workspace.invalid-selection"),
268 "Selection requires a channel, target and item");
269 std::vector<SelectionItem> items;
270 if (additive) items = selection_.snapshot(channel).items;
271 if (std::find(items.begin(), items.end(), selected) == items.end()) items.push_back(selected);
272 auto result = selection_.set(channel, std::move(items), selected);
273 if (result.ok() && result.code() != EditorStatus::NoOp) changed();
274 return result;
275}
276
277bool EditorWorkspace::clearSelection(const std::string& channel) {
278 return clearSelectionChecked(channel).ok();
279}
280
282 auto result = selection_.clear(channel);
283 if (result.ok() && result.code() != EditorStatus::NoOp) changed();
284 return result;
285}
286
287int EditorWorkspace::getSelectionCount(const std::string& channel) const {
288 return static_cast<int>(selection_.snapshot(channel).items.size());
289}
290
291std::string EditorWorkspace::getSelectionItem(const std::string& channel, int index) const {
292 const auto snapshot = selection_.snapshot(channel);
293 return index >= 0 && index < static_cast<int>(snapshot.items.size())
294 ? snapshot.items[static_cast<std::size_t>(index)].item.value()
295 : std::string{};
296}
297
298std::string EditorWorkspace::getSelectionType(const std::string& channel, int index) const {
299 const auto snapshot = selection_.snapshot(channel);
300 return index >= 0 && index < static_cast<int>(snapshot.items.size())
301 ? snapshot.items[static_cast<std::size_t>(index)].type
302 : std::string{};
303}
304
305std::string EditorWorkspace::getPrimarySelection(const std::string& channel) const {
306 const auto snapshot = selection_.snapshot(channel);
307 return snapshot.primary ? snapshot.primary->item.value() : std::string{};
308}
309
310std::uint64_t EditorWorkspace::getSelectionSequence(const std::string& channel) const {
311 return selection_.snapshot(channel).sequence;
312}
313
314bool EditorWorkspace::focus(const std::string& channel, const std::string& surface, const std::string& item) {
315 return focusItem(channel, StableId(surface), StableId(item)).ok();
316}
317
319 StableId item) {
320 auto result = focus_.focus(channel, std::move(surface), std::move(item));
321 if (result.ok() && result.code() != EditorStatus::NoOp) changed();
322 return result;
323}
324
325std::string EditorWorkspace::getFocusedSurface(const std::string& channel) const {
326 return focus_.snapshot(channel).surface.value();
327}
328
329bool EditorWorkspace::isRegion(const std::string& region) {
330 return region == "left" || region == "right" || region == "top" || region == "bottom" || region == "center" ||
331 region == "floating";
332}
333
334bool EditorWorkspace::parseDomain(const std::string& value, SelectionDomain& domain) {
335 if (value == "scene")
336 domain = SelectionDomain::Scene;
337 else if (value == "asset")
338 domain = SelectionDomain::Asset;
339 else if (value == "graph")
340 domain = SelectionDomain::Graph;
341 else if (value == "timeline")
342 domain = SelectionDomain::Timeline;
343 else if (value == "ui")
344 domain = SelectionDomain::UI;
345 else if (value == "custom")
346 domain = SelectionDomain::Custom;
347 else
348 return false;
349 return true;
350}
351
352WorkspacePanelDescriptor* EditorWorkspace::findPanel(const std::string& id) {
353 const auto found = std::find_if(panels_.begin(), panels_.end(), [&](const auto& panel) { return panel.id == id; });
354 return found == panels_.end() ? nullptr : &*found;
355}
356
357const WorkspacePanelDescriptor* EditorWorkspace::panelAtUnchecked(int index) const {
358 return index >= 0 && index < static_cast<int>(panels_.size()) ? &panels_[static_cast<std::size_t>(index)] : nullptr;
359}
360
361void EditorWorkspace::sortPanels() {
362 std::stable_sort(panels_.begin(), panels_.end(), [](const auto& left, const auto& right) {
363 if (left.region != right.region) return left.region < right.region;
364 if (left.order != right.order) return left.order < right.order;
365 return left.id < right.id;
366 });
367}
368
369void EditorWorkspace::changed() { ++revision_; }
370
371} // namespace eve::editor
LogicalId target
double value
std::string descriptor
std::string title
HexVec3 left
HexVec3 right
std::uint32_t height
std::uint32_t width
std::vector< std::int32_t > order
std::string id
Definition PlayHost.cpp:108
uint8_t * pixels
bool found
int removed
bool visible
uint32_t index
const VegetationPresetContext & context
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
UUID-backed identifier adapter for legacy textual boundaries.
Definition Identity.h:314
const std::string & value() const noexcept
Returns the exact legacy or canonical compatibility spelling.
Definition Identity.h:362
bool empty() const noexcept
True when no compatibility spelling has been assigned.
Definition Identity.h:374
float getRegionX(const std::string &region) const
Returns the region x.
void setRegionSize(const std::string &region, float pixels)
Sets the region size.
float getRegionY(const std::string &region) const
Returns the region y.
void layout(float screenW, float screenH)
Layout.
float getRegionW(const std::string &region) const
Returns the region w.
float getRegionH(const std::string &region) const
Returns the region h.
EditorFocusSnapshot snapshot(const std::string &channel) const
Read the current focus of one channel.
Result< EditorFocusSnapshot > focus(std::string channel, StableId surface, StableId item={})
Set the focused surface/item for one channel.
Result< SelectionSnapshot > clear(const std::string &channel)
Clear a channel while retaining a monotonic sequence.
SelectionSnapshot snapshot(const std::string &channel) const
Read one channel, returning an empty sequence-zero snapshot when absent.
Result< SelectionSnapshot > set(std::string channel, std::vector< SelectionItem > items, std::optional< SelectionItem > primary=std::nullopt)
Atomically replace a channel selection and optional primary item.
std::string getPrimarySelection(const std::string &channel) const
Primary selected item id for a channel.
std::string getFocusedSurface(const std::string &channel) const
Focused surface id for a channel.
bool getPanelSingleton(int index) const
Panel singleton policy by deterministic index.
std::uint64_t getSelectionSequence(const std::string &channel) const
Monotonic selection sequence for MVVM change detection.
Result< WorkspacePanelDescriptor > panelAt(std::size_t index) const
Return an owning panel snapshot instead of an ambiguous empty field.
std::string getPanelCapability(int index) const
Panel capability requirement by deterministic index.
std::string getPanelRegion(int index) const
Panel dock region by deterministic index.
float getRegionH(const std::string &region) const
Computed region height.
std::string getPanelContext(int index) const
Panel input context by deterministic index.
Result< WorkspacePanelDescriptor > removePanel(const StableId &id)
Remove a panel and return its final owning descriptor.
bool setPanelContext(const std::string &id, const std::string &context)
Attach a semantic input context such as scene, graph, or timeline.
Result< EditorFocusSnapshot > focusItem(const std::string &channel, StableId surface, StableId item)
Focus a strongly identified surface and item without discarding diagnostics.
std::string getPanelTitle(int index) const
Panel title by deterministic index.
bool focus(const std::string &channel, const std::string &surface, const std::string &item)
Set UI-toolkit-independent focus for a channel.
Result< SelectionSnapshot > selectItem(std::string channel, SelectionItem item, bool additive)
Select one already typed item without string domain parsing.
std::string getSelectionItem(const std::string &channel, int index) const
Selected stable item id by channel/index.
Result< WorkspacePanelDescriptor > registerPanel(WorkspacePanelDescriptor descriptor)
Register a checked owning panel descriptor.
void setTitle(const std::string &title)
Change the display title without changing workspace identity.
std::string getSelectionType(const std::string &channel, int index) const
Selected item type by channel/index.
bool select(const std::string &channel, const std::string &domain, const std::string &target, const std::string &item, const std::string &type, bool additive)
Select one stable item in a semantic channel.
bool setMode(const std::string &mode)
Set a project-defined mode such as edit, play, material, or animation.
Result< WorkspacePanelDescriptor > activatePanel(const StableId &id)
Activate a visible panel with structured not-found/rejected results.
float getRegionY(const std::string &region) const
Computed region Y coordinate.
EditorWorkspace(std::string id, std::string title)
Create a workspace with stable identity and display title.
Result< WorkspacePanelDescriptor > movePanel(const StableId &id, WorkspaceRegion region, int order)
Move a panel using a strongly typed dock region.
void clearPanels()
Remove every panel descriptor.
Result< StableId > setModeId(StableId mode)
Set a strongly identified workspace mode.
Result< SelectionSnapshot > clearSelectionChecked(const std::string &channel)
Clear one selection channel without discarding diagnostics.
bool getPanelVisible(int index) const
Panel visibility by deterministic index.
bool setPanelCapability(const std::string &id, const std::string &capability)
Attach a capability requirement used by the host when filtering panels.
void layout(float width, float height)
Compute standard dock rectangles for the requested host size.
int getPanelOrder(int index) const
Panel order by deterministic index.
bool setPanelSingleton(const std::string &id, bool singleton)
Mark whether hosts should allow more than one instance of this panel type.
void setRegionSize(const std::string &region, float pixels)
Configure one standard dock region size in pixels.
std::string getPanelId(int index) const
Panel id by deterministic index.
float getRegionX(const std::string &region) const
Computed region X coordinate.
int getSelectionCount(const std::string &channel) const
Number of selected items in a channel.
bool setPanelVisible(const std::string &id, bool visible)
Show or hide a panel without removing its descriptor.
float getRegionW(const std::string &region) const
Computed region width.
bool clearSelection(const std::string &channel)
Clear one semantic selection channel.
SelectionDomain
SelectionDomain public API.
eve::editing::StableId StableId
Definition EditorIds.h:36
WorkspaceRegion
Supported semantic dock regions for UI-neutral workspace panels.
std::string_view workspaceRegionName(WorkspaceRegion region)
Return the stable serialized name for a workspace region.
eve::editing::TargetId TargetId
Definition EditorIds.h:29
eve::editing::RuleId RuleId
Definition EditorIds.h:32
eve::editing::SelectionDomain SelectionDomain
Semantic domain of one selection channel.
SelectionItem public API.
std::vector< SelectionItem > items
std::optional< SelectionItem > primary
UI-neutral description of one composable editor panel.