Index: ps/trunk/binaries/data/mods/public/gui/pregame/MainMenuItemHandler.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/pregame/MainMenuItemHandler.js +++ ps/trunk/binaries/data/mods/public/gui/pregame/MainMenuItemHandler.js @@ -19,7 +19,6 @@ 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 @@ 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 @@ 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; Index: ps/trunk/binaries/data/mods/public/gui/pregame/SplashscreenHandler.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/pregame/SplashscreenHandler.js +++ ps/trunk/binaries/data/mods/public/gui/pregame/SplashscreenHandler.js @@ -23,8 +23,7 @@ if (this.showSplashScreen) this.openPage(); - // TODO: support actually deleting the handler - this.mainMenuPage.onTick = () => {}; + delete this.mainMenuPage.onTick; } openPage() Index: ps/trunk/binaries/data/mods/public/gui/session/Menu.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/Menu.js +++ ps/trunk/binaries/data/mods/public/gui/session/Menu.js @@ -101,8 +101,7 @@ if (maxOffset <= 0) { - // TODO: support actually deleting the handler - this.menuButtonPanel.onTick = () => {}; + delete this.menuButtonPanel.onTick; return; } Index: ps/trunk/source/gui/ObjectBases/IGUIObject.h =================================================================== --- ps/trunk/source/gui/ObjectBases/IGUIObject.h +++ ps/trunk/source/gui/ObjectBases/IGUIObject.h @@ -57,6 +57,7 @@ // 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 @@ */ 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). Index: ps/trunk/source/gui/ObjectBases/IGUIObject.cpp =================================================================== --- ps/trunk/source/gui/ObjectBases/IGUIObject.cpp +++ ps/trunk/source/gui/ObjectBases/IGUIObject.cpp @@ -334,6 +334,19 @@ 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"); Index: ps/trunk/source/gui/Scripting/JSInterface_IGUIObject.h =================================================================== --- ps/trunk/source/gui/Scripting/JSInterface_IGUIObject.h +++ ps/trunk/source/gui/Scripting/JSInterface_IGUIObject.h @@ -29,6 +29,7 @@ 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); Index: ps/trunk/source/gui/Scripting/JSInterface_IGUIObject.cpp =================================================================== --- ps/trunk/source/gui/Scripting/JSInterface_IGUIObject.cpp +++ ps/trunk/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 @@ 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