208 lines
7.7 KiB
C++
208 lines
7.7 KiB
C++
#include <XCEditor/Panels/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
|