Add XCUI runtime screen stack helper

This commit is contained in:
2026-04-05 06:05:54 +08:00
parent f185663259
commit 0c24c7c611
5 changed files with 273 additions and 1 deletions

View File

@@ -522,6 +522,7 @@ add_library(XCEngine STATIC
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/UI/Runtime/UISystem.h
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/Runtime/UIScreenDocumentHost.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/Runtime/UIScreenPlayer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/Runtime/UIScreenStackController.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/Runtime/UISystem.cpp
# Input
@@ -587,6 +588,9 @@ target_link_libraries(XCEngine PUBLIC
)
if(MSVC)
target_compile_options(XCEngine PRIVATE
/FS
$<$<CONFIG:Debug,RelWithDebInfo>:/Z7>)
target_link_libraries(XCEngine PUBLIC delayimp)
target_link_options(XCEngine INTERFACE "/DELAYLOAD:assimp-vc143-mt.dll")
set_target_properties(XCEngine PROPERTIES

View File

@@ -0,0 +1,54 @@
#pragma once
#include <XCEngine/UI/Runtime/UISystem.h>
#include <cstddef>
#include <string>
#include <vector>
namespace XCEngine {
namespace UI {
namespace Runtime {
struct UIScreenStackEntry {
UIScreenLayerId layerId = 0;
UIScreenAsset asset = {};
UIScreenLayerOptions options = {};
};
class UIScreenStackController {
public:
explicit UIScreenStackController(UISystem& system);
UIScreenLayerId PushScreen(
const UIScreenAsset& asset,
const UIScreenLayerOptions& options = UIScreenLayerOptions());
UIScreenLayerId PushMenu(
const UIScreenAsset& asset,
const std::string& debugName = {});
UIScreenLayerId PushModal(
const UIScreenAsset& asset,
const std::string& debugName = {});
UIScreenLayerId PushHud(
const UIScreenAsset& asset,
const std::string& debugName = {});
bool ReplaceTop(
const UIScreenAsset& asset,
const UIScreenLayerOptions& options = UIScreenLayerOptions());
bool Pop();
bool Remove(UIScreenLayerId layerId);
void Clear();
std::size_t GetEntryCount() const;
const UIScreenStackEntry* GetTop() const;
const std::vector<UIScreenStackEntry>& GetEntries() const;
private:
UISystem* m_system = nullptr;
std::vector<UIScreenStackEntry> m_entries = {};
};
} // namespace Runtime
} // namespace UI
} // namespace XCEngine

View File

@@ -0,0 +1,148 @@
#include <XCEngine/UI/Runtime/UIScreenStackController.h>
#include <utility>
namespace XCEngine {
namespace UI {
namespace Runtime {
namespace {
std::string ResolveDebugName(
const UIScreenAsset& asset,
const std::string& fallbackName,
const std::string& explicitName) {
if (!explicitName.empty()) {
return explicitName;
}
if (!asset.screenId.empty()) {
return asset.screenId;
}
return fallbackName;
}
} // namespace
UIScreenStackController::UIScreenStackController(UISystem& system)
: m_system(&system) {
}
UIScreenLayerId UIScreenStackController::PushScreen(
const UIScreenAsset& asset,
const UIScreenLayerOptions& options) {
const UIScreenLayerId layerId = m_system != nullptr
? m_system->PushScreen(asset, options)
: 0;
if (layerId == 0) {
return 0;
}
UIScreenStackEntry entry = {};
entry.layerId = layerId;
entry.asset = asset;
entry.options = options;
m_entries.push_back(std::move(entry));
return layerId;
}
UIScreenLayerId UIScreenStackController::PushMenu(
const UIScreenAsset& asset,
const std::string& debugName) {
UIScreenLayerOptions options = {};
options.debugName = ResolveDebugName(asset, "Menu", debugName);
options.acceptsInput = true;
options.blocksLayersBelow = true;
return PushScreen(asset, options);
}
UIScreenLayerId UIScreenStackController::PushModal(
const UIScreenAsset& asset,
const std::string& debugName) {
UIScreenLayerOptions options = {};
options.debugName = ResolveDebugName(asset, "Modal", debugName);
options.acceptsInput = true;
options.blocksLayersBelow = true;
return PushScreen(asset, options);
}
UIScreenLayerId UIScreenStackController::PushHud(
const UIScreenAsset& asset,
const std::string& debugName) {
UIScreenLayerOptions options = {};
options.debugName = ResolveDebugName(asset, "HUD", debugName);
options.acceptsInput = false;
options.blocksLayersBelow = false;
return PushScreen(asset, options);
}
bool UIScreenStackController::ReplaceTop(
const UIScreenAsset& asset,
const UIScreenLayerOptions& options) {
if (m_entries.empty()) {
return PushScreen(asset, options) != 0;
}
if (!Pop()) {
return false;
}
return PushScreen(asset, options) != 0;
}
bool UIScreenStackController::Pop() {
if (m_system == nullptr || m_entries.empty()) {
return false;
}
const UIScreenLayerId layerId = m_entries.back().layerId;
if (!m_system->RemoveLayer(layerId)) {
return false;
}
m_entries.pop_back();
return true;
}
bool UIScreenStackController::Remove(UIScreenLayerId layerId) {
if (m_system == nullptr) {
return false;
}
for (std::size_t index = 0; index < m_entries.size(); ++index) {
if (m_entries[index].layerId != layerId) {
continue;
}
if (!m_system->RemoveLayer(layerId)) {
return false;
}
m_entries.erase(m_entries.begin() + static_cast<std::ptrdiff_t>(index));
return true;
}
return false;
}
void UIScreenStackController::Clear() {
if (m_system != nullptr) {
m_system->DestroyAllPlayers();
}
m_entries.clear();
}
std::size_t UIScreenStackController::GetEntryCount() const {
return m_entries.size();
}
const UIScreenStackEntry* UIScreenStackController::GetTop() const {
return m_entries.empty() ? nullptr : &m_entries.back();
}
const std::vector<UIScreenStackEntry>& UIScreenStackController::GetEntries() const {
return m_entries;
}
} // namespace Runtime
} // namespace UI
} // namespace XCEngine