diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index 013cecfc..f25f18f4 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -14,6 +14,7 @@ file(GLOB CORE_SOURCES src/cocos2d-ext/*.cpp src/core/*.cpp src/hooks/*.cpp + src/ids/*.cpp src/internal/*.cpp src/internal/windows/*.cpp src/internal/mac/*.cpp diff --git a/loader/include/Geode/UI.hpp b/loader/include/Geode/UI.hpp index 8f8bb18d..8b6e4b60 100644 --- a/loader/include/Geode/UI.hpp +++ b/loader/include/Geode/UI.hpp @@ -2,13 +2,17 @@ #include "ui/BasedButtonSprite.hpp" #include "ui/BasedButton.hpp" +#include "ui/ColorPickPopup.hpp" +#include "ui/EnterLayerEvent.hpp" #include "ui/IconButtonSprite.hpp" #include "ui/InputNode.hpp" #include "ui/ListView.hpp" +#include "ui/MDPopup.hpp" #include "ui/MDTextArea.hpp" #include "ui/Notification.hpp" #include "ui/Popup.hpp" #include "ui/SceneManager.hpp" #include "ui/Scrollbar.hpp" #include "ui/ScrollLayer.hpp" +#include "ui/SelectList.hpp" #include "ui/TextRenderer.hpp" diff --git a/loader/include/Geode/cocos/cocos2dx/base_nodes/CCNode.h b/loader/include/Geode/cocos/cocos2dx/base_nodes/CCNode.h index 10055ebf..80679282 100644 --- a/loader/include/Geode/cocos/cocos2dx/base_nodes/CCNode.h +++ b/loader/include/Geode/cocos/cocos2dx/base_nodes/CCNode.h @@ -37,6 +37,7 @@ #include "kazmath/kazmath.h" #include "script_support/CCScriptSupport.h" #include "CCProtocols.h" +#include "Layout.hpp" NS_CC_BEGIN @@ -875,6 +876,13 @@ public: * @returns The child, or nullptr if none was found */ CCNode* getChildByIDRecursive(std::string const& id); + + void setLayout(Layout* layout, bool apply = true); + Layout* getLayout(); + void updateLayout(); + + void setPositionHint(PositionHint hint); + PositionHint getPositionHint(); ); /// @{ diff --git a/loader/include/Geode/cocos/cocos2dx/base_nodes/Layout.hpp b/loader/include/Geode/cocos/cocos2dx/base_nodes/Layout.hpp new file mode 100644 index 00000000..5697cbb0 --- /dev/null +++ b/loader/include/Geode/cocos/cocos2dx/base_nodes/Layout.hpp @@ -0,0 +1,153 @@ +#pragma once + +#include "ccMacros.h" +#include "cocoa/CCAffineTransform.h" +#include "cocoa/CCArray.h" +#include <Geode/platform/platform.hpp> +#include <optional> +#include <unordered_map> + +NS_CC_BEGIN + +class CCNode; + +/** + * Layouts automatically handle the positioning of nodes. Use CCNode::setLayout + * to apply a layout to a node, and then use CCNode::updateLayout to apply + * the layout's positioning. Geode comes with a few default layouts like + * RowLayout, ColumnLayout, and GridLayout, but if you need a different kind + * of layout you can inherit from the Layout class. + */ +class Layout { +public: + /** + * Automatically apply the layout's positioning on a set of nodes + * @param nodes Nodes to position + * @param availableSize Give hints to the layout about how much space is + * available. Note that the layout may still overflow + */ + virtual void apply(CCArray* nodes, CCSize const& availableSize) = 0; +}; + +/** + * Determines how a node should be positioned within its parent, if that + * parent has an automatically positioning layout + */ +enum class PositionHint { + // The container can determine the best position + // for this node + Default, + // The container's layout should not affect the + // position of this node + Absolute, +}; + +/** + * Specifies the alignment of something + */ +enum class Alignment { + Begin, + Center, + End, +}; + +/** + * Simple layout for arranging nodes in a row (horizontal line) + */ +class GEODE_DLL RowLayout : public Layout { +protected: + Alignment m_alignment = Alignment::Center; + std::optional<float> m_alignVertically; + float m_gap; + +public: + void apply(CCArray* nodes, CCSize const& availableSize) override; + + /** + * Create a new RowLayout. Note that this class is not automatically + * managed by default, so you must assign it to a CCNode or manually + * manage the memory yourself. + * @param gap Space between nodes + * @param alignVertically Whether to align the nodes vertically, and if so, + * what Y position to align them at + * @returns Created RowLayout + */ + static RowLayout* create( + float gap = 5.f, + std::optional<float> alignVertically = std::nullopt + ); + + RowLayout* setAlignment(Alignment align); + RowLayout* setGap(float gap); + RowLayout* setAlignVertically(std::optional<float> align); +}; + +/** + * Simple layout for arranging nodes in a column (vertical line) + */ +class GEODE_DLL ColumnLayout : public Layout { +protected: + Alignment m_alignment = Alignment::Center; + std::optional<float> m_alignHorizontally; + float m_gap; + +public: + void apply(CCArray* nodes, CCSize const& availableSize) override; + + static ColumnLayout* create( + float gap = 5.f, + std::optional<float> alignHorizontally = std::nullopt + ); + + ColumnLayout* setAlignment(Alignment align); + ColumnLayout* setGap(float gap); + ColumnLayout* setAlignHorizontally(std::optional<float> align); +}; + +/** + * Grid direction; which direction the grid should add its next row to if the + * current row is full + */ +enum class GridDirection { + // Downward + Column, + // Upward + ReverseColumn, + // Right + Row, + // Left + ReverseRow, +}; + +/** + * Grid alignment; same as normal Alignment but also features the "Stretch" + * option which will stretch the row out to be the same size as the others +*/ +enum class GridAlignment { + Begin, + Center, + Stretch, + End, +}; + +class GEODE_DLL GridLayout : public Layout { +protected: + GridDirection m_direction = GridDirection::Column; + GridAlignment m_alignment = GridAlignment::Center; + std::optional<size_t> m_rowSize; + +public: + void apply(CCArray* nodes, CCSize const& availableSize) override; + + static GridLayout* create( + std::optional<size_t> rowSize, + GridAlignment alignment = GridAlignment::Center, + GridDirection direction = GridDirection::Column + ); + + GridLayout* setDirection(GridDirection direction); + GridLayout* setAlignment(GridAlignment alignment); + GridLayout* setRowSize(std::optional<size_t> rowSize); +}; + +NS_CC_END diff --git a/loader/include/Geode/cocos/cocos2dx/cocoa/CCObject.h b/loader/include/Geode/cocos/cocos2dx/cocoa/CCObject.h index a73dfa2d..f7408b3a 100644 --- a/loader/include/Geode/cocos/cocos2dx/cocoa/CCObject.h +++ b/loader/include/Geode/cocos/cocos2dx/cocoa/CCObject.h @@ -173,14 +173,14 @@ typedef void (CCObject::*SEL_MenuHandler)(CCObject*); typedef void (CCObject::*SEL_EventHandler)(CCEvent*); typedef int (CCObject::*SEL_Compare)(CCObject*); -#define schedule_selector(_SELECTOR) (SEL_SCHEDULE)(&_SELECTOR) -#define callfunc_selector(_SELECTOR) (SEL_CallFunc)(&_SELECTOR) -#define callfuncN_selector(_SELECTOR) (SEL_CallFuncN)(&_SELECTOR) -#define callfuncND_selector(_SELECTOR) (SEL_CallFuncND)(&_SELECTOR) -#define callfuncO_selector(_SELECTOR) (SEL_CallFuncO)(&_SELECTOR) -#define menu_selector(_SELECTOR) (SEL_MenuHandler)(&_SELECTOR) -#define event_selector(_SELECTOR) (SEL_EventHandler)(&_SELECTOR) -#define compare_selector(_SELECTOR) (SEL_Compare)(&_SELECTOR) +#define schedule_selector(_SELECTOR) (cocos2d::SEL_SCHEDULE)(&_SELECTOR) +#define callfunc_selector(_SELECTOR) (cocos2d::SEL_CallFunc)(&_SELECTOR) +#define callfuncN_selector(_SELECTOR) (cocos2d::SEL_CallFuncN)(&_SELECTOR) +#define callfuncND_selector(_SELECTOR) (cocos2d::SEL_CallFuncND)(&_SELECTOR) +#define callfuncO_selector(_SELECTOR) (cocos2d::SEL_CallFuncO)(&_SELECTOR) +#define menu_selector(_SELECTOR) (cocos2d::SEL_MenuHandler)(&_SELECTOR) +#define event_selector(_SELECTOR) (cocos2d::SEL_EventHandler)(&_SELECTOR) +#define compare_selector(_SELECTOR) (cocos2d::SEL_Compare)(&_SELECTOR) // end of base_nodes group /// @} diff --git a/loader/include/Geode/modify/Modify.hpp b/loader/include/Geode/modify/Modify.hpp index 9347de7e..de22a8ac 100644 --- a/loader/include/Geode/modify/Modify.hpp +++ b/loader/include/Geode/modify/Modify.hpp @@ -19,7 +19,6 @@ if constexpr (derived##index::uuid != nullptr && (void*)base##index::uuid != (vo namespace geode::modifier { - template <class Derived, class Base> class Modify; diff --git a/loader/include/Geode/ui/ColorPickPopup.hpp b/loader/include/Geode/ui/ColorPickPopup.hpp index 49d3f17d..6e71f0de 100644 --- a/loader/include/Geode/ui/ColorPickPopup.hpp +++ b/loader/include/Geode/ui/ColorPickPopup.hpp @@ -1,3 +1,5 @@ +#pragma once + #include "Popup.hpp" #include "InputNode.hpp" diff --git a/loader/include/Geode/ui/EnterLayerEvent.hpp b/loader/include/Geode/ui/EnterLayerEvent.hpp new file mode 100644 index 00000000..c3186226 --- /dev/null +++ b/loader/include/Geode/ui/EnterLayerEvent.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include "../loader/Event.hpp" + +namespace cocos2d { + class CCNode; +} + +namespace geode { + template<class T> + concept InheritsCCNode = std::is_base_of_v<cocos2d::CCNode, T>; + + template<InheritsCCNode T> + class EnterLayerEvent : public Event { + protected: + std::string m_layerID; + T* m_layer; + + public: + EnterLayerEvent( + std::string const& layerID, + T* layer + ) : m_layerID(layerID), + m_layer(layer) {} + + std::string getID() const { + return m_layerID; + } + + T* getLayer() const { + return m_layer; + } + }; + + template<class T, class N> + concept InheritsEnterLayer = std::is_base_of_v<EnterLayerEvent<N>, T>; + + template<class N, InheritsEnterLayer<N> T> + class EnterLayerEventHandler : public EventHandler<EnterLayerEvent<N>> { + public: + using Consumer = void(*)(T*); + + protected: + Consumer m_consumer; + std::optional<std::string> m_targetID; + + public: + PassThrough handle(EnterLayerEvent<N>* event) override { + if (m_targetID == event->getID()) { + m_consumer(static_cast<T*>(event)); + } + return PassThrough::Propagate; + } + + EnterLayerEventHandler( + std::optional<std::string> const& id, + Consumer handler + ) : m_targetID(id), + m_consumer(handler) {} + }; +} diff --git a/loader/src/cocos2d-ext/Layout.cpp b/loader/src/cocos2d-ext/Layout.cpp new file mode 100644 index 00000000..ddf9473a --- /dev/null +++ b/loader/src/cocos2d-ext/Layout.cpp @@ -0,0 +1,138 @@ +#include <cocos2d.h> +#include <Geode/utils/WackyGeodeMacros.hpp> + +using namespace cocos2d; + +void RowLayout::apply(CCArray* nodes, CCSize const& availableSize) { + float totalWidth = .0f; + CCARRAY_FOREACH_B_BASE(nodes, node, CCNode*, ix) { + totalWidth += node->getScaledContentSize().width; + if (ix) { + totalWidth += m_gap; + } + } + + float pos; + switch (m_alignment) { + default: + case Alignment::Center: pos = -totalWidth / 2; break; + case Alignment::Begin: pos = -totalWidth; break; + case Alignment::End: pos = 0.f; break; + } + CCARRAY_FOREACH_B_TYPE(nodes, node, CCNode) { + auto sw = node->getScaledContentSize().width; + node->setPositionX(pos + sw / 2); + if (m_alignVertically) { + node->setPositionY(m_alignVertically.value()); + } + pos += sw + m_gap; + } +} + +RowLayout* RowLayout::create( + float gap, + std::optional<float> alignVertically +) { + auto ret = new RowLayout; + ret->m_gap = gap; + ret->m_alignVertically = alignVertically; + return ret; +} + +RowLayout* RowLayout::setAlignment(Alignment align) { + m_alignment = align; + return this; +} + +RowLayout* RowLayout::setGap(float gap) { + m_gap = gap; + return this; +} + +RowLayout* RowLayout::setAlignVertically(std::optional<float> align) { + m_alignVertically = align; + return this; +} + +void ColumnLayout::apply(CCArray* nodes, CCSize const& availableSize) { + float totalHeight = .0f; + CCARRAY_FOREACH_B_BASE(nodes, node, CCNode*, ix) { + totalHeight += node->getScaledContentSize().height; + if (ix) { + totalHeight += m_gap; + } + } + + float pos; + switch (m_alignment) { + default: + case Alignment::Center: pos = -totalHeight / 2; break; + case Alignment::Begin: pos = -totalHeight; break; + case Alignment::End: pos = 0.f; break; + } + CCARRAY_FOREACH_B_TYPE(nodes, node, CCNode) { + auto sw = node->getScaledContentSize().height; + node->setPositionY(pos + sw / 2); + if (m_alignHorizontally) { + node->setPositionX(m_alignHorizontally.value()); + } + pos += sw + m_gap; + } +} + +ColumnLayout* ColumnLayout::create( + float gap, + std::optional<float> alignHorizontally +) { + auto ret = new ColumnLayout; + ret->m_gap = gap; + ret->m_alignHorizontally = alignHorizontally; + return ret; +} + +ColumnLayout* ColumnLayout::setAlignment(Alignment align) { + m_alignment = align; + return this; +} + +ColumnLayout* ColumnLayout::setGap(float gap) { + m_gap = gap; + return this; +} + +ColumnLayout* ColumnLayout::setAlignHorizontally(std::optional<float> align) { + m_alignHorizontally = align; + return this; +} + +void GridLayout::apply(CCArray* nodes, CCSize const& availableSize) { + // todo +} + +GridLayout* GridLayout::create( + std::optional<size_t> rowSize, + GridAlignment alignment, + GridDirection direction +) { + auto ret = new GridLayout; + ret->m_rowSize = rowSize; + ret->m_alignment = alignment; + ret->m_direction = direction; + return ret; +} + +GridLayout* GridLayout::setDirection(GridDirection direction) { + m_direction = direction; + return this; +} + +GridLayout* GridLayout::setAlignment(GridAlignment alignment) { + m_alignment = alignment; + return this; +} + +GridLayout* GridLayout::setRowSize(std::optional<size_t> rowSize) { + m_rowSize = rowSize; + return this; +} + diff --git a/loader/src/hooks/GeodeNodeMetadata.cpp b/loader/src/hooks/GeodeNodeMetadata.cpp index 8bb95f69..b3bcf056 100644 --- a/loader/src/hooks/GeodeNodeMetadata.cpp +++ b/loader/src/hooks/GeodeNodeMetadata.cpp @@ -18,6 +18,8 @@ private: FieldContainer* m_fieldContainer; Ref<cocos2d::CCObject> m_userObject; std::string m_id = ""; + std::unique_ptr<Layout> m_layout = nullptr; + PositionHint m_positionHint = PositionHint::Default; friend class ProxyCCNode; friend class cocos2d::CCNode; @@ -102,4 +104,37 @@ CCNode* CCNode::getChildByIDRecursive(std::string const& id) { return nullptr; } +void CCNode::setLayout(Layout* layout, bool apply) { + GeodeNodeMetadata::set(this)->m_layout.reset(layout); + if (apply) { + this->updateLayout(); + } +} + +Layout* CCNode::getLayout() { + return GeodeNodeMetadata::set(this)->m_layout.get(); +} + +void CCNode::updateLayout() { + if (auto layout = GeodeNodeMetadata::set(this)->m_layout.get()) { + // nodes with absolute position should never be rearranged + auto filtered = CCArray::createWithCapacity(m_pChildren->capacity()); + CCARRAY_FOREACH_B_TYPE(m_pChildren, child, CCNode) { + if (child->getPositionHint() != PositionHint::Absolute) { + filtered->addObject(child); + } + } + layout->apply(filtered, m_obContentSize); + filtered->release(); + } +} + +void CCNode::setPositionHint(PositionHint hint) { + GeodeNodeMetadata::set(this)->m_positionHint = hint; +} + +PositionHint CCNode::getPositionHint() { + return GeodeNodeMetadata::set(this)->m_positionHint; +} + #pragma warning(pop) diff --git a/loader/src/hooks/MenuLayer.cpp b/loader/src/hooks/MenuLayer.cpp index a6c741ff..a5bec5bf 100644 --- a/loader/src/hooks/MenuLayer.cpp +++ b/loader/src/hooks/MenuLayer.cpp @@ -1,4 +1,4 @@ -#include <Geode/Geode.hpp> +#include <Geode/Bindings.hpp> #include <Geode/utils/WackyGeodeMacros.hpp> #include <Geode/ui/BasedButtonSprite.hpp> #include <Geode/ui/Notification.hpp> @@ -139,77 +139,12 @@ class $modify(CustomMenuLayer, MenuLayer) { bool init() { if (!MenuLayer::init()) return false; - + Loader::get()->updateResourcePaths(); - auto setIDSafe = +[](CCNode* node, int index, const char* id) { - if (auto child = getChild(node, index)) { - child->setID(id); - } - }; - - // set IDs to everything - this->setID("main-menu-layer"); - setIDSafe(this, 0, "main-menu-bg"); - getChildOfType<CCSprite>(this, 0)->setID("main-title"); - - if (PlatformToolbox::isControllerConnected()) { - getChildOfType<CCSprite>(this, 1)->setID("play-gamepad-icon"); - getChildOfType<CCSprite>(this, 2)->setID("editor-gamepad-icon"); - getChildOfType<CCSprite>(this, 3)->setID("icon-kit-gamepad-icon"); - - getChildOfType<CCSprite>(this, 4)->setID("settings-gamepad-icon"); - getChildOfType<CCSprite>(this, 5)->setID("mouse-gamepad-icon"); - getChildOfType<CCSprite>(this, 6)->setID("click-gamepad-icon"); - - getChildOfType<CCLabelBMFont>(this, 0)->setID("mouse-gamepad-label"); - getChildOfType<CCLabelBMFont>(this, 1)->setID("click-gamepad-label"); - - getChildOfType<CCLabelBMFont>(this, 2)->setID("player-username"); - } else { - getChildOfType<CCLabelBMFont>(this, 0)->setID("player-username"); - } - if (auto menu = getChildOfType<CCMenu>(this, 0)) { - menu->setID("main-menu"); - setIDSafe(menu, 0, "play-button"); - setIDSafe(menu, 1, "icon-kit-button"); - setIDSafe(menu, 2, "editor-button"); - setIDSafe(menu, 3, "profile-button"); - } - if (auto menu = getChildOfType<CCMenu>(this, 1)) { - menu->setID("bottom-menu"); - setIDSafe(menu, 0, "achievements-button"); - setIDSafe(menu, 1, "settings-button"); - setIDSafe(menu, 2, "stats-button"); - setIDSafe(menu, 3, "newgrounds-button"); - setIDSafe(menu, -1,"daily-chest-button"); - } - if (auto menu = getChildOfType<CCMenu>(this, 2)) { - menu->setID("social-media-menu"); - setIDSafe(menu, 0, "robtop-logo-button"); - setIDSafe(menu, 1, "facebook-button"); - setIDSafe(menu, 2, "twitter-button"); - setIDSafe(menu, 3, "youtube-button"); - } - if (auto menu = getChildOfType<CCMenu>(this, 3)) { - menu->setID("more-games-menu"); - setIDSafe(menu, 0, "more-games-button"); - setIDSafe(menu, 1, "close-button"); - } - auto winSize = CCDirector::sharedDirector()->getWinSize(); // add geode button - auto bottomMenu = static_cast<CCMenu*>(this->getChildByID("bottom-menu")); - - // keep chest in the same position - auto chest = bottomMenu->getChildByID("daily-chest-button"); - if (chest) { - chest->retain(); - chest->removeFromParent(); - } - - auto y = getChild(bottomMenu, 0)->getPositionY(); g_geodeButton = SafeCreate<CCSprite>() .with(CircleButtonSprite::createWithSpriteFrameName( @@ -221,21 +156,16 @@ class $modify(CustomMenuLayer, MenuLayer) { .orMake<ButtonSprite>("!!"); addUpdateIcon(); + + auto bottomMenu = static_cast<CCMenu*>(this->getChildByID("bottom-menu")); + auto btn = CCMenuItemSpriteExtra::create( g_geodeButton.data(), this, menu_selector(CustomMenuLayer::onGeode) ); btn->setID("geode-button"); bottomMenu->addChild(btn); - bottomMenu->alignItemsHorizontallyWithPadding(3.f); - - CCARRAY_FOREACH_B_TYPE(bottomMenu->getChildren(), node, CCNode) { - node->setPositionY(y); - } - if (chest) { - bottomMenu->addChild(chest); - chest->release(); - } + bottomMenu->updateLayout(); if (auto node = this->getChildByID("settings-gamepad-icon")) { node->setPositionX(bottomMenu->getChildByID( @@ -286,7 +216,7 @@ class $modify(CustomMenuLayer, MenuLayer) { Index::get()->updateIndex(updateIndexProgress); } - + return true; } diff --git a/loader/src/ids/MenuLayer.cpp b/loader/src/ids/MenuLayer.cpp new file mode 100644 index 00000000..3ee8f760 --- /dev/null +++ b/loader/src/ids/MenuLayer.cpp @@ -0,0 +1,81 @@ +#include <Geode/Modify.hpp> +#include <Geode/Bindings.hpp> +#include <Geode/utils/cocos.hpp> +#include <Geode/ui/EnterLayerEvent.hpp> + +USE_GEODE_NAMESPACE(); + +class $modify(MenuLayer) { + bool init() { + auto setIDSafe = +[](CCNode* node, int index, const char* id) -> CCNode* { + if (auto child = getChild(node, index)) { + child->setID(id); + return child; + } + return nullptr; + }; + + // set IDs to everything + this->setID("main-menu-layer"); + setIDSafe(this, 0, "main-menu-bg"); + getChildOfType<CCSprite>(this, 0)->setID("main-title"); + + if (PlatformToolbox::isControllerConnected()) { + getChildOfType<CCSprite>(this, 1)->setID("play-gamepad-icon"); + getChildOfType<CCSprite>(this, 2)->setID("editor-gamepad-icon"); + getChildOfType<CCSprite>(this, 3)->setID("icon-kit-gamepad-icon"); + + getChildOfType<CCSprite>(this, 4)->setID("settings-gamepad-icon"); + getChildOfType<CCSprite>(this, 5)->setID("mouse-gamepad-icon"); + getChildOfType<CCSprite>(this, 6)->setID("click-gamepad-icon"); + + getChildOfType<CCLabelBMFont>(this, 0)->setID("mouse-gamepad-label"); + getChildOfType<CCLabelBMFont>(this, 1)->setID("click-gamepad-label"); + + getChildOfType<CCLabelBMFont>(this, 2)->setID("player-username"); + } else { + getChildOfType<CCLabelBMFont>(this, 0)->setID("player-username"); + } + if (auto menu = getChildOfType<CCMenu>(this, 0)) { + menu->setID("main-menu"); + setIDSafe(menu, 0, "play-button"); + auto iconKit = setIDSafe(menu, 1, "icon-kit-button"); + setIDSafe(menu, 2, "editor-button"); + + if (auto pfp = setIDSafe(menu, 3, "profile-button")) { + pfp->setPositionHint(PositionHint::Absolute); + } + + menu->setLayout(RowLayout::create(5.f, 0.f)); + } + if (auto menu = getChildOfType<CCMenu>(this, 1)) { + menu->setID("bottom-menu"); + auto ach = setIDSafe(menu, 0, "achievements-button"); + setIDSafe(menu, 1, "settings-button"); + setIDSafe(menu, 2, "stats-button"); + setIDSafe(menu, 3, "newgrounds-button"); + + if (auto dailyChest = setIDSafe(menu, -1, "daily-chest-button")) { + dailyChest->setPositionHint(PositionHint::Absolute); + } + + menu->setLayout(RowLayout::create(5.f, ach->getPositionY())); + } + if (auto menu = getChildOfType<CCMenu>(this, 2)) { + menu->setID("social-media-menu"); + setIDSafe(menu, 0, "robtop-logo-button"); + setIDSafe(menu, 1, "facebook-button"); + setIDSafe(menu, 2, "twitter-button"); + setIDSafe(menu, 3, "youtube-button"); + } + if (auto menu = getChildOfType<CCMenu>(this, 3)) { + menu->setID("more-games-menu"); + setIDSafe(menu, 0, "more-games-button"); + setIDSafe(menu, 1, "close-button"); + } + + EnterLayerEvent("MenuLayer", this).post(); + + return true; + } +};