diff --git a/Assets/Scripts/UI/SC_ChangeSceneButton.cs b/Assets/Scripts/UI/SC_ChangeSceneButton.cs index 6caba2b1..b41a421a 100644 --- a/Assets/Scripts/UI/SC_ChangeSceneButton.cs +++ b/Assets/Scripts/UI/SC_ChangeSceneButton.cs @@ -11,8 +11,9 @@ public class ChangeSceneButton : Script UIElement ui = GetComponent(); if (ui != null) { - ui.OnClick.RegisterAction(() => + ui.OnRelease.RegisterAction(() => { + if (sceneID != 0) { Audio.PlaySFXOnce2D("event:/UI/success"); diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index a89fb050..3ebcc904 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -132,16 +132,19 @@ namespace Sandbox SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); - SHSystemManager::RegisterRoutine(); - SHSystemManager::RegisterRoutine(); - SHSystemManager::RegisterRoutine(); - SHSystemManager::RegisterRoutine(); //SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); + + SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); + + SHSystemManager::RegisterRoutine(); #ifdef SHEDITOR diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index 22c7c12e..bd2cfea5 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -369,6 +369,27 @@ namespace SHADE return eventData->handle; } + SHEventHandle SHScriptEngine::onUIElementReleased(SHEventPtr eventPtr) + { + auto eventData = reinterpret_cast*>(eventPtr.get()); + csUIElementOnReleased(eventData->data->EID); + return eventData->handle; + } + + SHEventHandle SHScriptEngine::onUIElementOnHoverEntered(SHEventPtr eventPtr) + { + auto eventData = reinterpret_cast*>(eventPtr.get()); + csUIElementOnHoverEntered(eventData->data->EID); + return eventData->handle; + } + + SHEventHandle SHScriptEngine::onUIElementOnHoverExited(SHEventPtr eventPtr) + { + auto eventData = reinterpret_cast*>(eventPtr.get()); + csUIElementOnHoverExited(eventData->data->EID); + return eventData->handle; + } + SHEventHandle SHScriptEngine::onSceneNodeChildrenAdded(SHEventPtr eventPtr) { auto eventData = reinterpret_cast*>(eventPtr.get()); @@ -539,6 +560,24 @@ namespace SHADE DEFAULT_CSHARP_NAMESPACE + ".UIElement", "OnClicked" ); + csUIElementOnReleased = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".UIElement", + "OnReleased" + ); + csUIElementOnHoverEntered = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".UIElement", + "OnHoverEntered" + ); + csUIElementOnHoverExited = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".UIElement", + "OnHoverExited" + ); csEditorRenderScripts = dotNet.GetFunctionPtr ( DEFAULT_CSHARP_LIB_NAME, @@ -608,6 +647,21 @@ namespace SHADE std::make_shared>(this, &SHScriptEngine::onUIElementClicked) }; SHEventManager::SubscribeTo(SH_BUTTON_CLICK_EVENT, std::dynamic_pointer_cast(clickedUIElementEventReceiver)); + std::shared_ptr> releasedUIElementEventReceiver + { + std::make_shared>(this, &SHScriptEngine::onUIElementReleased) + }; + SHEventManager::SubscribeTo(SH_BUTTON_RELEASE_EVENT, std::dynamic_pointer_cast(releasedUIElementEventReceiver)); + std::shared_ptr> hoverEnterUIElementEventReceiver + { + std::make_shared>(this, &SHScriptEngine::onUIElementOnHoverEntered) + }; + SHEventManager::SubscribeTo(SH_BUTTON_HOVER_ENTER_EVENT, std::dynamic_pointer_cast(hoverEnterUIElementEventReceiver)); + std::shared_ptr> hoverExitedUIElementEventReceiver + { + std::make_shared>(this, &SHScriptEngine::onUIElementOnHoverExited) + }; + SHEventManager::SubscribeTo(SH_BUTTON_HOVER_EXIT_EVENT, std::dynamic_pointer_cast(hoverExitedUIElementEventReceiver)); /* SceneGraph */ // Register for SceneNode child added event diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.h b/SHADE_Engine/src/Scripting/SHScriptEngine.h index 9b234d04..b207ae64 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.h +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.h @@ -292,6 +292,9 @@ namespace SHADE CsEventRelayFuncPtr csSceneNodeChildrenChanged = nullptr; CsEventRelayFuncPtr csUIElementOnRemoved = nullptr; CsEventRelayFuncPtr csUIElementOnClicked = nullptr; + CsEventRelayFuncPtr csUIElementOnReleased = nullptr; + CsEventRelayFuncPtr csUIElementOnHoverEntered = nullptr; + CsEventRelayFuncPtr csUIElementOnHoverExited = nullptr; // - Editor CsScriptEditorFuncPtr csEditorRenderScripts = nullptr; CsFuncPtr csEditorUndo = nullptr; @@ -306,6 +309,9 @@ namespace SHADE SHEventHandle onColliderComponentRemoved(SHEventPtr eventPtr); SHEventHandle onUIElementRemoved(SHEventPtr eventPtr); SHEventHandle onUIElementClicked(SHEventPtr eventPtr); + SHEventHandle onUIElementReleased(SHEventPtr eventPtr); + SHEventHandle onUIElementOnHoverEntered(SHEventPtr eventPtr); + SHEventHandle onUIElementOnHoverExited(SHEventPtr eventPtr); SHEventHandle onSceneNodeChildrenAdded(SHEventPtr eventPtr); SHEventHandle onSceneNodeChildrenRemoved(SHEventPtr eventPtr); SHEventHandle onSceneDestroyed(SHEventPtr eventPtr); diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index 3552e47b..b42e71a6 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -204,6 +204,7 @@ namespace SHADE SHButtonClickEvent clickEvent; clickEvent.EID = comp.GetEID(); SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_HOVER_ENTER_EVENT); + //SHLOG_INFO("C++ BROADCASTED HOVER ENTER EVENT EID: {}", clickEvent.EID); } comp.isHovered = true; @@ -313,6 +314,7 @@ namespace SHADE auto material = renderable->GetModifiableMaterial(); comp.currentTexture = textureID; material->SetProperty("data.textureIndex", SHResourceManager::LoadOrGet(textureID)); + loadTexture = true; } @@ -367,6 +369,7 @@ namespace SHADE auto material = renderable->GetModifiableMaterial(); comp.currentTexture = textureID; material->SetProperty("data.textureIndex", SHResourceManager::LoadOrGet(textureID)); + loadTexture = true; } @@ -390,6 +393,11 @@ namespace SHADE if (SHSceneManager::CheckNodeAndComponentsActive(comp.GetEID())) system->UpdateToggleButtonComponent(comp); } + if (system->loadTexture == true) + { + system->loadTexture = false; + SHResourceManager::FinaliseChanges(); + } } SHVec2 SHUISystem::CanvasToScreenPoint(SHVec2& const canvasPoint, bool normalized) noexcept diff --git a/SHADE_Engine/src/UI/SHUISystem.h b/SHADE_Engine/src/UI/SHUISystem.h index 3b2bb2cf..f3f7847e 100644 --- a/SHADE_Engine/src/UI/SHUISystem.h +++ b/SHADE_Engine/src/UI/SHUISystem.h @@ -68,6 +68,8 @@ namespace SHADE private: + bool loadTexture{false}; + void UpdateUIComponent(SHUIComponent& comp) noexcept; void UpdateButtonComponent(SHButtonComponent& comp) noexcept; void UpdateToggleButtonComponent(SHToggleButtonComponent& comp) noexcept; diff --git a/SHADE_Managed/src/Components/UIElement.cxx b/SHADE_Managed/src/Components/UIElement.cxx index d76d6d42..8e6134e1 100644 --- a/SHADE_Managed/src/Components/UIElement.cxx +++ b/SHADE_Managed/src/Components/UIElement.cxx @@ -28,6 +28,18 @@ namespace SHADE : Component(entity) {} + void UIElement::ClearStaticEventData() + { + if (onClickEventMap != nullptr) + onClickEventMap->Clear(); + if (onReleasedEventMap != nullptr) + onReleasedEventMap->Clear(); + if (onHoverEnterEventMap != nullptr) + onHoverEnterEventMap->Clear(); + if (onHoverExitEventMap != nullptr) + onHoverExitEventMap->Clear(); + } + /*---------------------------------------------------------------------------------*/ /* Properties */ /*---------------------------------------------------------------------------------*/ @@ -37,7 +49,7 @@ namespace SHADE if (onClickEventMap == nullptr) { onClickEventMap = gcnew System::Collections::Generic::Dictionary(); - } + } // Create event if it wasn't before if (!onClickEventMap->ContainsKey(owner.EntityId)) @@ -48,6 +60,57 @@ namespace SHADE // Return the event return onClickEventMap[owner.EntityId]; } + CallbackEvent^ UIElement::OnRelease::get() + { + // Create map if it wasn't before + if (onReleasedEventMap == nullptr) + { + onReleasedEventMap = gcnew System::Collections::Generic::Dictionary(); + } + + // Create event if it wasn't before + if (!onReleasedEventMap->ContainsKey(owner.EntityId)) + { + onReleasedEventMap->Add(owner.EntityId, gcnew CallbackEvent()); + } + + // Return the event + return onReleasedEventMap[owner.EntityId]; + } + CallbackEvent^ UIElement::OnHoverEnter::get() + { + // Create map if it wasn't before + if (onHoverEnterEventMap == nullptr) + { + onHoverEnterEventMap = gcnew System::Collections::Generic::Dictionary(); + } + + // Create event if it wasn't before + if (!onHoverEnterEventMap->ContainsKey(owner.EntityId)) + { + onHoverEnterEventMap->Add(owner.EntityId, gcnew CallbackEvent()); + } + + // Return the event + return onHoverEnterEventMap[owner.EntityId]; + } + CallbackEvent^ UIElement::OnHoverExit::get() + { + // Create map if it wasn't before + if (onHoverExitEventMap == nullptr) + { + onHoverExitEventMap = gcnew System::Collections::Generic::Dictionary(); + } + + // Create event if it wasn't before + if (!onHoverExitEventMap->ContainsKey(owner.EntityId)) + { + onHoverExitEventMap->Add(owner.EntityId, gcnew CallbackEvent()); + } + + // Return the event + return onHoverExitEventMap[owner.EntityId]; + } /*---------------------------------------------------------------------------------*/ /* Event Handling Functions */ @@ -60,6 +123,18 @@ namespace SHADE { onClickEventMap->Remove(entity); } + if (onReleasedEventMap != nullptr && onReleasedEventMap->ContainsKey(entity)) + { + onReleasedEventMap->Remove(entity); + } + if (onHoverEnterEventMap != nullptr && onHoverEnterEventMap->ContainsKey(entity)) + { + onHoverEnterEventMap->Remove(entity); + } + if (onHoverExitEventMap != nullptr && onHoverExitEventMap->ContainsKey(entity)) + { + onHoverExitEventMap->Remove(entity); + } SAFE_NATIVE_CALL_END("UIElement.OnComponentRemoved") } void UIElement::OnClicked(EntityID entity) @@ -72,4 +147,34 @@ namespace SHADE } SAFE_NATIVE_CALL_END("UIElement.OnClicked") } + void UIElement::OnReleased(EntityID entity) + { + SAFE_NATIVE_CALL_BEGIN + // Remove the event if it contained an event + if (onReleasedEventMap != nullptr && onReleasedEventMap->ContainsKey(entity)) + { + onReleasedEventMap[entity]->Invoke(); + } + SAFE_NATIVE_CALL_END("UIElement.OnReleased") + } + void UIElement::OnHoverEntered(EntityID entity) + { + SAFE_NATIVE_CALL_BEGIN + // Remove the event if it contained an event + if (onHoverEnterEventMap != nullptr && onHoverEnterEventMap->ContainsKey(entity)) + { + onHoverEnterEventMap[entity]->Invoke(); + } + SAFE_NATIVE_CALL_END("UIElement.OnHoverEntered") + } + void UIElement::OnHoverExited(EntityID entity) + { + SAFE_NATIVE_CALL_BEGIN + // Remove the event if it contained an event + if (onHoverExitEventMap != nullptr && onHoverExitEventMap->ContainsKey(entity)) + { + onHoverExitEventMap[entity]->Invoke(); + } + SAFE_NATIVE_CALL_END("UIElement.OnHoverExited") + } } diff --git a/SHADE_Managed/src/Components/UIElement.hxx b/SHADE_Managed/src/Components/UIElement.hxx index a969e4b5..c93e1e55 100644 --- a/SHADE_Managed/src/Components/UIElement.hxx +++ b/SHADE_Managed/src/Components/UIElement.hxx @@ -50,6 +50,37 @@ namespace SHADE { CallbackEvent^ get(); } + /// + /// Event that is raised when this UIElement is released. + /// + property CallbackEvent^ OnRelease + { + CallbackEvent^ get(); + } + /// + /// Event that is raised on the first frame when this UIElement is hovered over. + /// + property CallbackEvent^ OnHoverEnter + { + CallbackEvent^ get(); + } + /// + /// Event that is raised on the first frame when this UIElement is no longer + /// hovered over. + /// + property CallbackEvent^ OnHoverExit + { + CallbackEvent^ get(); + } + + internal: + /*-----------------------------------------------------------------------------*/ + /* Static Clear Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Disposes static event data which may contains data from SHADE_Scripting. + /// + static void ClearStaticEventData(); private: /*-----------------------------------------------------------------------------*/ @@ -65,11 +96,32 @@ namespace SHADE /// /// The entity which was clicked. static void OnClicked(EntityID entity); + /// + /// To be called from native code when this component is released from clicking. + /// + /// The entity which was clicked. + static void OnReleased(EntityID entity); + /// + /// To be called from native code on the first frame that this component is + /// hovered on. + /// + /// The entity which was clicked. + static void OnHoverEntered(EntityID entity); + /// + /// To be called from native code on the first frame that this component is + /// no longer hovered on. + /// + /// The entity which was clicked. + static void OnHoverExited(EntityID entity); /*-----------------------------------------------------------------------------*/ /* Static Data Members */ /*-----------------------------------------------------------------------------*/ + // As these hold references to code in SHADE_Scripting, we must remember to dispose of them when changing scenes static System::Collections::Generic::Dictionary^ onClickEventMap; + static System::Collections::Generic::Dictionary^ onReleasedEventMap; + static System::Collections::Generic::Dictionary^ onHoverEnterEventMap; + static System::Collections::Generic::Dictionary^ onHoverExitEventMap; }; } diff --git a/SHADE_Managed/src/Engine/ECS.hxx b/SHADE_Managed/src/Engine/ECS.hxx index 18acf30d..64207f72 100644 --- a/SHADE_Managed/src/Engine/ECS.hxx +++ b/SHADE_Managed/src/Engine/ECS.hxx @@ -51,7 +51,7 @@ namespace SHADE /// specified Component. /// generic where T : BaseComponent - static T GetComponent(EntityID entity); + static T GetComponent(EntityID entity); /// /// Retrieves the first Component from the specified GameObject's children that /// matches the specified type. diff --git a/SHADE_Managed/src/Engine/EngineInterface.cxx b/SHADE_Managed/src/Engine/EngineInterface.cxx index 2009b2e5..50f8fbc2 100644 --- a/SHADE_Managed/src/Engine/EngineInterface.cxx +++ b/SHADE_Managed/src/Engine/EngineInterface.cxx @@ -21,6 +21,7 @@ of DigiPen Institute of Technology is prohibited. #include "Utility/Convert.hxx" #include "Utility/Debug.hxx" #include "Scripts/ScriptStore.hxx" +#include "Components/UIElement.hxx" namespace SHADE { @@ -43,6 +44,9 @@ namespace SHADE oss << "[EngineInterface] Unloading " << Convert::ToNative(ManagedLibraryName) << ".dll"; ScriptStore::Exit(); + // Unload static data of components that have access to the assembly + UIElement::ClearStaticEventData(); + // Unload the script scriptContext->Unload(); scriptContext = nullptr;