Add editor panel host lifecycle contract
This commit is contained in:
@@ -18,6 +18,7 @@ add_library(XCUIEditorLib STATIC
|
||||
src/Core/UIEditorDockHostInteraction.cpp
|
||||
src/Core/UIEditorMenuModel.cpp
|
||||
src/Core/UIEditorMenuSession.cpp
|
||||
src/Core/UIEditorPanelHostLifecycle.cpp
|
||||
src/Core/UIEditorPanelRegistry.cpp
|
||||
src/Core/UIEditorShellCompose.cpp
|
||||
src/Core/UIEditorShellInteraction.cpp
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEditor/Core/UIEditorPanelRegistry.h>
|
||||
#include <XCEditor/Core/UIEditorWorkspaceSession.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine::UI::Editor {
|
||||
|
||||
enum class UIEditorPanelHostLifecycleEventKind : std::uint8_t {
|
||||
Attached = 0,
|
||||
Detached,
|
||||
Shown,
|
||||
Hidden,
|
||||
Activated,
|
||||
Deactivated,
|
||||
FocusGained,
|
||||
FocusLost
|
||||
};
|
||||
|
||||
std::string_view GetUIEditorPanelHostLifecycleEventKindName(
|
||||
UIEditorPanelHostLifecycleEventKind kind);
|
||||
|
||||
struct UIEditorPanelHostState {
|
||||
std::string panelId = {};
|
||||
bool attached = false;
|
||||
bool visible = false;
|
||||
bool active = false;
|
||||
bool focused = false;
|
||||
};
|
||||
|
||||
struct UIEditorPanelHostLifecycleEvent {
|
||||
UIEditorPanelHostLifecycleEventKind kind = UIEditorPanelHostLifecycleEventKind::Attached;
|
||||
std::string panelId = {};
|
||||
};
|
||||
|
||||
struct UIEditorPanelHostLifecycleState {
|
||||
std::vector<UIEditorPanelHostState> panelStates = {};
|
||||
};
|
||||
|
||||
struct UIEditorPanelHostLifecycleRequest {
|
||||
std::string focusedPanelId = {};
|
||||
};
|
||||
|
||||
struct UIEditorPanelHostLifecycleFrame {
|
||||
std::vector<UIEditorPanelHostState> panelStates = {};
|
||||
std::vector<UIEditorPanelHostLifecycleEvent> events = {};
|
||||
};
|
||||
|
||||
const UIEditorPanelHostState* FindUIEditorPanelHostState(
|
||||
const UIEditorPanelHostLifecycleState& state,
|
||||
std::string_view panelId);
|
||||
|
||||
const UIEditorPanelHostState* FindUIEditorPanelHostState(
|
||||
const UIEditorPanelHostLifecycleFrame& frame,
|
||||
std::string_view panelId);
|
||||
|
||||
UIEditorPanelHostLifecycleFrame UpdateUIEditorPanelHostLifecycle(
|
||||
UIEditorPanelHostLifecycleState& state,
|
||||
const UIEditorPanelRegistry& panelRegistry,
|
||||
const UIEditorWorkspaceModel& workspace,
|
||||
const UIEditorWorkspaceSession& session,
|
||||
const UIEditorPanelHostLifecycleRequest& request = {});
|
||||
|
||||
} // namespace XCEngine::UI::Editor
|
||||
207
new_editor/src/Core/UIEditorPanelHostLifecycle.cpp
Normal file
207
new_editor/src/Core/UIEditorPanelHostLifecycle.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
#include <XCEditor/Core/UIEditorPanelHostLifecycle.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
namespace XCEngine::UI::Editor {
|
||||
|
||||
namespace {
|
||||
|
||||
using HostStateMap = std::unordered_map<std::string_view, const UIEditorPanelHostState*>;
|
||||
|
||||
HostStateMap BuildHostStateMap(const std::vector<UIEditorPanelHostState>& states) {
|
||||
HostStateMap map = {};
|
||||
map.reserve(states.size());
|
||||
for (const UIEditorPanelHostState& state : states) {
|
||||
map.emplace(state.panelId, &state);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
const UIEditorPanelHostState* FindHostState(
|
||||
const std::vector<UIEditorPanelHostState>& states,
|
||||
std::string_view panelId) {
|
||||
for (const UIEditorPanelHostState& state : states) {
|
||||
if (state.panelId == panelId) {
|
||||
return &state;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AppendLeaveEvents(
|
||||
std::vector<UIEditorPanelHostLifecycleEvent>& events,
|
||||
const std::vector<UIEditorPanelHostState>& previousStates,
|
||||
const HostStateMap& currentStateMap) {
|
||||
auto appendCategory = [&](auto predicate, UIEditorPanelHostLifecycleEventKind kind) {
|
||||
for (const UIEditorPanelHostState& previous : previousStates) {
|
||||
const UIEditorPanelHostState emptyState = {};
|
||||
const UIEditorPanelHostState& current =
|
||||
currentStateMap.contains(previous.panelId)
|
||||
? *currentStateMap.at(previous.panelId)
|
||||
: emptyState;
|
||||
if (predicate(previous, current)) {
|
||||
events.push_back({ kind, previous.panelId });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
appendCategory(
|
||||
[](const UIEditorPanelHostState& previous, const UIEditorPanelHostState& current) {
|
||||
return previous.focused && !current.focused;
|
||||
},
|
||||
UIEditorPanelHostLifecycleEventKind::FocusLost);
|
||||
appendCategory(
|
||||
[](const UIEditorPanelHostState& previous, const UIEditorPanelHostState& current) {
|
||||
return previous.active && !current.active;
|
||||
},
|
||||
UIEditorPanelHostLifecycleEventKind::Deactivated);
|
||||
appendCategory(
|
||||
[](const UIEditorPanelHostState& previous, const UIEditorPanelHostState& current) {
|
||||
return previous.visible && !current.visible;
|
||||
},
|
||||
UIEditorPanelHostLifecycleEventKind::Hidden);
|
||||
appendCategory(
|
||||
[](const UIEditorPanelHostState& previous, const UIEditorPanelHostState& current) {
|
||||
return previous.attached && !current.attached;
|
||||
},
|
||||
UIEditorPanelHostLifecycleEventKind::Detached);
|
||||
}
|
||||
|
||||
void AppendEnterEvents(
|
||||
std::vector<UIEditorPanelHostLifecycleEvent>& events,
|
||||
const std::vector<UIEditorPanelHostState>& currentStates,
|
||||
const HostStateMap& previousStateMap) {
|
||||
auto appendCategory = [&](auto predicate, UIEditorPanelHostLifecycleEventKind kind) {
|
||||
for (const UIEditorPanelHostState& current : currentStates) {
|
||||
const UIEditorPanelHostState emptyState = {};
|
||||
const UIEditorPanelHostState& previous =
|
||||
previousStateMap.contains(current.panelId)
|
||||
? *previousStateMap.at(current.panelId)
|
||||
: emptyState;
|
||||
if (predicate(previous, current)) {
|
||||
events.push_back({ kind, current.panelId });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
appendCategory(
|
||||
[](const UIEditorPanelHostState& previous, const UIEditorPanelHostState& current) {
|
||||
return !previous.attached && current.attached;
|
||||
},
|
||||
UIEditorPanelHostLifecycleEventKind::Attached);
|
||||
appendCategory(
|
||||
[](const UIEditorPanelHostState& previous, const UIEditorPanelHostState& current) {
|
||||
return !previous.visible && current.visible;
|
||||
},
|
||||
UIEditorPanelHostLifecycleEventKind::Shown);
|
||||
appendCategory(
|
||||
[](const UIEditorPanelHostState& previous, const UIEditorPanelHostState& current) {
|
||||
return !previous.active && current.active;
|
||||
},
|
||||
UIEditorPanelHostLifecycleEventKind::Activated);
|
||||
appendCategory(
|
||||
[](const UIEditorPanelHostState& previous, const UIEditorPanelHostState& current) {
|
||||
return !previous.focused && current.focused;
|
||||
},
|
||||
UIEditorPanelHostLifecycleEventKind::FocusGained);
|
||||
}
|
||||
|
||||
std::vector<UIEditorPanelHostState> BuildResolvedPanelHostStates(
|
||||
const UIEditorPanelRegistry& panelRegistry,
|
||||
const UIEditorWorkspaceModel& workspace,
|
||||
const UIEditorWorkspaceSession& session,
|
||||
const UIEditorPanelHostLifecycleRequest& request) {
|
||||
const std::vector<UIEditorWorkspaceVisiblePanel> visiblePanels =
|
||||
CollectUIEditorWorkspaceVisiblePanels(workspace, session);
|
||||
std::unordered_set<std::string_view> visiblePanelIds = {};
|
||||
visiblePanelIds.reserve(visiblePanels.size());
|
||||
for (const UIEditorWorkspaceVisiblePanel& panel : visiblePanels) {
|
||||
visiblePanelIds.insert(panel.panelId);
|
||||
}
|
||||
|
||||
std::vector<UIEditorPanelHostState> states = {};
|
||||
states.reserve(panelRegistry.panels.size());
|
||||
for (const UIEditorPanelDescriptor& descriptor : panelRegistry.panels) {
|
||||
if (!ContainsUIEditorWorkspacePanel(workspace, descriptor.panelId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const UIEditorPanelSessionState* sessionState =
|
||||
FindUIEditorPanelSessionState(session, descriptor.panelId);
|
||||
if (sessionState == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
UIEditorPanelHostState state = {};
|
||||
state.panelId = descriptor.panelId;
|
||||
state.attached = sessionState->open;
|
||||
state.visible = state.attached && visiblePanelIds.contains(state.panelId);
|
||||
state.active = state.visible && workspace.activePanelId == state.panelId;
|
||||
state.focused = state.active && request.focusedPanelId == state.panelId;
|
||||
states.push_back(std::move(state));
|
||||
}
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string_view GetUIEditorPanelHostLifecycleEventKindName(
|
||||
UIEditorPanelHostLifecycleEventKind kind) {
|
||||
switch (kind) {
|
||||
case UIEditorPanelHostLifecycleEventKind::Attached:
|
||||
return "Attached";
|
||||
case UIEditorPanelHostLifecycleEventKind::Detached:
|
||||
return "Detached";
|
||||
case UIEditorPanelHostLifecycleEventKind::Shown:
|
||||
return "Shown";
|
||||
case UIEditorPanelHostLifecycleEventKind::Hidden:
|
||||
return "Hidden";
|
||||
case UIEditorPanelHostLifecycleEventKind::Activated:
|
||||
return "Activated";
|
||||
case UIEditorPanelHostLifecycleEventKind::Deactivated:
|
||||
return "Deactivated";
|
||||
case UIEditorPanelHostLifecycleEventKind::FocusGained:
|
||||
return "FocusGained";
|
||||
case UIEditorPanelHostLifecycleEventKind::FocusLost:
|
||||
return "FocusLost";
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
const UIEditorPanelHostState* FindUIEditorPanelHostState(
|
||||
const UIEditorPanelHostLifecycleState& state,
|
||||
std::string_view panelId) {
|
||||
return FindHostState(state.panelStates, panelId);
|
||||
}
|
||||
|
||||
const UIEditorPanelHostState* FindUIEditorPanelHostState(
|
||||
const UIEditorPanelHostLifecycleFrame& frame,
|
||||
std::string_view panelId) {
|
||||
return FindHostState(frame.panelStates, panelId);
|
||||
}
|
||||
|
||||
UIEditorPanelHostLifecycleFrame UpdateUIEditorPanelHostLifecycle(
|
||||
UIEditorPanelHostLifecycleState& state,
|
||||
const UIEditorPanelRegistry& panelRegistry,
|
||||
const UIEditorWorkspaceModel& workspace,
|
||||
const UIEditorWorkspaceSession& session,
|
||||
const UIEditorPanelHostLifecycleRequest& request) {
|
||||
UIEditorPanelHostLifecycleFrame frame = {};
|
||||
frame.panelStates =
|
||||
BuildResolvedPanelHostStates(panelRegistry, workspace, session, request);
|
||||
|
||||
const HostStateMap previousStateMap = BuildHostStateMap(state.panelStates);
|
||||
const HostStateMap currentStateMap = BuildHostStateMap(frame.panelStates);
|
||||
AppendLeaveEvents(frame.events, state.panelStates, currentStateMap);
|
||||
AppendEnterEvents(frame.events, frame.panelStates, previousStateMap);
|
||||
|
||||
state.panelStates = frame.panelStates;
|
||||
return frame;
|
||||
}
|
||||
|
||||
} // namespace XCEngine::UI::Editor
|
||||
Reference in New Issue
Block a user