From 9f255eb96dd5885e6217742687a99e19bb56810b Mon Sep 17 00:00:00 2001 From: elexis Date: Mon, 28 Oct 2019 11:35:04 +0000 Subject: [PATCH] Support deleting GUI Object event handlers following rP666, refs #5387. Differential Revision: https://code.wildfiregames.com/D2395 Reported by: nani Tested on: gcc 9.2.0, Jenkins/vs2015 git-svn-id: https://svn.wildfiregames.com/public/ps/trunk@23103 3db68df2-c116-0410-a063-a993310a9797 --- .../mods/public/gui/pregame/MainMenuItemHandler.js | 12 ++++++-- .../mods/public/gui/pregame/SplashscreenHandler.js | 3 +- binaries/data/mods/public/gui/session/Menu.js | 3 +- source/gui/ObjectBases/IGUIObject.cpp | 13 +++++++++ source/gui/ObjectBases/IGUIObject.h | 9 ++++++ source/gui/Scripting/JSInterface_IGUIObject.cpp | 33 ++++++++++++++++++++-- source/gui/Scripting/JSInterface_IGUIObject.h | 1 + 7 files changed, 66 insertions(+), 8 deletions(-) diff --git a/binaries/data/mods/public/gui/pregame/MainMenuItemHandler.js b/binaries/data/mods/public/gui/pregame/MainMenuItemHandler.js index 6d97576b00..ae2e467a99 100644 --- a/binaries/data/mods/public/gui/pregame/MainMenuItemHandler.js +++ b/binaries/data/mods/public/gui/pregame/MainMenuItemHandler.js @@ -19,7 +19,6 @@ class MainMenuItemHandler this.setupMenuButtons(this.mainMenuButtons.children, this.menuItems); this.setupHotkeys(this.menuItems); - this.mainMenu.onTick = this.onTick.bind(this); Engine.GetGUIObjectByName("closeMenuButton").onPress = this.closeSubmenu.bind(this); } @@ -93,6 +92,10 @@ class MainMenuItemHandler size.top = this.submenu.size.bottom; this.MainMenuPanelRightBorderBottom.size = size; } + + // Start animation + this.lastTickTime = Date.now(); + this.mainMenu.onTick = this.onTick.bind(this); } closeSubmenu() @@ -110,14 +113,19 @@ class MainMenuItemHandler onTick() { let now = Date.now(); + if (now == this.lastTickTime) + return; let maxOffset = this.mainMenu.size.right - this.submenu.size.left; let offset = Math.min(this.MenuSpeed * (now - this.lastTickTime), maxOffset); this.lastTickTime = now; - if (this.submenu.hidden || offset <= 0) + if (this.submenu.hidden || !offset) + { + delete this.mainMenu.onTick; return; + } let size = this.submenu.size; size.left += offset; diff --git a/binaries/data/mods/public/gui/pregame/SplashscreenHandler.js b/binaries/data/mods/public/gui/pregame/SplashscreenHandler.js index bf9c94b6a8..753e5bc5f2 100644 --- a/binaries/data/mods/public/gui/pregame/SplashscreenHandler.js +++ b/binaries/data/mods/public/gui/pregame/SplashscreenHandler.js @@ -23,8 +23,7 @@ class SplashScreenHandler if (this.showSplashScreen) this.openPage(); - // TODO: support actually deleting the handler - this.mainMenuPage.onTick = () => {}; + delete this.mainMenuPage.onTick; } openPage() diff --git a/binaries/data/mods/public/gui/session/Menu.js b/binaries/data/mods/public/gui/session/Menu.js index f960589e67..2560aa1e58 100644 --- a/binaries/data/mods/public/gui/session/Menu.js +++ b/binaries/data/mods/public/gui/session/Menu.js @@ -101,8 +101,7 @@ class Menu if (maxOffset <= 0) { - // TODO: support actually deleting the handler - this.menuButtonPanel.onTick = () => {}; + delete this.menuButtonPanel.onTick; return; } diff --git a/source/gui/ObjectBases/IGUIObject.cpp b/source/gui/ObjectBases/IGUIObject.cpp index 59157936c7..52232ee88f 100644 --- a/source/gui/ObjectBases/IGUIObject.cpp +++ b/source/gui/ObjectBases/IGUIObject.cpp @@ -334,6 +334,19 @@ void IGUIObject::SetScriptHandler(const CStr& Action, JS::HandleObject Function) m_ScriptHandlers[Action] = JS::Heap(Function); } +void IGUIObject::UnsetScriptHandler(const CStr& Action) +{ + std::map >::iterator it = m_ScriptHandlers.find(Action); + + if (it == m_ScriptHandlers.end()) + return; + + m_ScriptHandlers.erase(it); + + if (m_ScriptHandlers.empty()) + JS_RemoveExtraGCRootsTracer(m_pGUI.GetScriptInterface()->GetJSRuntime(), Trace, this); +} + InReaction IGUIObject::SendEvent(EGUIMessageType type, const CStr& EventName) { PROFILE2_EVENT("gui event"); diff --git a/source/gui/ObjectBases/IGUIObject.h b/source/gui/ObjectBases/IGUIObject.h index 617877cd86..faad41cf73 100644 --- a/source/gui/ObjectBases/IGUIObject.h +++ b/source/gui/ObjectBases/IGUIObject.h @@ -57,6 +57,7 @@ class IGUIObject // Allow getProperty to access things like GetParent() friend bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp); friend bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult& result); + friend bool JSI_IGUIObject::deleteProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::ObjectOpResult& result); friend bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, JS::Value* vp); public: @@ -385,9 +386,17 @@ protected: */ void ScriptEvent(const CStr& Action, const JS::HandleValueArray& paramData); + /** + * Assigns a JS function to the event name. + */ void SetScriptHandler(const CStr& Action, JS::HandleObject Function); /** + * Deletes an event handler assigned to the given name, if such a handler exists. + */ + void UnsetScriptHandler(const CStr& Action); + + /** * Inputes the object that is currently hovered, this function * updates this object accordingly (i.e. if it's the object * being inputted one thing happens, and not, another). diff --git a/source/gui/Scripting/JSInterface_IGUIObject.cpp b/source/gui/Scripting/JSInterface_IGUIObject.cpp index 79a17a0928..7876dcb038 100644 --- a/source/gui/Scripting/JSInterface_IGUIObject.cpp +++ b/source/gui/Scripting/JSInterface_IGUIObject.cpp @@ -27,8 +27,10 @@ JSClass JSI_IGUIObject::JSI_class = { "GUIObject", JSCLASS_HAS_PRIVATE, - nullptr, nullptr, - JSI_IGUIObject::getProperty, JSI_IGUIObject::setProperty, + nullptr, + JSI_IGUIObject::deleteProperty, + JSI_IGUIObject::getProperty, + JSI_IGUIObject::setProperty, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; @@ -174,6 +176,33 @@ bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::Handle return result.fail(JSMSG_UNDEFINED_PROP); } +bool JSI_IGUIObject::deleteProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::ObjectOpResult& result) +{ + IGUIObject* e = ScriptInterface::GetPrivate(cx, obj, &JSI_IGUIObject::JSI_class); + if (!e) + return result.fail(JSMSG_NOT_NONNULL_OBJECT); + + JSAutoRequest rq(cx); + JS::RootedValue idval(cx); + if (!JS_IdToValue(cx, id, &idval)) + return result.fail(JSMSG_NOT_NONNULL_OBJECT); + + std::string propName; + if (!ScriptInterface::FromJSVal(cx, idval, propName)) + return result.fail(JSMSG_UNDEFINED_PROP); + + // event handlers + if (propName.substr(0, 2) == "on") + { + CStr eventName(CStr(propName.substr(2)).LowerCase()); + e->UnsetScriptHandler(eventName); + return result.succeed(); + } + + JS_ReportError(cx, "Only event handlers can be deleted from GUI objects!"); + return result.fail(JSMSG_UNDEFINED_PROP); +} + bool JSI_IGUIObject::toString(JSContext* cx, uint argc, JS::Value* vp) { // No JSAutoRequest needed for these calls diff --git a/source/gui/Scripting/JSInterface_IGUIObject.h b/source/gui/Scripting/JSInterface_IGUIObject.h index 9f812be1e0..a90f827701 100644 --- a/source/gui/Scripting/JSInterface_IGUIObject.h +++ b/source/gui/Scripting/JSInterface_IGUIObject.h @@ -29,6 +29,7 @@ namespace JSI_IGUIObject bool getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp); bool setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult& result); + bool deleteProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::ObjectOpResult& result); bool toString(JSContext* cx, uint argc, JS::Value* vp); bool focus(JSContext* cx, uint argc, JS::Value* vp); bool blur(JSContext* cx, uint argc, JS::Value* vp); -- 2.11.4.GIT