From 3b148b76c43ede05610f764aa2af45db5f4bfa77 Mon Sep 17 00:00:00 2001 From: antopilo Date: Fri, 13 Sep 2024 00:51:34 -0400 Subject: [PATCH] Started to expose DOM to C# API with support for custom nodes. Currently crash when doing FindNodeByID --- Nuake/src/Resource/ResourceLoader.cpp | 1 - Nuake/src/Resource/UI.cpp | 6 +- Nuake/src/Resource/UI.h | 1 + Nuake/src/Scene/Systems/ScriptingSystem.cpp | 20 +++- Nuake/src/Scripting/NetModules/UINetAPI.cpp | 123 ++++++++++++++++++++ Nuake/src/Scripting/NetModules/UINetAPI.h | 15 +++ Nuake/src/Scripting/ScriptingEngineNet.cpp | 21 ++-- Nuake/src/Scripting/ScriptingEngineNet.h | 9 +- Nuake/src/UI/Nodes/Canvas.cpp | 68 +++++++---- Nuake/src/UI/Nodes/Canvas.h | 20 +++- Nuake/src/UI/Nodes/Node.cpp | 24 +++- Nuake/src/UI/Nodes/Node.h | 19 +-- Nuake/src/UI/Nodes/Text.cpp | 13 ++- Nuake/src/UI/Nodes/Text.h | 1 + Nuake/src/UI/Parsers/CanvasParser.cpp | 19 ++- Nuake/src/UI/Parsers/CanvasParser.h | 10 +- NuakeNet/src/Components.cs | 2 +- NuakeNet/src/UI/UIComponent.cs | 108 ++++++++++++++--- 18 files changed, 390 insertions(+), 90 deletions(-) create mode 100644 Nuake/src/Scripting/NetModules/UINetAPI.cpp create mode 100644 Nuake/src/Scripting/NetModules/UINetAPI.h diff --git a/Nuake/src/Resource/ResourceLoader.cpp b/Nuake/src/Resource/ResourceLoader.cpp index 8186590e..fbb25949 100644 --- a/Nuake/src/Resource/ResourceLoader.cpp +++ b/Nuake/src/Resource/ResourceLoader.cpp @@ -98,7 +98,6 @@ Ref ResourceLoader::LoadModel(const std::string& path) Ref ResourceLoader::LoadUI(const std::string& path) { auto uiResource = CreateRef(path); - uiResource->ID = UUID(); return uiResource; } diff --git a/Nuake/src/Resource/UI.cpp b/Nuake/src/Resource/UI.cpp index 5ec6647d..c6f2de17 100644 --- a/Nuake/src/Resource/UI.cpp +++ b/Nuake/src/Resource/UI.cpp @@ -24,7 +24,9 @@ UIResource::UIResource(const std::string& path) : inputManager = new MyInputManager(*Engine::GetCurrentWindow()); } - canvas = CanvasParser::Get().Parse(FileSystem::RelativeToAbsolute(path)); + canvas = Canvas::New(); + canvas->uuid = this->ID; + canvas = CanvasParser::Get().Parse(canvas, FileSystem::RelativeToAbsolute(path)); canvas->SetInputManager(inputManager); canvas->ComputeLayout(defaultSize); } @@ -65,7 +67,7 @@ void UIResource::Reload() return; } - canvas = CanvasParser::Get().Parse(FileSystem::RelativeToAbsolute(filePath)); + canvas = CanvasParser::Get().Parse(canvas, FileSystem::RelativeToAbsolute(filePath)); if (canvas) { canvas->SetInputManager(inputManager); diff --git a/Nuake/src/Resource/UI.h b/Nuake/src/Resource/UI.h index be387241..c50b3c3e 100644 --- a/Nuake/src/Resource/UI.h +++ b/Nuake/src/Resource/UI.h @@ -26,6 +26,7 @@ namespace Nuake void Reload(); Ref GetOutputTexture() const; + Ref GetCanvas() { return canvas; } private: Ref canvas; diff --git a/Nuake/src/Scene/Systems/ScriptingSystem.cpp b/Nuake/src/Scene/Systems/ScriptingSystem.cpp index 841cd4c4..2e8cd43b 100644 --- a/Nuake/src/Scene/Systems/ScriptingSystem.cpp +++ b/Nuake/src/Scene/Systems/ScriptingSystem.cpp @@ -65,7 +65,7 @@ namespace Nuake // Instantiate UI widgets for (auto& uiWidget : CanvasParser::Get().GetAllCustomWidgetInstance()) { - scriptingEngineNet.RegisterCustomWidgetInstance(uiWidget.first, uiWidget.second); + scriptingEngineNet.RegisterCustomWidgetInstance(uiWidget.first.first, uiWidget.first.second, uiWidget.second); } // Call OnInit on entity script instances @@ -84,10 +84,11 @@ namespace Nuake // Call OnInit on UI widgets for (auto& widget : CanvasParser::Get().GetAllCustomWidgetInstance()) { - const UUID& widgetInstanceUUID = widget.first; - if (scriptingEngineNet.HasCustomWidgetInstance(widgetInstanceUUID)) + const UUID& canvasInstanceUUID = widget.first.first; + const UUID& widgetInstanceUUID = widget.first.second; + if (scriptingEngineNet.HasCustomWidgetInstance(canvasInstanceUUID, widgetInstanceUUID)) { - auto widgetInstance = scriptingEngineNet.GetCustomWidgetInstance(widgetInstanceUUID); + auto widgetInstance = scriptingEngineNet.GetCustomWidgetInstance(canvasInstanceUUID, widgetInstanceUUID); widgetInstance.InvokeMethod("OnInit"); } } @@ -157,6 +158,17 @@ namespace Nuake scriptInstance.InvokeMethod("OnUpdate", ts.GetSeconds()); } + for (auto& widget : CanvasParser::Get().GetAllCustomWidgetInstance()) + { + const UUID& canvasInstanceUUID = widget.first.first; + const UUID& widgetInstanceUUID = widget.first.second; + if (scriptingEngineNet.HasCustomWidgetInstance(canvasInstanceUUID, widgetInstanceUUID)) + { + auto widgetInstance = scriptingEngineNet.GetCustomWidgetInstance(canvasInstanceUUID, widgetInstanceUUID); + widgetInstance.InvokeMethod("OnTick", ts.GetSeconds()); + } + } + DispatchPhysicCallbacks(); } diff --git a/Nuake/src/Scripting/NetModules/UINetAPI.cpp b/Nuake/src/Scripting/NetModules/UINetAPI.cpp new file mode 100644 index 00000000..0c917102 --- /dev/null +++ b/Nuake/src/Scripting/NetModules/UINetAPI.cpp @@ -0,0 +1,123 @@ +#include "UINetAPI.h" +#include "src/Core/Core.h" +#include +#include +#include "src/Resource/UUID.h" +#include "src/UI/Nodes/Canvas.h" +#include "src/UI/Nodes/Text.h" + +#include + +#include + + +using namespace Nuake; + +UUID UUIDFromString(const std::string& input) +{ + return std::stoull(input); +} + +uint64_t FindChildByIDIcall(const Coral::String& canvasUUID, const Coral::String& id, const Coral::String& id2) +{ + if (!ResourceManager::IsResourceLoaded(UUIDFromString(canvasUUID))) + { + Logger::Log("Error finding child, canvas is not loaded.", ".net/ui", CRITICAL); + return UUID(0); + } + + Ref uiResource = ResourceManager::GetResource(UUIDFromString(canvasUUID)); + Ref canvas = uiResource->GetCanvas(); + if(Ref searchNode = canvas->GetNodeByUUID(UUIDFromString(id)); + searchNode != nullptr) + { + Ref foundNode; + if (foundNode->FindChildByID(id2, foundNode)) + { + return foundNode->GetScriptingID(); + } + } + + return UUID(0); +} + +bool HasNativeInstanceICall(const Coral::String& canvasUUID, const Coral::String& nodeUUID, const Coral::String& nodeUUID2) +{ + if (!ResourceManager::IsResourceLoaded(UUIDFromString(canvasUUID))) + { + Logger::Log("Error finding child, canvas is not loaded." + std::string(canvasUUID), ".net/ui", CRITICAL); + return UUID(0); + } + + Ref uiResource = ResourceManager::GetResource(UUIDFromString(canvasUUID)); + Ref canvas = uiResource->GetCanvas(); + if (Ref node = canvas->GetNodeByUUID(UUIDFromString(nodeUUID)); + node != nullptr) + { + if (ScriptingEngineNet::Get().HasCustomWidgetInstance(UUIDFromString(canvasUUID), UUIDFromString(nodeUUID))) + { + return true; + } + + return false; + } + + return false; +} + +Coral::ManagedObject GetNativeInstanceNodeICall(const Coral::String& canvasUUID, const Coral::String& nodeUUID) +{ + if (!ResourceManager::IsResourceLoaded(UUIDFromString(canvasUUID))) + { + Logger::Log("Error getting native instance of UI node, canvas is not loaded.", ".net/ui", CRITICAL); + return Coral::ManagedObject(); + } + + Ref uiResource = ResourceManager::GetResource(UUIDFromString(canvasUUID)); + Ref canvas = uiResource->GetCanvas(); + if(ScriptingEngineNet::Get().HasCustomWidgetInstance(UUIDFromString(canvasUUID), UUIDFromString(nodeUUID))) + { + return ScriptingEngineNet::Get().GetCustomWidgetInstance(UUIDFromString(canvasUUID), UUIDFromString(nodeUUID)); + } + + Logger::Log("Error getting native instance of UI node, custom widget doesnt have an instance", ".net/ui", CRITICAL); + return Coral::ManagedObject(); +} + +Coral::String GetTextNodeTextICall(const Coral::String& canvasUUID, const Coral::String& nodeUUID) +{ + if(!ResourceManager::IsResourceLoaded(UUIDFromString(canvasUUID))) + { + Logger::Log("Error getting native instance of UI node, canvas is not loaded.", ".net/ui", CRITICAL); + return Coral::String::New(""); + } + + Ref uiResource = ResourceManager::GetResource(UUIDFromString(canvasUUID)); + Ref canvas = uiResource->GetCanvas(); + Ref textNode = std::static_pointer_cast(canvas->GetNodeByUUID(UUIDFromString(nodeUUID))); + return Coral::String::New(textNode->GetText()); +} + +void SetTextNodeTextICall(const Coral::String& canvasUUID, const Coral::String& nodeUUID, Coral::String newText) +{ + if (!ResourceManager::IsResourceLoaded(UUIDFromString(canvasUUID))) + { + Logger::Log("Error getting native instance of UI node, canvas is not loaded.", ".net/ui", CRITICAL); + return; + } + + Ref uiResource = ResourceManager::GetResource(UUIDFromString(canvasUUID)); + Ref canvas = uiResource->GetCanvas(); + Ref textNode = std::static_pointer_cast(canvas->GetNodeByUUID(UUIDFromString(nodeUUID))); + textNode->SetText(newText); +} + +void UINetAPI::RegisterMethods() +{ + RegisterMethod("Node.FindChildByIDICall", &FindChildByIDIcall); + RegisterMethod("Node.HasNativeInstanceICall", &HasNativeInstanceICall); + RegisterMethod("Node.GetNativeInstanceNodeICall", &GetNativeInstanceNodeICall); + + RegisterMethod("TextNode.GetTextNodeTextICall", &GetTextNodeTextICall); + RegisterMethod("TextNode.SetTextNodeTextICall", &SetTextNodeTextICall); +} \ No newline at end of file diff --git a/Nuake/src/Scripting/NetModules/UINetAPI.h b/Nuake/src/Scripting/NetModules/UINetAPI.h new file mode 100644 index 00000000..18e72e04 --- /dev/null +++ b/Nuake/src/Scripting/NetModules/UINetAPI.h @@ -0,0 +1,15 @@ +#pragma once +#include "NetAPIModule.h" + +namespace Nuake +{ + + class UINetAPI : public NetAPIModule + { + public: + virtual const std::string GetModuleName() const override { return "UI"; } + + virtual void RegisterMethods() override; + + }; +} \ No newline at end of file diff --git a/Nuake/src/Scripting/ScriptingEngineNet.cpp b/Nuake/src/Scripting/ScriptingEngineNet.cpp index 1103a46f..289ba49f 100644 --- a/Nuake/src/Scripting/ScriptingEngineNet.cpp +++ b/Nuake/src/Scripting/ScriptingEngineNet.cpp @@ -10,6 +10,7 @@ #include "NetModules/EngineNetAPI.h" #include "NetModules/InputNetAPI.h" #include "NetModules/SceneNetAPI.h" +#include "NetModules/UINetAPI.h" #include @@ -53,7 +54,8 @@ namespace Nuake { CreateRef(), CreateRef(), - CreateRef() + CreateRef(), + CreateRef() }; for (auto& m : modules) @@ -289,7 +291,7 @@ namespace Nuake return uiWidgets[widgetName]; } - void ScriptingEngineNet::RegisterCustomWidgetInstance(const UUID& uuid, const std::string& widgetTypeName) + void ScriptingEngineNet::RegisterCustomWidgetInstance(const UUID& canvasUUID, const UUID& nodeUUID, const std::string& widgetTypeName) { if (uiWidgets.find(widgetTypeName) == uiWidgets.end()) { @@ -301,24 +303,25 @@ namespace Nuake } auto classInstance = uiWidgets[widgetTypeName].coralType->CreateInstance(); - classInstance.SetPropertyValue("ID", uuid); - widgetUUIDToManagedObjects[uuid] = classInstance; + classInstance.SetFieldValue("CanvasUUID", Coral::String::New(std::to_string(canvasUUID))); + classInstance.SetFieldValue("UUID", Coral::String::New(std::to_string(nodeUUID))); + widgetUUIDToManagedObjects[std::make_pair(canvasUUID, nodeUUID)] = classInstance; } - bool ScriptingEngineNet::HasCustomWidgetInstance(const UUID& uuid) + bool ScriptingEngineNet::HasCustomWidgetInstance(const UUID& canvasUUID, const UUID& uuid) { - return widgetUUIDToManagedObjects.contains(uuid); + return widgetUUIDToManagedObjects.contains(std::make_pair(canvasUUID, uuid)); } - Coral::ManagedObject ScriptingEngineNet::GetCustomWidgetInstance(const UUID& uuid) + Coral::ManagedObject ScriptingEngineNet::GetCustomWidgetInstance(const UUID& canvasUUID, const UUID& uuid) { - if (!HasCustomWidgetInstance(uuid)) + if (!HasCustomWidgetInstance(canvasUUID, uuid)) { Logger::Log("Failed to get custom widget .Net script instance, doesn't exist", ".net", CRITICAL); return Coral::ManagedObject(); } - return widgetUUIDToManagedObjects[uuid]; + return widgetUUIDToManagedObjects[std::make_pair(canvasUUID, uuid)]; } std::vector ScriptingEngineNet::BuildProjectAssembly(Ref project) diff --git a/Nuake/src/Scripting/ScriptingEngineNet.h b/Nuake/src/Scripting/ScriptingEngineNet.h index 28316704..2eb7a596 100644 --- a/Nuake/src/Scripting/ScriptingEngineNet.h +++ b/Nuake/src/Scripting/ScriptingEngineNet.h @@ -102,9 +102,9 @@ namespace Nuake bool HasUIWidget(const std::string& widgetName); UIWidgetObject& GetUIWidget(const std::string& widgetName); - void RegisterCustomWidgetInstance(const UUID& uuid, const std::string& widgetTypeName); - bool HasCustomWidgetInstance(const UUID& uuid); - Coral::ManagedObject GetCustomWidgetInstance(const UUID& uuid); + void RegisterCustomWidgetInstance(const UUID& canvasUUID, const UUID& nodeUUID, const std::string& widgetTypeName); + bool HasCustomWidgetInstance(const UUID& canvasUUID, const UUID& uuid); + Coral::ManagedObject GetCustomWidgetInstance(const UUID& canvasUUID, const UUID& uuid); std::unordered_map GetBrushEntities() const { return brushEntityTypes; } std::unordered_map GetPointEntities() const { return pointEntityTypes; } @@ -139,7 +139,8 @@ namespace Nuake std::unordered_map uiWidgets; std::unordered_map entityToManagedObjects; - std::unordered_map widgetUUIDToManagedObjects; + std::map, Coral::ManagedObject> widgetUUIDToManagedObjects; + ScriptingEngineNet(); ~ScriptingEngineNet(); diff --git a/Nuake/src/UI/Nodes/Canvas.cpp b/Nuake/src/UI/Nodes/Canvas.cpp index e6435afa..d9a23056 100644 --- a/Nuake/src/UI/Nodes/Canvas.cpp +++ b/Nuake/src/UI/Nodes/Canvas.cpp @@ -92,41 +92,52 @@ namespace NuakeUI for (auto& rule : mStyleSheet->Rules) { bool respectSelector = true; - for (StyleSelector& selector : rule.Selector) { bool foundSelector = false; - if (selector.Type == StyleSelectorType::Class) + switch (selector.Type) { - for (auto& c : node->Classes) + case StyleSelectorType::Class: { - if (c == selector.Value) - foundSelector = true; + for (auto& c : node->Classes) + { + if (c == selector.Value) + foundSelector = true; + } + break; } - } - else if (selector.Type == StyleSelectorType::Pseudo) - { - if (selector.Value == "hover" && node->State == NodeState::Hover) - foundSelector = true; - if (selector.Value == "active" && node->State == NodeState::Pressed) - foundSelector = true; - } - else if (selector.Type == StyleSelectorType::Id) - { - if (node->GetID() == selector.Value) - foundSelector = true; - } - else if (selector.Type == StyleSelectorType::Tag) - { - if (selector.Value == node->GetType()) + case StyleSelectorType::Pseudo: { - foundSelector = true; - + const bool isHover = selector.Value == "hover" && node->State == NodeState::Hover; + const bool isActive = selector.Value == "active" && node->State == NodeState::Clicked; + if (isHover || isActive) + { + foundSelector = true; + } + break; + } + case StyleSelectorType::Id: + { + if (selector.Value == node->GetID()) + { + foundSelector = true; + } + break; + } + case StyleSelectorType::Tag: + { + if (selector.Value == node->GetType()) + { + foundSelector = true; + } + break; } } if (!foundSelector) + { respectSelector = false; + } } if (respectSelector) @@ -149,6 +160,7 @@ namespace NuakeUI void Canvas::SetRoot(NodePtr root) { mRootNode = root; + root->canvasOwner = this; } void Canvas::SetInputManager(InputManager* inputManager) @@ -166,4 +178,14 @@ namespace NuakeUI mDirty = true; mStyleSheet = styleSheet; } + + Ref Canvas::GetNodeByUUID(const UUID& uuid) + { + if (!nodeCache.contains(uuid)) + { + return nullptr; + } + + return nodeCache[uuid]; + } } diff --git a/Nuake/src/UI/Nodes/Canvas.h b/Nuake/src/UI/Nodes/Canvas.h index e0af1086..109f898a 100644 --- a/Nuake/src/UI/Nodes/Canvas.h +++ b/Nuake/src/UI/Nodes/Canvas.h @@ -1,12 +1,15 @@ #pragma once #include "Node.h" -#include "../InputManager.h" -#include "../Styles/StyleSheet.h" +#include "src/Core/Maths.h" +#include "src/Resource/UUID.h" +#include "src/UI/InputManager.h" +#include "src/UI/Styles/StyleSheet.h" -#include #include "yoga/YGConfig.h" + #include + namespace NuakeUI { class Canvas; @@ -14,9 +17,13 @@ namespace NuakeUI class Canvas { + friend Node; + private: YGConfigRef mYogaConfig; + std::map> nodeCache; + std::string mFilePath = ""; InputManager* mInputManager; @@ -25,11 +32,16 @@ namespace NuakeUI NodePtr mRootNode; bool mDirty; + + public: static CanvasPtr New(); Canvas(); ~Canvas(); + UUID uuid = UUID(0); + UUID GetUUID() { return uuid; } + void Tick(); void Draw(); void ComputeLayout(Vector2 size); @@ -51,5 +63,7 @@ namespace NuakeUI return true; } + + Ref GetNodeByUUID(const UUID& uuid); }; } \ No newline at end of file diff --git a/Nuake/src/UI/Nodes/Node.cpp b/Nuake/src/UI/Nodes/Node.cpp index a2734abf..db759a34 100644 --- a/Nuake/src/UI/Nodes/Node.cpp +++ b/Nuake/src/UI/Nodes/Node.cpp @@ -4,10 +4,12 @@ #include "NodeState.h" #include "../StringHelper.h" +#include "src/UI/Nodes/Canvas.h" #include #include + namespace NuakeUI { NodePtr Node::New(const std::string id, const std::string& value) @@ -15,7 +17,10 @@ namespace NuakeUI return std::make_shared(id, value); } - Node::Node(const std::string& id, const std::string& value) : ID(id) + Node::Node(const std::string& id, const std::string& value) : + ID(id), + Type("div"), + canvasOwner(nullptr) { InitializeNode(); @@ -300,6 +305,14 @@ namespace NuakeUI } } + void Node::OnClick(InputManager * inputManager) + { + if (ScriptingEngineNet::Get().HasCustomWidgetInstance(canvasOwner->GetUUID(), scriptingId)) + { + ScriptingEngineNet::Get().GetCustomWidgetInstance(canvasOwner->GetUUID(), scriptingId).InvokeMethod("OnClick"); + } + } + bool Node::IsMouseHover(float x, float y) { YGNodeRef ygNode = GetYogaNode(); @@ -335,8 +348,17 @@ namespace NuakeUI if (!mHasBeenInitialized) InitializeNode(); + if (!canvasOwner) + { + assert(false && "cannot add a node if it is not part of canvas"); + } + child->Parent = this; + child->canvasOwner = canvasOwner; Childrens.push_back(child); + + canvasOwner->nodeCache[child->scriptingId] = child; + uint32_t index = (uint32_t)Childrens.size() - 1; YGNodeInsertChild(this->mNode, child->GetYogaNode(), index); } diff --git a/Nuake/src/UI/Nodes/Node.h b/Nuake/src/UI/Nodes/Node.h index f1d296f3..d3d85ee9 100644 --- a/Nuake/src/UI/Nodes/Node.h +++ b/Nuake/src/UI/Nodes/Node.h @@ -84,11 +84,13 @@ namespace NuakeUI class Node; class CanvasParser; class Renderer; + class Canvas; typedef std::shared_ptr NodePtr; class Node { + friend NuakeUI::Canvas; friend NuakeUI::CanvasParser; friend NuakeUI::Renderer; @@ -97,9 +99,11 @@ namespace NuakeUI UUID scriptingId; protected: + Canvas* canvasOwner; + + std::string Type = "node"; float ScrollDelta = 0.0f; std::string ID = ""; - std::string Type = "node"; Node* Parent = nullptr; std::vector Childrens = std::vector(); @@ -136,13 +140,7 @@ namespace NuakeUI void OnMouseHover(InputManager* inputManager) {}; void OnMouseExit(InputManager* inputManager) {}; - void OnClick(InputManager* inputManager) - { - if (ScriptingEngineNet::Get().HasCustomWidgetInstance(scriptingId)) - { - ScriptingEngineNet::Get().GetCustomWidgetInstance(scriptingId).InvokeMethod("OnClick"); - } - }; + void OnClick(InputManager* inputManager); void OnTick(InputManager* manager) {}; void OnClickReleased(InputManager* inputManager) {}; void OnScroll(InputManager* inputManager) {}; @@ -152,6 +150,11 @@ namespace NuakeUI scriptingId = uuid; } + UUID GetScriptingID() const + { + return scriptingId; + } + bool HasFocus() const; void GrabFocus(); void ReleaseFocus(); diff --git a/Nuake/src/UI/Nodes/Text.cpp b/Nuake/src/UI/Nodes/Text.cpp index 39ea7ed9..55b406e7 100644 --- a/Nuake/src/UI/Nodes/Text.cpp +++ b/Nuake/src/UI/Nodes/Text.cpp @@ -14,9 +14,9 @@ namespace NuakeUI Text::Text(const std::string& id, const std::string& text) { + Type = "text"; ID = id; mNode = YGNodeNew(); - mFont = Renderer::Get().mDefaultFont; SetText(text); @@ -40,6 +40,17 @@ namespace NuakeUI Calculate(); } + std::string Text::GetText() const + { + std::string result = ""; + for (const auto& line : Lines) + { + result += line + "\n"; + } + + return result; + } + void Text::Draw(int z) { const float width = YGNodeLayoutGetWidth(mNode); diff --git a/Nuake/src/UI/Nodes/Text.h b/Nuake/src/UI/Nodes/Text.h index c1960d7a..9df011b4 100644 --- a/Nuake/src/UI/Nodes/Text.h +++ b/Nuake/src/UI/Nodes/Text.h @@ -21,6 +21,7 @@ namespace NuakeUI ~Text() = default; void SetText(const std::string& text); + std::string GetText() const; void Calculate() override; void UpdateInput(InputManager* manager) override {}; diff --git a/Nuake/src/UI/Parsers/CanvasParser.cpp b/Nuake/src/UI/Parsers/CanvasParser.cpp index af4d02d1..5b75499a 100644 --- a/Nuake/src/UI/Parsers/CanvasParser.cpp +++ b/Nuake/src/UI/Parsers/CanvasParser.cpp @@ -250,12 +250,12 @@ bool CanvasParser::ScanCustomWidgets(tinyxml2::XMLElement* e, NodePtr node) // Let's parse the file auto firstNode = doc.FirstChildElement(); - IterateOverElement(firstNode, node); + IterateOverElement(firstNode, node, nodeTypeName); return true; } -void CanvasParser::IterateOverElement(tinyxml2::XMLElement* e, NodePtr node) +void CanvasParser::IterateOverElement(tinyxml2::XMLElement* e, NodePtr node, const std::string& customNodeName) { tinyxml2::XMLElement* current = e; while (current) @@ -272,17 +272,18 @@ void CanvasParser::IterateOverElement(tinyxml2::XMLElement* e, NodePtr node) // Let's keep fragments for now as they remove // the need to create a C# class for simple templating. ScanFragment(current, node); - bool hasScript = ScanCustomWidgets(current, node); + ScanCustomWidgets(current, node); // Let's add custom widgets to the DOM. NodePtr newNode = CreateNodeFromXML(current, id); if (newNode) { - if (hasScript) + if (!customNodeName.empty()) { + // Allow to link between C# script and node using a UUID UUID scriptingId = UUID(); - node->SetScriptingID(scriptingId); - customWidgetIDs.push_back(std::make_pair(scriptingId, current->Value())); + newNode->SetScriptingID(scriptingId); + customWidgetIDs.push_back(std::make_pair(std::make_pair(node->canvasOwner->uuid, scriptingId), customNodeName)); } AddClassesToNode(current, newNode); @@ -301,7 +302,7 @@ void CanvasParser::IterateOverElement(tinyxml2::XMLElement* e, NodePtr node) } } -Ref CanvasParser::Parse(const std::string& path) +Ref CanvasParser::Parse(CanvasPtr canvas, const std::string& path) { customWidgetIDs.clear(); @@ -327,7 +328,6 @@ Ref CanvasParser::Parse(const std::string& path) return nullptr; } - CanvasPtr canvas = Canvas::New(); NodePtr root = Node::New("root"); auto firstNode = doc.FirstChildElement(); @@ -348,9 +348,8 @@ Ref CanvasParser::Parse(const std::string& path) } } - IterateOverElement(firstNode, root); - canvas->SetRoot(root); + IterateOverElement(firstNode, root); return canvas; } diff --git a/Nuake/src/UI/Parsers/CanvasParser.h b/Nuake/src/UI/Parsers/CanvasParser.h index 8e115477..a849536b 100644 --- a/Nuake/src/UI/Parsers/CanvasParser.h +++ b/Nuake/src/UI/Parsers/CanvasParser.h @@ -19,7 +19,7 @@ namespace NuakeUI private: std::map NodeTypes; std::string _parsingPath; - std::vector> customWidgetIDs; + std::vector, std::string>> customWidgetIDs; public: static CanvasParser& Get() @@ -33,6 +33,8 @@ namespace NuakeUI ~CanvasParser() = default; public: + UUID lastCanvasID = UUID(0); + /// /// Register a custom node type. /// @@ -42,16 +44,16 @@ namespace NuakeUI bool HasNodeType(const std::string& name) const; refNew GetNodeType(const std::string& name) const; - Ref Parse(const std::string& file); + Ref Parse(CanvasPtr canvas, const std::string& file); - std::vector> GetAllCustomWidgetInstance() { return customWidgetIDs; } + std::vector, std::string>> GetAllCustomWidgetInstance() { return customWidgetIDs; } private: void ScanFragment(tinyxml2::XMLElement* e, NodePtr node); bool ScanCustomWidgets(tinyxml2::XMLElement* e, NodePtr node); void WriteValueFromString(std::variant& var, const std::string& str); - void IterateOverElement(tinyxml2::XMLElement* e, NodePtr node); + void IterateOverElement(tinyxml2::XMLElement* e, NodePtr node, const std::string& customNodeName = ""); NodePtr CreateNodeFromXML(tinyxml2::XMLElement* xml, const std::string& id = "Node"); void AddClassesToNode(tinyxml2::XMLElement* e, NodePtr node); void AddModelIfToNode(tinyxml2::XMLElement* e, NodePtr node); diff --git a/NuakeNet/src/Components.cs b/NuakeNet/src/Components.cs index 147fea1a..b32df892 100644 --- a/NuakeNet/src/Components.cs +++ b/NuakeNet/src/Components.cs @@ -242,7 +242,7 @@ namespace Nuake.Net public bool Playing { get; set; } public int CurrentAnimation { get; set; } - public void Play(String name) + public void Play(string name) { unsafe { PlayIcall(EntityID, name); } } diff --git a/NuakeNet/src/UI/UIComponent.cs b/NuakeNet/src/UI/UIComponent.cs index fd048fc2..4b139f58 100644 --- a/NuakeNet/src/UI/UIComponent.cs +++ b/NuakeNet/src/UI/UIComponent.cs @@ -1,8 +1,14 @@ -using System; +using Coral.Managed; +using Coral.Managed.Interop; +using System; using System.Collections.Generic; using System.Drawing; +using System.IO; using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text; +using System.Threading; using System.Threading.Tasks; namespace Nuake.Net @@ -63,31 +69,95 @@ namespace Nuake.Net } } - public class UIWidget + public class Node + { + internal static unsafe delegate* FindChildByIDICall; + internal static unsafe delegate* HasNativeInstanceICall; + internal static unsafe delegate*> GetNativeInstanceNodeICall; + + public string UUID; + public string CanvasUUID; + + public string ID { get; set; } = ""; + public List Classes { get; set; } = new(); + + /// + /// Traverse the DOM starting from this node to find a child from a unique ID + /// + /// Type of node + /// Unique id of the node to find + /// + /// Node not found + public T FindChildByID(string id) where T : Node + { + unsafe + { + Engine.Log("Calling FindChildByIDICall with params: " + CanvasUUID + " , " + UUID + " , " + id); + + ulong uuid = FindChildByIDICall(CanvasUUID, CanvasUUID, UUID, id); + if (uuid == 0) + { + throw new Exception("Node not found"); + } + + Node? newNode = null; + //if (HasNativeInstanceICall(CanvasUUID, CanvasUUID, UUID)) + //{ + // NativeInstance handle; + // unsafe { handle = GetNativeInstanceNodeICall(CanvasUUID, UUID); } + // newNode = handle.Get(); + //} + + if(newNode == null) + { + newNode = new Node() + { + UUID = uuid.ToString(), + CanvasUUID = CanvasUUID + }; + + return newNode as T; + } + + return null; + } + } + } + + public class TextNode : Node + { + internal static unsafe delegate* SetTextNodeTextICall; + internal static unsafe delegate* GetTextNodeTextICall; + + public string Text + { + get + { + unsafe + { + return GetTextNodeTextICall(this.CanvasUUID, this.UUID).ToString(); + } + } + set + { + unsafe + { + SetTextNodeTextICall(this.CanvasUUID, this.UUID, value); + } + } + } + } + + public class UIWidget : Node { public Style Style { get; set; } - private string HTML; - - protected ulong ID { get; set; } - - public UIWidget() - { } - - protected UIWidget(ulong id) - { - ID = id; - Style = new Style(id); - HTML = ""; - } + public UIWidget() { } public virtual void OnInit() { } public virtual void OnTick(float dt) { } // Events - public virtual void OnClick() - { - - } + public virtual void OnClick() { } } }