Integrate XCUI runtime context into SceneRuntime
This commit is contained in:
@@ -4,13 +4,22 @@
|
||||
#include <XCEngine/Scripting/IScriptRuntime.h>
|
||||
#include <XCEngine/Scripting/ScriptComponent.h>
|
||||
#include <XCEngine/Scripting/ScriptEngine.h>
|
||||
#include <XCEngine/UI/Runtime/UIScreenStackController.h>
|
||||
#include <XCEngine/UI/Runtime/UIScreenTypes.h>
|
||||
#include <XCEngine/UI/Runtime/UISystem.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace XCEngine::Components;
|
||||
using namespace XCEngine::Scripting;
|
||||
using XCEngine::UI::Runtime::UIScreenAsset;
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -67,6 +76,61 @@ private:
|
||||
std::vector<std::string>* m_events = nullptr;
|
||||
};
|
||||
|
||||
class TempFileScope {
|
||||
public:
|
||||
TempFileScope(std::string stem, std::string extension, std::string contents) {
|
||||
const auto uniqueId = std::to_string(
|
||||
std::chrono::steady_clock::now().time_since_epoch().count());
|
||||
m_path = fs::temp_directory_path() / (std::move(stem) + "_" + uniqueId + std::move(extension));
|
||||
std::ofstream output(m_path, std::ios::binary | std::ios::trunc);
|
||||
output << contents;
|
||||
}
|
||||
|
||||
~TempFileScope() {
|
||||
std::error_code ec;
|
||||
fs::remove(m_path, ec);
|
||||
}
|
||||
|
||||
const fs::path& Path() const {
|
||||
return m_path;
|
||||
}
|
||||
|
||||
private:
|
||||
fs::path m_path = {};
|
||||
};
|
||||
|
||||
std::string BuildViewMarkup(const char* heroTitle) {
|
||||
return
|
||||
"<View name=\"Runtime Screen\">\n"
|
||||
" <Column id=\"root\" padding=\"18\" gap=\"10\">\n"
|
||||
" <Card id=\"hero\" title=\"" + std::string(heroTitle) + "\" subtitle=\"Shared XCUI runtime layer\" />\n"
|
||||
" <Text id=\"status\" text=\"Ready for play\" />\n"
|
||||
" </Column>\n"
|
||||
"</View>\n";
|
||||
}
|
||||
|
||||
UIScreenAsset BuildScreenAsset(const fs::path& viewPath, const char* screenId) {
|
||||
UIScreenAsset screen = {};
|
||||
screen.screenId = screenId;
|
||||
screen.documentPath = viewPath.string();
|
||||
return screen;
|
||||
}
|
||||
|
||||
bool DrawDataContainsText(
|
||||
const XCEngine::UI::UIDrawData& drawData,
|
||||
const std::string& text) {
|
||||
for (const XCEngine::UI::UIDrawList& drawList : drawData.GetDrawLists()) {
|
||||
for (const XCEngine::UI::UIDrawCommand& command : drawList.GetCommands()) {
|
||||
if (command.type == XCEngine::UI::UIDrawCommandType::Text &&
|
||||
command.text == text) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
class RecordingScriptRuntime : public IScriptRuntime {
|
||||
public:
|
||||
explicit RecordingScriptRuntime(std::vector<std::string>* events)
|
||||
@@ -304,4 +368,66 @@ TEST_F(SceneRuntimeTest, StartingNewSceneStopsPreviousRuntimeFirst) {
|
||||
runtime.Stop();
|
||||
}
|
||||
|
||||
TEST_F(SceneRuntimeTest, UpdateTicksUiRuntimeAndClearsQueuedInputEvents) {
|
||||
Scene* runtimeScene = CreateScene("RuntimeScene");
|
||||
runtime.Start(runtimeScene);
|
||||
runtime.SetUIViewportRect(XCEngine::UI::UIRect(0.0f, 0.0f, 800.0f, 480.0f));
|
||||
runtime.SetUIFocused(true);
|
||||
|
||||
TempFileScope menuView("xcui_scene_runtime_menu", ".xcui", BuildViewMarkup("Runtime Menu"));
|
||||
const auto layerId = runtime.GetUIScreenStackController().PushMenu(
|
||||
BuildScreenAsset(menuView.Path(), "runtime.menu"),
|
||||
"menu");
|
||||
ASSERT_NE(layerId, 0u);
|
||||
|
||||
XCEngine::UI::UIInputEvent textEvent = {};
|
||||
textEvent.type = XCEngine::UI::UIInputEventType::Character;
|
||||
textEvent.character = 'A';
|
||||
runtime.QueueUIInputEvent(textEvent);
|
||||
|
||||
runtime.Update(0.016f);
|
||||
|
||||
const auto& firstFrame = runtime.GetLastUIFrame();
|
||||
ASSERT_EQ(firstFrame.presentedLayerCount, 1u);
|
||||
ASSERT_EQ(firstFrame.layers.size(), 1u);
|
||||
EXPECT_EQ(firstFrame.frameIndex, 1u);
|
||||
EXPECT_EQ(firstFrame.layers.front().stats.inputEventCount, 1u);
|
||||
EXPECT_TRUE(DrawDataContainsText(firstFrame.drawData, "Runtime Menu"));
|
||||
|
||||
runtime.Update(0.016f);
|
||||
|
||||
const auto& secondFrame = runtime.GetLastUIFrame();
|
||||
ASSERT_EQ(secondFrame.presentedLayerCount, 1u);
|
||||
ASSERT_EQ(secondFrame.layers.size(), 1u);
|
||||
EXPECT_EQ(secondFrame.frameIndex, 2u);
|
||||
EXPECT_EQ(secondFrame.layers.front().stats.inputEventCount, 0u);
|
||||
}
|
||||
|
||||
TEST_F(SceneRuntimeTest, StopClearsUiRuntimeState) {
|
||||
Scene* runtimeScene = CreateScene("RuntimeScene");
|
||||
runtime.Start(runtimeScene);
|
||||
runtime.SetUIViewportRect(XCEngine::UI::UIRect(0.0f, 0.0f, 800.0f, 480.0f));
|
||||
runtime.SetUIFocused(true);
|
||||
|
||||
TempFileScope menuView("xcui_scene_runtime_pause", ".xcui", BuildViewMarkup("Pause Menu"));
|
||||
const auto layerId = runtime.GetUIScreenStackController().PushMenu(
|
||||
BuildScreenAsset(menuView.Path(), "runtime.pause"),
|
||||
"pause");
|
||||
ASSERT_NE(layerId, 0u);
|
||||
|
||||
runtime.Update(0.016f);
|
||||
ASSERT_EQ(runtime.GetUISystem().GetLayerCount(), 1u);
|
||||
ASSERT_EQ(runtime.GetUIScreenStackController().GetEntryCount(), 1u);
|
||||
ASSERT_EQ(runtime.GetLastUIFrame().presentedLayerCount, 1u);
|
||||
|
||||
runtime.Stop();
|
||||
|
||||
EXPECT_FALSE(runtime.IsRunning());
|
||||
EXPECT_EQ(runtime.GetScene(), nullptr);
|
||||
EXPECT_EQ(runtime.GetUISystem().GetLayerCount(), 0u);
|
||||
EXPECT_EQ(runtime.GetUIScreenStackController().GetEntryCount(), 0u);
|
||||
EXPECT_EQ(runtime.GetLastUIFrame().presentedLayerCount, 0u);
|
||||
EXPECT_TRUE(runtime.GetLastUIFrame().layers.empty());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user