Files
XCEngine/engine/src/UI/Runtime/UISystem.cpp

185 lines
5.4 KiB
C++

#include <XCEngine/UI/Runtime/UISystem.h>
#include <algorithm>
namespace XCEngine {
namespace UI {
namespace Runtime {
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;
}
return m_layerIds.empty() ? 0 : m_layerIds.back();
}
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;
}
bool UISystem::SetLayerOptions(
UIScreenLayerId layerId,
const UIScreenLayerOptions& options) {
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);
return index < m_layerOptions.size()
? &m_layerOptions[index]
: nullptr;
}
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;
std::vector<std::size_t> presentedIndices;
presentedIndices.reserve(m_players.size());
for (std::size_t index = m_players.size(); index > 0; --index) {
const std::size_t layerIndex = index - 1;
if (!m_layerOptions[layerIndex].visible) {
continue;
}
presentedIndices.push_back(layerIndex);
if (m_layerOptions[layerIndex].blocksLayersBelow) {
break;
}
}
std::reverse(presentedIndices.begin(), presentedIndices.end());
std::size_t interactiveLayerIndex = m_players.size();
for (std::size_t index = presentedIndices.size(); index > 0; --index) {
const std::size_t layerIndex = presentedIndices[index - 1];
if (m_layerOptions[layerIndex].acceptsInput) {
interactiveLayerIndex = layerIndex;
break;
}
}
for (const std::size_t layerIndex : presentedIndices) {
UIScreenFrameInput layerInput = input;
if (layerIndex != interactiveLayerIndex) {
layerInput.events.clear();
}
const UIScreenFrameResult& frame = m_players[layerIndex]->Update(layerInput);
for (const UIDrawList& drawList : frame.drawData.GetDrawLists()) {
m_lastFrame.drawData.AddDrawList(drawList);
}
UISystemPresentedLayer presentedLayer = {};
presentedLayer.layerId = m_layerIds[layerIndex];
if (const UIScreenAsset* asset = m_players[layerIndex]->GetAsset();
asset != nullptr) {
presentedLayer.asset = *asset;
}
presentedLayer.options = m_layerOptions[layerIndex];
presentedLayer.stats = frame.stats;
m_lastFrame.layers.push_back(std::move(presentedLayer));
if (m_lastFrame.errorMessage.empty() && !frame.errorMessage.empty()) {
m_lastFrame.errorMessage = frame.errorMessage;
}
}
m_lastFrame.presentedLayerCount = m_lastFrame.layers.size();
m_lastFrame.skippedLayerCount =
m_players.size() > m_lastFrame.presentedLayerCount
? m_players.size() - m_lastFrame.presentedLayerCount
: 0;
return m_lastFrame;
}
void UISystem::Tick(const UIScreenFrameInput& input) {
for (const std::unique_ptr<UIScreenPlayer>& player : m_players) {
if (player) {
player->Update(input);
}
}
}
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;
}
}
return m_layerIds.size();
}
} // namespace Runtime
} // namespace UI
} // namespace XCEngine