diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index bde65aff..6f617e76 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -264,6 +264,11 @@ class cocos2d::CCEaseOut { static cocos2d::CCEaseOut* create(cocos2d::CCActionInterval*, float) = mac 0x2a1b70; } +[[link(win)]] +class cocos2d::CCEaseBounceOut { + static cocos2d::CCEaseBounceOut* create(cocos2d::CCActionInterval*) = mac 0x2a3b40; +} + [[link(win)]] class cocos2d::CCEGLView { CCEGLView(); diff --git a/loader/include/Geode/ui/MenuItemSprite.hpp b/loader/include/Geode/ui/MenuItemSprite.hpp new file mode 100644 index 00000000..113eb80d --- /dev/null +++ b/loader/include/Geode/ui/MenuItemSprite.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include "../utils/MiniFunction.hpp" + +#pragma warning(disable : 4275) + +namespace geode { + class GEODE_DLL MenuItemSprite : public cocos2d::CCMenuItemSprite { + protected: + + MenuItemSprite(); + ~MenuItemSprite() override; + + public: + static MenuItemSprite* create( + cocos2d::CCNode* normalSprite, cocos2d::CCNode* disabledSprite, + cocos2d::CCObject* target, cocos2d::SEL_MenuHandler callback + ); + + static MenuItemSprite* create( + cocos2d::CCNode* normalSprite, + cocos2d::CCObject* target, cocos2d::SEL_MenuHandler callback + ); + + bool init( + cocos2d::CCNode* normalSprite, cocos2d::CCNode* disabledSprite, + cocos2d::CCObject* target, cocos2d::SEL_MenuHandler callback + ); + + void runActionOnSprite(cocos2d::CCNode* sprite, cocos2d::CCAction* generator); + void runActionOnSprites(utils::MiniFunction generator); + + utils::MiniFunction m_selectedAction; + utils::MiniFunction m_unselectedAction; + utils::MiniFunction m_activateAction; + + void activate() override; + void selected() override; + void unselected() override; + + void setImage(cocos2d::CCNode* image); + void setNormalImage(cocos2d::CCNode* image) override; + void setDisabledImage(cocos2d::CCNode* image) override; + void setSelectedImage(cocos2d::CCNode* image) override; + }; +} diff --git a/loader/include/Geode/ui/MenuItemToggle.hpp b/loader/include/Geode/ui/MenuItemToggle.hpp new file mode 100644 index 00000000..6399773a --- /dev/null +++ b/loader/include/Geode/ui/MenuItemToggle.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include "MenuItemSprite.hpp" + +#pragma warning(disable : 4275) + +namespace geode { + class GEODE_DLL MenuItemToggle : public cocos2d::CCMenuItem { + protected: + MenuItemSprite* m_offButton; + MenuItemSprite* m_onButton; + bool m_toggled; + + MenuItemToggle(); + ~MenuItemToggle() override; + + public: + static MenuItemToggle* create( + cocos2d::CCNode* onSprite, cocos2d::CCNode* offSprite, + cocos2d::CCObject* target, cocos2d::SEL_MenuHandler callback + ); + + bool init( + cocos2d::CCNode* onSprite, cocos2d::CCNode* offSprite, + cocos2d::CCObject* target, cocos2d::SEL_MenuHandler callback + ); + + void setOffButton(MenuItemSprite* button); + void setOnButton(MenuItemSprite* button); + MenuItemSprite* getOffButton() const; + MenuItemSprite* getOnButton() const; + + bool isToggled() const; + void toggle(bool enabled); + + void setScale(float scale) override; + void activate() override; + void selected() override; + void unselected() override; + void setEnabled(bool enabled) override; + }; +} diff --git a/loader/include/Geode/utils/MiniFunction.hpp b/loader/include/Geode/utils/MiniFunction.hpp index edb66052..72cf1e19 100644 --- a/loader/include/Geode/utils/MiniFunction.hpp +++ b/loader/include/Geode/utils/MiniFunction.hpp @@ -123,6 +123,30 @@ namespace geode::utils { return *this; } + template + requires(MiniFunctionCallable && !std::is_same_v, MiniFunction>) + MiniFunction& operator=(Callable&& func) { + delete m_state; + m_state = new MiniFunctionState, Ret, Args...>(std::forward(func)); + return *this; + } + + template + requires(!MiniFunctionCallable && std::is_pointer_v && std::is_function_v>) + MiniFunction& operator=(FunctionPointer func) { + delete m_state; + m_state = new MiniFunctionStatePointer(func); + return *this; + } + + template + requires(std::is_member_function_pointer_v) + MiniFunction& operator=(MemberFunctionPointer func) { + delete m_state; + m_state = new MiniFunctionStateMemberPointer(func); + return *this; + } + Ret operator()(Args... args) const { if (!m_state) return Ret(); return m_state->call(args...); diff --git a/loader/src/ui/internal/list/ModListLayer.cpp b/loader/src/ui/internal/list/ModListLayer.cpp index a06e745c..e950a521 100644 --- a/loader/src/ui/internal/list/ModListLayer.cpp +++ b/loader/src/ui/internal/list/ModListLayer.cpp @@ -16,6 +16,8 @@ #include #include +#include + #define FTS_FUZZY_MATCH_IMPLEMENTATION #include @@ -259,7 +261,7 @@ bool ModListLayer::init() { m_topMenu = CCMenu::create(); // add back button - auto backBtn = CCMenuItemSpriteExtra::create( + auto backBtn = MenuItemSprite::create( CCSprite::createWithSpriteFrameName("GJ_arrow_01_001.png"), this, menu_selector(ModListLayer::onExit) ); diff --git a/loader/src/ui/nodes/MenuItemSprite.cpp b/loader/src/ui/nodes/MenuItemSprite.cpp new file mode 100644 index 00000000..cb6ec2a2 --- /dev/null +++ b/loader/src/ui/nodes/MenuItemSprite.cpp @@ -0,0 +1,98 @@ +#include + +using namespace geode::prelude; + +MenuItemSprite* MenuItemSprite::create( + cocos2d::CCNode* normalSprite, + cocos2d::CCObject* target, cocos2d::SEL_MenuHandler callback +) { + return MenuItemSprite::create(normalSprite, nullptr, target, callback); +} + +MenuItemSprite* MenuItemSprite::create( + cocos2d::CCNode* normalSprite, cocos2d::CCNode* disabledSprite, + cocos2d::CCObject* target, cocos2d::SEL_MenuHandler callback +) { + auto ret = new MenuItemSprite(); + if (ret && ret->init(normalSprite, disabledSprite, target, callback)) { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; +} + +MenuItemSprite::MenuItemSprite() {} + +MenuItemSprite::~MenuItemSprite() { +} + +void MenuItemSprite::setImage(cocos2d::CCNode* image) { + if (image) { + image->setAnchorPoint({ 0.5f, 0.5f }); + image->setPosition(image->getContentSize() / 2); + } +} + +// why are the members private like what +void MenuItemSprite::setNormalImage(cocos2d::CCNode* image) { + CCMenuItemSprite::setNormalImage(image); + this->setImage(image); +} +void MenuItemSprite::setDisabledImage(cocos2d::CCNode* image) { + CCMenuItemSprite::setDisabledImage(image); + this->setImage(image); +} +void MenuItemSprite::setSelectedImage(cocos2d::CCNode* image) { + CCMenuItemSprite::setSelectedImage(image); + this->setImage(image); +} + +bool MenuItemSprite::init( + cocos2d::CCNode* normalSprite, cocos2d::CCNode* disabledSprite, + cocos2d::CCObject* target, cocos2d::SEL_MenuHandler callback +) { + if (!CCMenuItemSprite::initWithNormalSprite(normalSprite, disabledSprite, nullptr, target, callback)) return false; + + m_selectedAction = []() -> cocos2d::CCAction* { + return cocos2d::CCEaseBounceOut::create(cocos2d::CCScaleTo::create(0.3f, 1.26f)); + }; + m_unselectedAction = []() -> cocos2d::CCAction* { + return cocos2d::CCEaseBounceOut::create(cocos2d::CCScaleTo::create(0.4f, 1.0f)); + }; + m_activateAction = []() -> cocos2d::CCAction* { + return cocos2d::CCScaleTo::create(0.f, 1.0f); + }; + + return true; +} + +void MenuItemSprite::runActionOnSprite(cocos2d::CCNode* sprite, cocos2d::CCAction* generator) { + if (sprite) { + sprite->stopAllActions(); + if (generator) sprite->runAction(generator); + } +} + +void MenuItemSprite::runActionOnSprites(MiniFunction generator) { + this->runActionOnSprite(this->getNormalImage(), generator()); + this->runActionOnSprite(this->getDisabledImage(), generator()); + this->runActionOnSprite(this->getSelectedImage(), generator()); +} + +void MenuItemSprite::activate() { + this->runActionOnSprites(m_activateAction); + CCMenuItem::activate(); +} +void MenuItemSprite::selected() { + if (!m_bEnabled) return; + CCMenuItem::selected(); + + this->runActionOnSprites(m_selectedAction); +} +void MenuItemSprite::unselected() { + if (!m_bEnabled) return; + CCMenuItem::unselected(); + + this->runActionOnSprites(m_unselectedAction); +} \ No newline at end of file