2026-04-05 05:14:16 +08:00
|
|
|
#include <XCEngine/UI/Runtime/UISystem.h>
|
|
|
|
|
|
|
|
|
|
namespace XCEngine {
|
|
|
|
|
namespace UI {
|
|
|
|
|
namespace Runtime {
|
|
|
|
|
|
2026-04-05 05:44:07 +08:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
std::size_t FindTopInputLayerIndex(
|
|
|
|
|
const std::vector<UIScreenLayerOptions>& layerOptions,
|
|
|
|
|
std::size_t lowestPresentedIndex) {
|
|
|
|
|
if (layerOptions.empty() || lowestPresentedIndex >= layerOptions.size()) {
|
|
|
|
|
return static_cast<std::size_t>(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (std::size_t index = layerOptions.size(); index-- > lowestPresentedIndex;) {
|
|
|
|
|
if (layerOptions[index].visible && layerOptions[index].acceptsInput) {
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return static_cast<std::size_t>(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::size_t FindLowestPresentedLayerIndex(const std::vector<UIScreenLayerOptions>& layerOptions) {
|
|
|
|
|
if (layerOptions.empty()) {
|
|
|
|
|
return 0u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (std::size_t index = layerOptions.size(); index-- > 0u;) {
|
|
|
|
|
if (layerOptions[index].visible && layerOptions[index].blocksLayersBelow) {
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
2026-04-05 05:14:16 +08:00
|
|
|
UISystem::UISystem(IUIScreenDocumentHost& documentHost)
|
|
|
|
|
: m_documentHost(&documentHost) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UIScreenPlayer& UISystem::CreatePlayer(const UIScreenLayerOptions& options) {
|
|
|
|
|
m_players.push_back(std::make_unique<UIScreenPlayer>(*m_documentHost));
|
|
|
|
|
m_layerIds.push_back(m_nextLayerId++);
|
|
|
|
|
m_layerOptions.push_back(options);
|
|
|
|
|
return *m_players.back();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UIScreenLayerId UISystem::PushScreen(
|
|
|
|
|
const UIScreenAsset& asset,
|
|
|
|
|
const UIScreenLayerOptions& options) {
|
|
|
|
|
UIScreenPlayer& player = CreatePlayer(options);
|
|
|
|
|
if (!player.Load(asset)) {
|
|
|
|
|
m_players.pop_back();
|
|
|
|
|
m_layerIds.pop_back();
|
|
|
|
|
m_layerOptions.pop_back();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2026-04-05 05:44:07 +08:00
|
|
|
|
|
|
|
|
return m_layerIds.back();
|
2026-04-05 05:14:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UISystem::RemoveLayer(UIScreenLayerId layerId) {
|
|
|
|
|
const std::size_t index = FindLayerIndex(layerId);
|
|
|
|
|
if (index >= m_players.size()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_players.erase(m_players.begin() + static_cast<std::ptrdiff_t>(index));
|
|
|
|
|
m_layerIds.erase(m_layerIds.begin() + static_cast<std::ptrdiff_t>(index));
|
|
|
|
|
m_layerOptions.erase(m_layerOptions.begin() + static_cast<std::ptrdiff_t>(index));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UISystem::SetLayerVisibility(UIScreenLayerId layerId, bool visible) {
|
|
|
|
|
const std::size_t index = FindLayerIndex(layerId);
|
|
|
|
|
if (index >= m_layerOptions.size()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_layerOptions[index].visible = visible;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-05 05:44:07 +08:00
|
|
|
bool UISystem::SetLayerOptions(UIScreenLayerId layerId, const UIScreenLayerOptions& options) {
|
2026-04-05 05:14:16 +08:00
|
|
|
const std::size_t index = FindLayerIndex(layerId);
|
|
|
|
|
if (index >= m_layerOptions.size()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_layerOptions[index] = options;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const UIScreenLayerOptions* UISystem::FindLayerOptions(UIScreenLayerId layerId) const {
|
|
|
|
|
const std::size_t index = FindLayerIndex(layerId);
|
2026-04-05 05:44:07 +08:00
|
|
|
return index < m_layerOptions.size() ? &m_layerOptions[index] : nullptr;
|
2026-04-05 05:14:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UIScreenLayerId UISystem::GetLayerId(std::size_t index) const {
|
|
|
|
|
return index < m_layerIds.size() ? m_layerIds[index] : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UISystem::DestroyAllPlayers() {
|
|
|
|
|
m_players.clear();
|
|
|
|
|
m_layerIds.clear();
|
|
|
|
|
m_layerOptions.clear();
|
|
|
|
|
m_lastFrame = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::size_t UISystem::GetPlayerCount() const {
|
|
|
|
|
return m_players.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::size_t UISystem::GetLayerCount() const {
|
|
|
|
|
return m_layerIds.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const UISystemFrameResult& UISystem::Update(const UIScreenFrameInput& input) {
|
|
|
|
|
m_lastFrame = {};
|
|
|
|
|
m_lastFrame.frameIndex = input.frameIndex;
|
|
|
|
|
|
2026-04-05 05:44:07 +08:00
|
|
|
if (m_players.empty()) {
|
|
|
|
|
return m_lastFrame;
|
2026-04-05 05:14:16 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-05 05:44:07 +08:00
|
|
|
const std::size_t lowestPresentedIndex = FindLowestPresentedLayerIndex(m_layerOptions);
|
|
|
|
|
const std::size_t inputLayerIndex = FindTopInputLayerIndex(m_layerOptions, lowestPresentedIndex);
|
2026-04-05 05:14:16 +08:00
|
|
|
|
2026-04-05 05:44:07 +08:00
|
|
|
for (std::size_t index = 0; index < lowestPresentedIndex && index < m_players.size(); ++index) {
|
|
|
|
|
++m_lastFrame.skippedLayerCount;
|
2026-04-05 05:14:16 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-05 05:44:07 +08:00
|
|
|
for (std::size_t index = lowestPresentedIndex; index < m_players.size(); ++index) {
|
|
|
|
|
if (!m_layerOptions[index].visible) {
|
|
|
|
|
++m_lastFrame.skippedLayerCount;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-05 05:14:16 +08:00
|
|
|
UIScreenFrameInput layerInput = input;
|
2026-04-05 05:44:07 +08:00
|
|
|
if (index != inputLayerIndex) {
|
2026-04-05 05:14:16 +08:00
|
|
|
layerInput.events.clear();
|
2026-04-05 05:44:07 +08:00
|
|
|
layerInput.focused = false;
|
2026-04-05 05:14:16 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-05 05:44:07 +08:00
|
|
|
const UIScreenFrameResult& layerFrame = m_players[index]->Update(layerInput);
|
|
|
|
|
for (const UIDrawList& drawList : layerFrame.drawData.GetDrawLists()) {
|
2026-04-05 05:14:16 +08:00
|
|
|
m_lastFrame.drawData.AddDrawList(drawList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UISystemPresentedLayer presentedLayer = {};
|
2026-04-05 05:44:07 +08:00
|
|
|
presentedLayer.layerId = m_layerIds[index];
|
|
|
|
|
if (const UIScreenAsset* asset = m_players[index]->GetAsset(); asset != nullptr) {
|
2026-04-05 05:14:16 +08:00
|
|
|
presentedLayer.asset = *asset;
|
|
|
|
|
}
|
2026-04-05 05:44:07 +08:00
|
|
|
presentedLayer.options = m_layerOptions[index];
|
|
|
|
|
presentedLayer.stats = layerFrame.stats;
|
2026-04-05 05:14:16 +08:00
|
|
|
m_lastFrame.layers.push_back(std::move(presentedLayer));
|
2026-04-05 05:44:07 +08:00
|
|
|
++m_lastFrame.presentedLayerCount;
|
2026-04-05 05:14:16 +08:00
|
|
|
|
2026-04-05 05:44:07 +08:00
|
|
|
if (m_lastFrame.errorMessage.empty() && !layerFrame.errorMessage.empty()) {
|
|
|
|
|
m_lastFrame.errorMessage = layerFrame.errorMessage;
|
2026-04-05 05:14:16 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return m_lastFrame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UISystem::Tick(const UIScreenFrameInput& input) {
|
2026-04-05 05:44:07 +08:00
|
|
|
Update(input);
|
2026-04-05 05:14:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const UISystemFrameResult& UISystem::GetLastFrame() const {
|
|
|
|
|
return m_lastFrame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::vector<std::unique_ptr<UIScreenPlayer>>& UISystem::GetPlayers() const {
|
|
|
|
|
return m_players;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::size_t UISystem::FindLayerIndex(UIScreenLayerId layerId) const {
|
|
|
|
|
for (std::size_t index = 0; index < m_layerIds.size(); ++index) {
|
|
|
|
|
if (m_layerIds[index] == layerId) {
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-05 05:44:07 +08:00
|
|
|
return static_cast<std::size_t>(-1);
|
2026-04-05 05:14:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Runtime
|
|
|
|
|
} // namespace UI
|
|
|
|
|
} // namespace XCEngine
|