mirror of
https://github.com/geode-sdk/geode.git
synced 2025-03-24 03:39:56 -04:00
commit
75be0b6502
34 changed files with 2546 additions and 577 deletions
CMakeLists.txtVERSION
bindings
loader
CMakeLists.txt
include/Geode
cocos
loader
platform
ui
utils
resources
src
cocos2d-ext
hooks
ids
AddIDs.hppCreatorLayer.cppEditLevelLayer.cppEditorPauseLayer.cppEditorUI.cppGJGarageLayer.cppLevelBrowserLayer.cppLevelInfoLayer.cppLevelSettingsLayer.cppMenuLayer.cpp
internal
loader
ui/internal/list
utils
|
@ -15,14 +15,32 @@ string(STRIP "${GEODE_VERSION}" GEODE_VERSION)
|
|||
|
||||
# Check if version has a tag like v1.0.0-alpha
|
||||
string(FIND ${GEODE_VERSION} "-" GEODE_VERSION_HAS_TAG)
|
||||
if (GEODE_VERSION_HAS_TAG)
|
||||
string(REGEX MATCH "[a-z]+[0-9]?$" GEODE_VERSION_TAG ${GEODE_VERSION})
|
||||
if (NOT ${GEODE_VERSION_HAS_TAG} EQUAL "-1")
|
||||
string(REGEX MATCH "[a-z]+(\.[0-9]+)?$" GEODE_VERSION_TAG ${GEODE_VERSION})
|
||||
string(SUBSTRING "${GEODE_VERSION}" 0 ${GEODE_VERSION_HAS_TAG} GEODE_VERSION)
|
||||
string(FIND ${GEODE_VERSION_TAG} "." GEODE_VERSION_TAG_HAS_NUMBER)
|
||||
|
||||
# Extract tag type and number from tag
|
||||
if (NOT ${GEODE_VERSION_TAG_HAS_NUMBER} EQUAL "-1")
|
||||
string(SUBSTRING "${GEODE_VERSION_TAG}" 0 ${GEODE_VERSION_TAG_HAS_NUMBER} GEODE_VERSION_TAG_TYPE)
|
||||
math(EXPR GEODE_VERSION_TAG_HAS_NUMBER "${GEODE_VERSION_TAG_HAS_NUMBER} + 1")
|
||||
string(SUBSTRING "${GEODE_VERSION_TAG}" ${GEODE_VERSION_TAG_HAS_NUMBER} -1 GEODE_VERSION_TAG_NUMBER)
|
||||
else()
|
||||
set(GEODE_VERSION_TAG_TYPE "${GEODE_VERSION_TAG}")
|
||||
set(GEODE_VERSION_TAG_NUMBER "")
|
||||
endif()
|
||||
|
||||
# Capitalize first letter of tag type
|
||||
string(SUBSTRING ${GEODE_VERSION_TAG_TYPE} 0 1 FIRST_LETTER)
|
||||
string(TOUPPER ${FIRST_LETTER} FIRST_LETTER)
|
||||
string(REGEX REPLACE "^.(.*)" "${FIRST_LETTER}\\1" GEODE_VERSION_TAG_TYPE "${GEODE_VERSION_TAG_TYPE}")
|
||||
else()
|
||||
set(GEODE_VERSION_TAG "")
|
||||
set(GEODE_VERSION_TAG_TYPE "")
|
||||
set(GEODE_VERSION_TAG_NUMBER "")
|
||||
endif()
|
||||
|
||||
message(STATUS "Version: ${GEODE_VERSION}, tag: ${GEODE_VERSION_TAG}")
|
||||
message(STATUS "Version: ${GEODE_VERSION}, tag: ${GEODE_VERSION_TAG} (type: ${GEODE_VERSION_TAG_TYPE}, number: ${GEODE_VERSION_TAG_NUMBER})")
|
||||
|
||||
project(geode-sdk VERSION ${GEODE_VERSION} LANGUAGES CXX C)
|
||||
|
||||
|
@ -60,7 +78,7 @@ if (GEODE_DISABLE_FMT_CONSTEVAL)
|
|||
target_compile_definitions(${PROJECT_NAME} INTERFACE -DFMT_CONSTEVAL=)
|
||||
endif()
|
||||
|
||||
CPMAddPackage("gh:geode-sdk/json#2b76460")
|
||||
CPMAddPackage("gh:geode-sdk/json#cef9c64")
|
||||
CPMAddPackage("gh:fmtlib/fmt#9.1.0")
|
||||
CPMAddPackage("gh:gulrak/filesystem#3e5b930")
|
||||
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
1.0.0-beta
|
||||
1.0.0-beta.6
|
|
@ -296,6 +296,7 @@ class CCCircleWave : cocos2d::CCNode {
|
|||
PAD = win 0x4;
|
||||
float m_currentRadius;
|
||||
float m_currentOpacity;
|
||||
cocos2d::ccColor3B m_color;
|
||||
cocos2d::CCPoint m_circleCenter;
|
||||
int m_filled;
|
||||
int m_lineWidth;
|
||||
|
@ -1120,7 +1121,7 @@ class EditorPauseLayer : CCBlockLayer, FLAlertLayerProtocol {
|
|||
if (!EditorUI::get()) return nullptr;
|
||||
|
||||
auto editor = LevelEditorLayer::get();
|
||||
for (auto i = 0; i < editor->getChildrenCount(); ++i) {
|
||||
for (auto i = 0u; i < editor->getChildrenCount(); ++i) {
|
||||
if (auto layer = cast::safe_cast<EditorPauseLayer*>(editor->getChildren()->objectAtIndex(i))) {
|
||||
return layer;
|
||||
}
|
||||
|
@ -1154,11 +1155,13 @@ class EditorPauseLayer : CCBlockLayer, FLAlertLayerProtocol {
|
|||
void uncheckAllPortals(cocos2d::CCObject* sender) = win 0x74760;
|
||||
void onResetUnusedColors(cocos2d::CCObject* sender) = win 0x74810;
|
||||
void doResetUnused() = win 0x165070;
|
||||
void updateSongButton() = win 0x74f10, mac 0x13e530;
|
||||
void onSong(cocos2d::CCObject*) = win 0x74e70, mac 0x13e470;
|
||||
|
||||
bool m_saved;
|
||||
PAD = mac 0x8, win 0x4;
|
||||
CCMenuItemSpriteExtra* m_button0;
|
||||
CCMenuItemSpriteExtra* m_button1;
|
||||
CCMenuItemSpriteExtra* m_guidelinesOffButton;
|
||||
CCMenuItemSpriteExtra* m_guidelinesOnButton;
|
||||
LevelEditorLayer* m_editorLayer;
|
||||
}
|
||||
|
||||
|
@ -2615,6 +2618,9 @@ class GameLevelManager : cocos2d::CCNode {
|
|||
void storeUserNames(gd::string) = win 0xa1840;
|
||||
gd::string userNameForUserID(int id) = win 0xa1c20;
|
||||
void updateUserScore() = win 0xada60;
|
||||
void downloadLevel(int id, bool downloadData) = win 0xaa730;
|
||||
bool hasDownloadedLevel(int id) = win 0xab830;
|
||||
GJGameLevel* getSavedLevel(int id) = win 0xa2ee0;
|
||||
|
||||
inline static GameLevelManager* get() {
|
||||
return GameLevelManager::sharedState();
|
||||
|
@ -2820,7 +2826,7 @@ class GameManager : GManager {
|
|||
void getGTexture(int) = mac 0x1cca40, win 0xc9a50;
|
||||
virtual bool init() = mac 0x1c2ec0, win 0xc4ad0;
|
||||
void reportAchievementWithID(char const*, int, bool) = mac 0x1c6460, win 0xc64c0;
|
||||
cocos2d::CCSize* resolutionForKey(cocos2d::CCSize*, int) = mac 0x1d0b40, win 0xceca0;
|
||||
cocos2d::CCSize resolutionForKey(int) = mac 0x1d0b40, win 0xceca0;
|
||||
virtual void update(float) = mac 0x1d0270, win 0xce440;
|
||||
bool isColorUnlocked(int _id, bool _type) = mac 0x1c3b90, win 0xc53f0;
|
||||
bool isIconUnlocked(int _id, IconType _type) = mac 0x1c35b0, win 0xc4fc0;
|
||||
|
@ -3271,6 +3277,9 @@ class GameSoundManager : cocos2d::CCNode {
|
|||
void asynchronousSetup() = win 0x25520;
|
||||
~GameSoundManager() = mac 0x362c00, win 0x25640;
|
||||
static GameSoundManager* sharedManager() = mac 0x3610f0, win 0x24800;
|
||||
inline static GameSoundManager* get() {
|
||||
return GameSoundManager::sharedManager();
|
||||
}
|
||||
|
||||
cocos2d::CCDictionary* m_dictionary1;
|
||||
cocos2d::CCDictionary* m_dictionary2;
|
||||
|
@ -3962,6 +3971,9 @@ class MenuLayer : cocos2d::CCLayer, FLAlertLayerProtocol, GooglePlayDelegate {
|
|||
void onYouTube(cocos2d::CCObject*) = win 0x1919A0;
|
||||
static cocos2d::CCScene* scene(bool) = mac 0x1d12d0, win 0x190720, ios 0x19e57c;
|
||||
static MenuLayer* node() = win 0x190550;
|
||||
inline static MenuLayer* create() {
|
||||
return MenuLayer::node();
|
||||
}
|
||||
|
||||
cocos2d::CCSprite* m_googlePlaySprite;
|
||||
cocos2d::CCSprite* m_viewProfileInfoText;
|
||||
|
@ -4562,7 +4574,7 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate {
|
|||
void modeDidChange() = mac 0x22bfd0;
|
||||
void placeStreakPoint() = mac 0x21af90, win 0x1f95e0;
|
||||
void playBurstEffect() = mac 0x21c780, win 0x1f6790;
|
||||
void playDeathEffect() = mac 0x225930, win 0x2efbe0;
|
||||
void playDeathEffect() = mac 0x225930, win 0x1efbe0;
|
||||
void playDynamicSpiderRun() = mac 0x222ec0, win 0x1f9d80;
|
||||
void playerDestroyed(bool) = mac 0x2256d0, win 0x1efaa0;
|
||||
bool playerIsFalling() = mac 0x21c730, win 0x1f5d60;
|
||||
|
|
|
@ -1,8 +1,21 @@
|
|||
cmake_minimum_required(VERSION 3.21 FATAL_ERROR)
|
||||
|
||||
project(geode-loader VERSION ${GEODE_VERSION} LANGUAGES C CXX)
|
||||
set(PROJECT_VERSION_TYPE geode::VersionTag::Beta)
|
||||
set(PROJECT_VERSION_SUFFIX -beta)
|
||||
if (GEODE_VERSION_TAG_TYPE)
|
||||
if (GEODE_VERSION_TAG_NUMBER)
|
||||
set(PROJECT_VERSION_TAG_CONSTR "geode::VersionTag(geode::VersionTag::${GEODE_VERSION_TAG_TYPE}, ${GEODE_VERSION_TAG_NUMBER})")
|
||||
else()
|
||||
set(PROJECT_VERSION_TAG_CONSTR "geode::VersionTag::${GEODE_VERSION_TAG_TYPE}")
|
||||
endif()
|
||||
else()
|
||||
set(PROJECT_VERSION_TAG_CONSTR "std::nullopt")
|
||||
endif()
|
||||
|
||||
if (GEODE_VERSION_TAG)
|
||||
set(PROJECT_VERSION_SUFFIX "-${GEODE_VERSION_TAG}")
|
||||
else()
|
||||
set(PROJECT_VERSION_SUFFIX "")
|
||||
endif()
|
||||
|
||||
# Package info file for internal representation
|
||||
configure_file(resources/mod.json.in ${CMAKE_CURRENT_SOURCE_DIR}/resources/mod.json)
|
||||
|
|
64
loader/include/Geode/cocos/base_nodes/CCNode.h
vendored
64
loader/include/Geode/cocos/base_nodes/CCNode.h
vendored
|
@ -616,17 +616,15 @@ public:
|
|||
* Return an array of children
|
||||
*
|
||||
* Composing a "tree" structure is a very important feature of CCNode
|
||||
* Here's a sample code of traversing children array:
|
||||
* @code
|
||||
* @example
|
||||
* // Here's a sample code of traversing children array:
|
||||
* CCNode* node = NULL;
|
||||
* CCARRAY_FOREACH(parent->getChildren(), node)
|
||||
* {
|
||||
* node->setPosition(0,0);
|
||||
* }
|
||||
* @endcode
|
||||
* This sample code traverses all children nodes, and set theie position to (0,0)
|
||||
*
|
||||
* @return An array of children
|
||||
* // This sample code traverses all children nodes, and set theie position to (0,0)
|
||||
* @returns An array of children
|
||||
*/
|
||||
virtual CCArray* getChildren();
|
||||
|
||||
|
@ -761,7 +759,7 @@ public:
|
|||
* Returns a tag that is used to identify the node easily.
|
||||
*
|
||||
* You can set tags to node then identify them easily.
|
||||
* @code
|
||||
* @example
|
||||
* #define TAG_PLAYER 1
|
||||
* #define TAG_MONSTER 2
|
||||
* #define TAG_BOSS 3
|
||||
|
@ -786,9 +784,7 @@ public:
|
|||
* break;
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @return A interger that identifies the node.
|
||||
* @returns A interger that identifies the node.
|
||||
*/
|
||||
RT_REMOVE( virtual int getTag() const; )
|
||||
/**
|
||||
|
@ -883,6 +879,26 @@ public:
|
|||
*/
|
||||
GEODE_DLL CCNode* getChildByIDRecursive(std::string const& id);
|
||||
|
||||
/**
|
||||
* Add a child before a specified existing child
|
||||
* @param child The node to add. The node may not be a child of another
|
||||
* node already
|
||||
* @param before The child the node is added before of. If this is null or
|
||||
* not a child of this node, the new child will be placed at the start of the
|
||||
* child list
|
||||
*/
|
||||
GEODE_DLL void insertBefore(CCNode* child, CCNode* before);
|
||||
|
||||
/**
|
||||
* Add a child after an specified existing child
|
||||
* @param child The node to add. The node may not be a child of another
|
||||
* node already
|
||||
* @param after The child the node is added after of. If this is null or
|
||||
* not a child of this node, the new child will be placed at the end of the
|
||||
* child list
|
||||
*/
|
||||
GEODE_DLL void insertAfter(CCNode* child, CCNode* after);
|
||||
|
||||
/**
|
||||
* Set an attribute on a node. Attributes are a system added by Geode,
|
||||
* where a node may have any sort of extra data associated with it. Used
|
||||
|
@ -921,9 +937,14 @@ public:
|
|||
* has been added, call updateLayout
|
||||
* @param layout Layout to set to this node
|
||||
* @param apply Whether to call updateLayout now or not
|
||||
* @param respectAnchor If true, if the target node is
|
||||
* isIgnoreAnchorPointForPosition, then it is set to false and the children
|
||||
* are automatically moved to match where they should be positioned.
|
||||
* Visually, this should result in no difference; however, when dealing with
|
||||
* CCLayers / CCMenus, this will change where the children are located
|
||||
* @note Geode addition
|
||||
*/
|
||||
GEODE_DLL void setLayout(Layout* layout, bool apply = true);
|
||||
GEODE_DLL void setLayout(Layout* layout, bool apply = true, bool respectAnchor = true);
|
||||
/**
|
||||
* Get the Layout for this node
|
||||
* @returns The current layout, or nullptr if no layout is set
|
||||
|
@ -935,23 +956,22 @@ public:
|
|||
* set, nothing happens
|
||||
* @note Geode addition
|
||||
*/
|
||||
GEODE_DLL void updateLayout();
|
||||
|
||||
GEODE_DLL void updateLayout(bool updateChildOrder = true);
|
||||
/**
|
||||
* Give a hint to the current Layout about where this node should be
|
||||
* positioned in it. Allows detaching the node from the current
|
||||
* layout by setting position to absolute
|
||||
* @param hint The hint to set
|
||||
* @note The layout definitely should, but might not respect the hint
|
||||
* given
|
||||
* Set the layout options for this node. Layout options can be used to
|
||||
* control how this node is positioned in its parent's Layout, for example
|
||||
* setting the grow size for a flex layout
|
||||
* @param options The layout options
|
||||
* @param apply Whether to update the layout of the parent node
|
||||
* @note Geode addition
|
||||
*/
|
||||
GEODE_DLL void setPositionHint(PositionHint hint);
|
||||
GEODE_DLL void setLayoutOptions(LayoutOptions* options, bool apply = true);
|
||||
/**
|
||||
* Get the current position hint for this node
|
||||
* Get the layout options for this node
|
||||
* @returns The current layout options, or nullptr if no options are set
|
||||
* @note Geode addition
|
||||
*/
|
||||
GEODE_DLL PositionHint getPositionHint();
|
||||
GEODE_DLL LayoutOptions* getLayoutOptions();
|
||||
|
||||
/**
|
||||
* Swap two children
|
||||
|
|
388
loader/include/Geode/cocos/base_nodes/Layout.hpp
vendored
388
loader/include/Geode/cocos/base_nodes/Layout.hpp
vendored
|
@ -18,136 +18,334 @@ class CCNode;
|
|||
* RowLayout, ColumnLayout, and GridLayout, but if you need a different kind
|
||||
* of layout you can inherit from the Layout class.
|
||||
*/
|
||||
class Layout {
|
||||
class GEODE_DLL Layout {
|
||||
protected:
|
||||
static CCArray* getNodesToPosition(CCNode* forNode);
|
||||
|
||||
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
|
||||
* @param on Node to apply the layout on. Position's the node's children
|
||||
* according to the layout. The content size of the node should be
|
||||
* respected as a boundary the layout shouldn't overflow. The node may be
|
||||
* rescaled to better fit its contents
|
||||
*/
|
||||
virtual void apply(CCArray* nodes, CCSize const& availableSize) = 0;
|
||||
virtual void apply(CCNode* on) = 0;
|
||||
|
||||
virtual ~Layout() = default;
|
||||
};
|
||||
|
||||
class GEODE_DLL LayoutOptions {
|
||||
public:
|
||||
virtual ~LayoutOptions() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines how a node should be positioned within its parent, if that
|
||||
* parent has an automatically positioning layout
|
||||
* The direction of an AxisLayout
|
||||
*/
|
||||
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,
|
||||
enum class Axis {
|
||||
Row,
|
||||
Column,
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies the alignment of something
|
||||
* Specifies the alignment of something in an AxisLayout
|
||||
*/
|
||||
enum class Alignment {
|
||||
Begin,
|
||||
enum class AxisAlignment {
|
||||
// Align items to the start
|
||||
// |ooo......|
|
||||
Start,
|
||||
// All items are centered
|
||||
// |...ooo...|
|
||||
Center,
|
||||
// Align items to the end
|
||||
// |......ooo|
|
||||
End,
|
||||
// Each item gets the same portion from the layout (disregards gap)
|
||||
// |.o..o..o.|
|
||||
Even,
|
||||
};
|
||||
|
||||
constexpr float AXISLAYOUT_DEFAULT_MIN_SCALE = 0.65f;
|
||||
constexpr int AXISLAYOUT_DEFAULT_PRIORITY = 0;
|
||||
|
||||
/**
|
||||
* Options for controlling the behaviour of individual nodes in an AxisLayout
|
||||
* @example
|
||||
* auto node = CCNode::create();
|
||||
* // this node will have 10 units of spacing between it and the next one
|
||||
* node->setLayoutOptions(
|
||||
* AxisLayoutOptions::create()
|
||||
* ->setNextGap(10.f)
|
||||
* );
|
||||
* someNodeWithALayout->addChild(node);
|
||||
*/
|
||||
class GEODE_DLL AxisLayoutOptions : public LayoutOptions {
|
||||
protected:
|
||||
std::optional<bool> m_autoScale = std::nullopt;
|
||||
float m_maxScale = 1.f;
|
||||
float m_minScale = AXISLAYOUT_DEFAULT_MIN_SCALE;
|
||||
float m_relativeScale = 1.f;
|
||||
std::optional<float> m_length = std::nullopt;
|
||||
std::optional<float> m_nextGap = std::nullopt;
|
||||
std::optional<float> m_prevGap = std::nullopt;
|
||||
bool m_breakLine = false;
|
||||
bool m_sameLine = false;
|
||||
int m_scalePriority = AXISLAYOUT_DEFAULT_PRIORITY;
|
||||
|
||||
public:
|
||||
static AxisLayoutOptions* create();
|
||||
|
||||
std::optional<bool> getAutoScale() const;
|
||||
float getMaxScale() const;
|
||||
float getMinScale() const;
|
||||
float getRelativeScale() const;
|
||||
std::optional<float> getLength() const;
|
||||
std::optional<float> getPrevGap() const;
|
||||
std::optional<float> getNextGap() const;
|
||||
bool getBreakLine() const;
|
||||
bool getSameLine() const;
|
||||
int getScalePriority() const;
|
||||
|
||||
/**
|
||||
* Set the maximum scale this node can be if it's contained in an
|
||||
* auto-scaled layout. Default is 1
|
||||
*/
|
||||
AxisLayoutOptions* setMaxScale(float scale);
|
||||
|
||||
/**
|
||||
* Set the minimum scale this node can be if it's contained in an
|
||||
* auto-scaled layout. Default is AXISLAYOUT_DEFAULT_MIN_SCALE
|
||||
*/
|
||||
AxisLayoutOptions* setMinScale(float scale);
|
||||
|
||||
/**
|
||||
* Set the relative scale of this node compared to other nodes if it's
|
||||
* contained in an auto-scaled layout. Default is 1
|
||||
*/
|
||||
AxisLayoutOptions* setRelativeScale(float scale);
|
||||
|
||||
/**
|
||||
* Set auto-scaling for this node, overriding the layout's auto-scale
|
||||
* setting. If nullopt, the layout's auto-scale options will be used
|
||||
*/
|
||||
AxisLayoutOptions* setAutoScale(std::optional<bool> enabled);
|
||||
|
||||
/**
|
||||
* Set an absolute length for this node. If nullopt, the length will be
|
||||
* dynamically calculated based on content size
|
||||
*/
|
||||
AxisLayoutOptions* setLength(std::optional<float> length);
|
||||
|
||||
/**
|
||||
* Override the default gap in the layout between this node and the
|
||||
* previous one. If nullopt, the default gap of the layout will be used
|
||||
*/
|
||||
AxisLayoutOptions* setPrevGap(std::optional<float> gap);
|
||||
|
||||
/**
|
||||
* Override the default gap in the layout between this node and the next
|
||||
* one. If nullopt, the default gap of the layout will be used
|
||||
*/
|
||||
AxisLayoutOptions* setNextGap(std::optional<float> gap);
|
||||
|
||||
/**
|
||||
* If enabled, the node will always cause a growable axis layout to break
|
||||
* into a new line even if the current line could've fit the next node
|
||||
*/
|
||||
AxisLayoutOptions* setBreakLine(bool enable);
|
||||
|
||||
/**
|
||||
* If enabled, the node will be forced to be on the same line as the
|
||||
* previous node even if doing this would overflow
|
||||
*/
|
||||
AxisLayoutOptions* setSameLine(bool enable);
|
||||
|
||||
/**
|
||||
* Set the scale priority of this node. Nodes with higher priority will be
|
||||
* scaled down first before nodes with lower priority when an auto-scaled
|
||||
* layout attempts to fit its contents. Default is
|
||||
* AXISLAYOUT_DEFAULT_PRIORITY
|
||||
* @note For optimal performance, the priorities should all be close to
|
||||
* each other with no gaps
|
||||
*/
|
||||
AxisLayoutOptions* setScalePriority(int priority);
|
||||
};
|
||||
|
||||
/**
|
||||
* A multi-purpose dynamic layout for arranging nodes along an axis. Can be
|
||||
* used to arrange nodes in a single line, a grid, or a flex layout. The
|
||||
* RowLayout and ColumnLayout classes function as simple thin wrappers over
|
||||
* AxisLayout. The positioning of individual nodes in the layout can be
|
||||
* further controlled using AxisLayoutOptions
|
||||
* @warning Calculating layouts can get increasingly expensive for large
|
||||
* amounts of child nodes being fit into a small space - while this should
|
||||
* never prove a real performance concern as most layouts only have a few
|
||||
* hundred children at the very most, be aware that you probably shouldn't
|
||||
* call CCNode::updateLayout every frame for a menu with thousands of children
|
||||
* @example
|
||||
* auto menu = CCMenu::create();
|
||||
* // The menu's children will be arranged horizontally, unless they overflow
|
||||
* // the content size width in which case a new line will be inserted and
|
||||
* // aligned to the left. The menu automatically will automatically grow in
|
||||
* // height to fit all the rows
|
||||
* menu->setLayout(
|
||||
* RowLayout::create()
|
||||
* ->setGap(10.f)
|
||||
* ->setGrowCrossAxis(true)
|
||||
* ->setAxisAlignment(AxisAlignment::Start)
|
||||
* );
|
||||
* menu->setContentSize({ 200.f, 0.f });
|
||||
* menu->addChild(...);
|
||||
* menu->updateLayout();
|
||||
*/
|
||||
class GEODE_DLL AxisLayout : public Layout {
|
||||
protected:
|
||||
Axis m_axis;
|
||||
AxisAlignment m_axisAlignment = AxisAlignment::Center;
|
||||
AxisAlignment m_crossAlignment = AxisAlignment::Center;
|
||||
AxisAlignment m_crossLineAlignment = AxisAlignment::Center;
|
||||
float m_gap = 5.f;
|
||||
bool m_autoScale = true;
|
||||
bool m_axisReverse = false;
|
||||
bool m_crossReverse = false;
|
||||
bool m_allowCrossAxisOverflow = true;
|
||||
bool m_growCrossAxis = false;
|
||||
|
||||
struct Row;
|
||||
|
||||
float minScaleForPrio(CCArray* nodes, int prio) const;
|
||||
float maxScaleForPrio(CCArray* nodes, int prio) const;
|
||||
bool shouldAutoScale(AxisLayoutOptions const* opts) const;
|
||||
bool canTryScalingDown(
|
||||
CCArray* nodes,
|
||||
int& prio, float& scale,
|
||||
float crossScaleDownFactor,
|
||||
std::pair<int, int> const& minMaxPrios
|
||||
) const;
|
||||
float nextGap(AxisLayoutOptions const* now, AxisLayoutOptions const* next) const;
|
||||
Row* fitInRow(
|
||||
CCNode* on, CCArray* nodes,
|
||||
std::pair<int, int> const& minMaxPrios,
|
||||
bool doAutoScale,
|
||||
float scale, float squish, int prio
|
||||
) const;
|
||||
void tryFitLayout(
|
||||
CCNode* on, CCArray* nodes,
|
||||
std::pair<int, int> const& minMaxPrios,
|
||||
bool doAutoScale,
|
||||
float scale, float squish, int prio
|
||||
) const;
|
||||
|
||||
AxisLayout(Axis);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create a new AxisLayout. Note that this class is not automatically
|
||||
* managed by default, so you must assign it to a CCNode or manually
|
||||
* manage the memory yourself. See the chainable setters on AxisLayout for
|
||||
* what options you can customize for the layout
|
||||
* @param axis The direction of the layout
|
||||
* @note For convenience, you can use the RowLayout and ColumnLayout
|
||||
* classes, which are just thin wrappers over AxisLayout
|
||||
* @returns Created AxisLayout
|
||||
*/
|
||||
static AxisLayout* create(Axis axis = Axis::Row);
|
||||
|
||||
void apply(CCNode* on) override;
|
||||
|
||||
Axis getAxis() const;
|
||||
AxisAlignment getAxisAlignment() const;
|
||||
AxisAlignment getCrossAxisAlignment() const;
|
||||
AxisAlignment getCrossAxisLineAlignment() const;
|
||||
float getGap() const;
|
||||
bool getAxisReverse() const;
|
||||
bool getCrossAxisReverse() const;
|
||||
bool getAutoScale() const;
|
||||
bool getGrowCrossAxis() const;
|
||||
bool getCrossAxisOverflow() const;
|
||||
|
||||
AxisLayout* setAxis(Axis axis);
|
||||
/**
|
||||
* Sets where to align the target node's children on the main axis (X-axis
|
||||
* for Row, Y-axis for Column)
|
||||
*/
|
||||
AxisLayout* setAxisAlignment(AxisAlignment align);
|
||||
/**
|
||||
* Sets where to align the target node's children on the cross-axis (Y-axis
|
||||
* for Row, X-axis for Column)
|
||||
*/
|
||||
AxisLayout* setCrossAxisAlignment(AxisAlignment align);
|
||||
/**
|
||||
* Sets where to align the target node's children on the cross-axis for
|
||||
* each row (Y-axis for Row, X-axis for Column)
|
||||
*/
|
||||
AxisLayout* setCrossAxisLineAlignment(AxisAlignment align);
|
||||
/**
|
||||
* The spacing between the children of the node this layout applies to.
|
||||
* Measured as the space between their edges, not centres. Does not apply
|
||||
* on the main / cross axis if their alignment is AxisAlignment::Even
|
||||
*/
|
||||
AxisLayout* setGap(float gap);
|
||||
/**
|
||||
* Whether to reverse the direction of the children in this layout or not
|
||||
*/
|
||||
AxisLayout* setAxisReverse(bool reverse);
|
||||
/**
|
||||
* Whether to reverse the direction of the rows on the cross-axis or not
|
||||
*/
|
||||
AxisLayout* setCrossAxisReverse(bool reverse);
|
||||
/**
|
||||
* If enabled, then the layout may scale the target's children if they are
|
||||
* about to overflow. Assumes that all the childrens' intended scale is 1
|
||||
*/
|
||||
AxisLayout* setAutoScale(bool enable);
|
||||
/**
|
||||
* If true, if the main axis overflows extra nodes will be placed on new
|
||||
* rows/columns on the cross-axis
|
||||
*/
|
||||
AxisLayout* setGrowCrossAxis(bool expand);
|
||||
/**
|
||||
* If true, the cross-axis content size of the target node will be
|
||||
* automatically adjusted to fit the children
|
||||
*/
|
||||
AxisLayout* setCrossAxisOverflow(bool allow);
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple layout for arranging nodes in a row (horizontal line)
|
||||
*/
|
||||
class GEODE_DLL RowLayout : public Layout {
|
||||
class GEODE_DLL RowLayout : public AxisLayout {
|
||||
protected:
|
||||
Alignment m_alignment = Alignment::Center;
|
||||
std::optional<float> m_alignVertically;
|
||||
float m_gap;
|
||||
RowLayout();
|
||||
|
||||
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
|
||||
* manage the memory yourself. See the chainable setters on RowLayout for
|
||||
* what options you can customize for the layout
|
||||
* @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);
|
||||
static RowLayout* create();
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple layout for arranging nodes in a column (vertical line)
|
||||
*/
|
||||
class GEODE_DLL ColumnLayout : public Layout {
|
||||
class GEODE_DLL ColumnLayout : public AxisLayout {
|
||||
protected:
|
||||
Alignment m_alignment = Alignment::Center;
|
||||
std::optional<float> m_alignHorizontally;
|
||||
float m_gap;
|
||||
ColumnLayout();
|
||||
|
||||
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);
|
||||
/**
|
||||
* Create a new ColumnLayout. Note that this class is not automatically
|
||||
* managed by default, so you must assign it to a CCNode or manually
|
||||
* manage the memory yourself. See the chainable setters on RowLayout for
|
||||
* what options you can customize for the layout
|
||||
* @returns Created ColumnLayout
|
||||
*/
|
||||
static ColumnLayout* create();
|
||||
};
|
||||
|
||||
NS_CC_END
|
||||
|
|
19
loader/include/Geode/cocos/cocoa/CCArray.h
vendored
19
loader/include/Geode/cocos/cocoa/CCArray.h
vendored
|
@ -234,13 +234,11 @@ public:
|
|||
void fastRemoveObject(CCObject* object);
|
||||
/** Fast way to remove an element with a certain index */
|
||||
void fastRemoveObjectAtIndex(unsigned int index);
|
||||
|
||||
RT_ADD(
|
||||
/**
|
||||
* Rob modification
|
||||
* Fast way to remove an element with a certain index */
|
||||
void fastRemoveObjectAtIndexNew(unsigned int index);
|
||||
);
|
||||
/**
|
||||
* Fast way to remove an element with a certain index
|
||||
* @note RobTop addition
|
||||
*/
|
||||
void fastRemoveObjectAtIndexNew(unsigned int index);
|
||||
|
||||
// Rearranging Content
|
||||
|
||||
|
@ -263,6 +261,13 @@ public:
|
|||
*/
|
||||
virtual CCObject* copyWithZone(CCZone* pZone);
|
||||
|
||||
/**
|
||||
* Creates a shallow copy of this array, aka only clones the pointers to
|
||||
* the array members and not the members themselves
|
||||
* @returns New array with same members
|
||||
*/
|
||||
GEODE_DLL CCArray* shallowCopy();
|
||||
|
||||
/* override functions */
|
||||
virtual void acceptVisitor(CCDataVisitor &visitor);
|
||||
|
||||
|
|
|
@ -360,6 +360,13 @@ public:
|
|||
inline bool equals(const CCSize& target) const {
|
||||
return (fabs(this->width - target.width) < FLT_EPSILON) && (fabs(this->height - target.height) < FLT_EPSILON);
|
||||
}
|
||||
/**
|
||||
* Get the aspect ratio of this CCSize
|
||||
* @note Geode addition
|
||||
*/
|
||||
inline float aspect() const {
|
||||
return this->width / this->height;
|
||||
}
|
||||
};
|
||||
|
||||
// alk cont
|
||||
|
|
|
@ -96,18 +96,35 @@ public:
|
|||
*/
|
||||
static CCEGLView* sharedOpenGLView();
|
||||
|
||||
/**
|
||||
* @note Geode addition
|
||||
*/
|
||||
static GEODE_DLL CCEGLView* get();
|
||||
|
||||
RT_ADD( static CCEGLView* create(const gd::string&); )
|
||||
/**
|
||||
* @note RobTop addition
|
||||
*/
|
||||
static CCEGLView* create(const gd::string&);
|
||||
|
||||
RT_ADD(
|
||||
//actually this is my function but i dont wanna make a new macro for it
|
||||
inline CCPoint getMousePosition() { return { m_fMouseX, m_fMouseY }; }
|
||||
/**
|
||||
* @note Geode addition
|
||||
*/
|
||||
inline CCPoint getMousePosition() { return { m_fMouseX, m_fMouseY }; }
|
||||
|
||||
void toggleFullScreen(bool fullscreen);
|
||||
/**
|
||||
* @note RobTop addition
|
||||
*/
|
||||
void toggleFullScreen(bool fullscreen);
|
||||
|
||||
GLFWwindow* getWindow(void) const;
|
||||
)
|
||||
/**
|
||||
* @note RobTop addition
|
||||
*/
|
||||
GLFWwindow* getWindow(void) const;
|
||||
|
||||
/**
|
||||
* @note RobTop addition
|
||||
*/
|
||||
CCSize getDisplaySize();
|
||||
|
||||
protected:
|
||||
static CCEGLView* s_pEglView;
|
||||
|
|
|
@ -58,6 +58,44 @@ namespace geode {
|
|||
return buf.str();
|
||||
}
|
||||
|
||||
// todo: maybe add a debugParse function for these?
|
||||
|
||||
template <class T>
|
||||
requires requires(T t) {
|
||||
parse(t);
|
||||
}
|
||||
std::string parse(std::optional<T> const& thing) {
|
||||
if (thing.has_value()) {
|
||||
return "opt(" + parse(thing.value()) + ")";
|
||||
}
|
||||
return "nullopt";
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
requires requires(A a, B b) {
|
||||
parse(a);
|
||||
parse(b);
|
||||
}
|
||||
std::string parse(std::pair<A, B> const& thing) {
|
||||
return "(" + parse(thing.first) + ", " + parse(thing.second) + ")";
|
||||
}
|
||||
|
||||
template <class... T, std::size_t... Is>
|
||||
std::string parseTupleImpl(std::tuple<T...> const& tuple, std::index_sequence<Is...>) {
|
||||
std::string ret = "(";
|
||||
((ret += (Is == 0 ? "" : ", ") + parse(std::get<Is>(tuple))), ...);
|
||||
ret += ")";
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class... T>
|
||||
requires requires(T... t) {
|
||||
(parse(t), ...);
|
||||
}
|
||||
std::string parse(std::tuple<T...> const& tuple) {
|
||||
return parseTupleImpl(tuple, std::index_sequence_for<T...> {});
|
||||
}
|
||||
|
||||
// Log component system
|
||||
|
||||
struct GEODE_DLL ComponentTrait {
|
||||
|
|
|
@ -75,6 +75,10 @@ namespace geode::cast {
|
|||
std::is_polymorphic_v<std::remove_pointer_t<Before>>, "Input is not a polymorphic type"
|
||||
);
|
||||
|
||||
if (!ptr) {
|
||||
return After();
|
||||
}
|
||||
|
||||
auto basePtr = dynamic_cast<void*>(ptr);
|
||||
auto vftable = *reinterpret_cast<VftableType**>(basePtr);
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include <cocos2d.h>
|
||||
|
||||
#pragma warning(disable: 4275)
|
||||
|
||||
namespace geode {
|
||||
enum class CircleBaseSize {
|
||||
Tiny = 0, // Equivalent to the tiny delete button
|
||||
|
|
|
@ -77,7 +77,7 @@ namespace geode {
|
|||
struct JsonMaybeObject;
|
||||
struct JsonMaybeValue;
|
||||
|
||||
struct JsonMaybeSomething {
|
||||
struct GEODE_DLL JsonMaybeSomething {
|
||||
protected:
|
||||
JsonChecker& m_checker;
|
||||
json::Value& m_json;
|
||||
|
@ -87,29 +87,29 @@ namespace geode {
|
|||
friend struct JsonMaybeObject;
|
||||
friend struct JsonMaybeValue;
|
||||
|
||||
GEODE_DLL void setError(std::string const& error);
|
||||
void setError(std::string const& error);
|
||||
|
||||
public:
|
||||
GEODE_DLL json::Value& json();
|
||||
json::Value& json();
|
||||
|
||||
GEODE_DLL JsonMaybeSomething(
|
||||
JsonMaybeSomething(
|
||||
JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
|
||||
);
|
||||
|
||||
GEODE_DLL bool isError() const;
|
||||
GEODE_DLL std::string getError() const;
|
||||
bool isError() const;
|
||||
std::string getError() const;
|
||||
|
||||
GEODE_DLL operator bool() const;
|
||||
operator bool() const;
|
||||
};
|
||||
|
||||
struct JsonMaybeValue : public JsonMaybeSomething {
|
||||
struct GEODE_DLL JsonMaybeValue : public JsonMaybeSomething {
|
||||
bool m_inferType = true;
|
||||
|
||||
GEODE_DLL JsonMaybeValue(
|
||||
JsonMaybeValue(
|
||||
JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
|
||||
);
|
||||
|
||||
GEODE_DLL JsonMaybeSomething& self();
|
||||
JsonMaybeSomething& self();
|
||||
|
||||
template <json::Type T>
|
||||
JsonMaybeValue& as() {
|
||||
|
@ -124,7 +124,7 @@ namespace geode {
|
|||
return *this;
|
||||
}
|
||||
|
||||
GEODE_DLL JsonMaybeValue& array();
|
||||
JsonMaybeValue& array();
|
||||
|
||||
template <json::Type... T>
|
||||
JsonMaybeValue& asOneOf() {
|
||||
|
@ -231,7 +231,7 @@ namespace geode {
|
|||
return T();
|
||||
}
|
||||
|
||||
GEODE_DLL JsonMaybeObject obj();
|
||||
JsonMaybeObject obj();
|
||||
|
||||
template <class T>
|
||||
struct Iterator {
|
||||
|
@ -257,46 +257,46 @@ namespace geode {
|
|||
}
|
||||
};
|
||||
|
||||
GEODE_DLL JsonMaybeValue at(size_t i);
|
||||
JsonMaybeValue at(size_t i);
|
||||
|
||||
GEODE_DLL Iterator<JsonMaybeValue> iterate();
|
||||
Iterator<JsonMaybeValue> iterate();
|
||||
|
||||
GEODE_DLL Iterator<std::pair<std::string, JsonMaybeValue>> items();
|
||||
Iterator<std::pair<std::string, JsonMaybeValue>> items();
|
||||
};
|
||||
|
||||
struct JsonMaybeObject : JsonMaybeSomething {
|
||||
struct GEODE_DLL JsonMaybeObject : JsonMaybeSomething {
|
||||
std::set<std::string> m_knownKeys;
|
||||
|
||||
GEODE_DLL JsonMaybeObject(
|
||||
JsonMaybeObject(
|
||||
JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
|
||||
);
|
||||
|
||||
GEODE_DLL JsonMaybeSomething& self();
|
||||
JsonMaybeSomething& self();
|
||||
|
||||
GEODE_DLL void addKnownKey(std::string const& key);
|
||||
void addKnownKey(std::string const& key);
|
||||
|
||||
GEODE_DLL json::Value& json();
|
||||
json::Value& json();
|
||||
|
||||
GEODE_DLL JsonMaybeValue emptyValue();
|
||||
JsonMaybeValue emptyValue();
|
||||
|
||||
GEODE_DLL JsonMaybeValue has(std::string const& key);
|
||||
JsonMaybeValue has(std::string const& key);
|
||||
|
||||
GEODE_DLL JsonMaybeValue needs(std::string const& key);
|
||||
JsonMaybeValue needs(std::string const& key);
|
||||
|
||||
GEODE_DLL void checkUnknownKeys();
|
||||
void checkUnknownKeys();
|
||||
};
|
||||
|
||||
struct JsonChecker {
|
||||
struct GEODE_DLL JsonChecker {
|
||||
std::variant<std::monostate, std::string> m_result;
|
||||
json::Value& m_json;
|
||||
|
||||
GEODE_DLL JsonChecker(json::Value& json);
|
||||
JsonChecker(json::Value& json);
|
||||
|
||||
GEODE_DLL bool isError() const;
|
||||
bool isError() const;
|
||||
|
||||
GEODE_DLL std::string getError() const;
|
||||
std::string getError() const;
|
||||
|
||||
GEODE_DLL JsonMaybeValue root(std::string const& hierarchy);
|
||||
JsonMaybeValue root(std::string const& hierarchy);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -14,24 +14,73 @@ namespace geode {
|
|||
};
|
||||
|
||||
/**
|
||||
* A version label, like v1.0.0-alpha or v2.3.4-prerelease. Purely semantic,
|
||||
* and not used in comparisons; so for example v1.0.0-alpha == v1.0.0.
|
||||
* A version label, like v1.0.0-alpha or v2.3.4-prerelease. Limited to these
|
||||
* options; arbitary identifiers are not supported. Additional numbering
|
||||
* may be added after the identifier, such as v1.0.0-beta.1
|
||||
*/
|
||||
enum class VersionTag {
|
||||
Alpha,
|
||||
Beta,
|
||||
Prerelease,
|
||||
struct VersionTag {
|
||||
enum {
|
||||
Alpha,
|
||||
Beta,
|
||||
Prerelease,
|
||||
} value;
|
||||
std::optional<size_t> number;
|
||||
|
||||
using Type = decltype(value);
|
||||
|
||||
constexpr VersionTag(Type const& value) : value(value) {}
|
||||
constexpr VersionTag(Type const& value, std::optional<size_t> number)
|
||||
: value(value), number(number) {}
|
||||
|
||||
constexpr bool operator==(VersionTag const& other) const {
|
||||
return value == other.value && number == other.number;
|
||||
}
|
||||
constexpr bool operator<(VersionTag const& other) const {
|
||||
if (value == other.value) {
|
||||
if (number && other.number) return number < other.number;
|
||||
if (number) return true;
|
||||
if (other.number) return false;
|
||||
return false;
|
||||
}
|
||||
return value < other.value;
|
||||
}
|
||||
constexpr bool operator<=(VersionTag const& other) const {
|
||||
if (value == other.value) {
|
||||
if (number && other.number) return number <= other.number;
|
||||
if (number) return true;
|
||||
if (other.number) return false;
|
||||
return true;
|
||||
}
|
||||
return value <= other.value;
|
||||
}
|
||||
constexpr bool operator>(VersionTag const& other) const {
|
||||
if (value == other.value) {
|
||||
if (number && other.number) return number > other.number;
|
||||
if (number) return true;
|
||||
if (other.number) return false;
|
||||
return false;
|
||||
}
|
||||
return value > other.value;
|
||||
}
|
||||
constexpr bool operator>=(VersionTag const& other) const {
|
||||
if (value == other.value) {
|
||||
if (number && other.number) return number >= other.number;
|
||||
if (number) return true;
|
||||
if (other.number) return false;
|
||||
return true;
|
||||
}
|
||||
return value >= other.value;
|
||||
}
|
||||
|
||||
static Result<VersionTag> parse(std::stringstream& str);
|
||||
std::string toSuffixString() const;
|
||||
std::string toString() const;
|
||||
};
|
||||
GEODE_DLL std::optional<VersionTag> versionTagFromString(std::string const& str);
|
||||
GEODE_DLL std::string versionTagToSuffixString(VersionTag tag);
|
||||
GEODE_DLL std::string versionTagToString(VersionTag tag);
|
||||
|
||||
/**
|
||||
* Class representing version information. Not strictly semver, notably in
|
||||
* regard to identifiers; identifiers are restricted to a few common ones,
|
||||
* and are purely semantic, i.e. not used in comparisons. See VersionTag
|
||||
* for details
|
||||
* @class VersionInfo
|
||||
* Class representing version information. Uses a limited subset of SemVer;
|
||||
* identifiers are restricted to a few predefined ones, and only one
|
||||
* identifier is allowed. See VersionTag for details
|
||||
*/
|
||||
class GEODE_DLL VersionInfo final {
|
||||
protected:
|
||||
|
@ -78,24 +127,24 @@ namespace geode {
|
|||
// Apple clang does not support operator<=>! Yippee!
|
||||
|
||||
constexpr bool operator==(VersionInfo const& other) const {
|
||||
return std::tie(m_major, m_minor, m_patch) ==
|
||||
std::tie(other.m_major, other.m_minor, other.m_patch);
|
||||
return std::tie(m_major, m_minor, m_patch, m_tag) ==
|
||||
std::tie(other.m_major, other.m_minor, other.m_patch, other.m_tag);
|
||||
}
|
||||
constexpr bool operator<(VersionInfo const& other) const {
|
||||
return std::tie(m_major, m_minor, m_patch) <
|
||||
std::tie(other.m_major, other.m_minor, other.m_patch);
|
||||
return std::tie(m_major, m_minor, m_patch, m_tag) <
|
||||
std::tie(other.m_major, other.m_minor, other.m_patch, other.m_tag);
|
||||
}
|
||||
constexpr bool operator<=(VersionInfo const& other) const {
|
||||
return std::tie(m_major, m_minor, m_patch) <=
|
||||
std::tie(other.m_major, other.m_minor, other.m_patch);
|
||||
return std::tie(m_major, m_minor, m_patch, m_tag) <=
|
||||
std::tie(other.m_major, other.m_minor, other.m_patch, other.m_tag);
|
||||
}
|
||||
constexpr bool operator>(VersionInfo const& other) const {
|
||||
return std::tie(m_major, m_minor, m_patch) >
|
||||
std::tie(other.m_major, other.m_minor, other.m_patch);
|
||||
return std::tie(m_major, m_minor, m_patch, m_tag) >
|
||||
std::tie(other.m_major, other.m_minor, other.m_patch, other.m_tag);
|
||||
}
|
||||
constexpr bool operator>=(VersionInfo const& other) const {
|
||||
return std::tie(m_major, m_minor, m_patch) >=
|
||||
std::tie(other.m_major, other.m_minor, other.m_patch);
|
||||
return std::tie(m_major, m_minor, m_patch, m_tag) >=
|
||||
std::tie(other.m_major, other.m_minor, other.m_patch, other.m_tag);
|
||||
}
|
||||
|
||||
std::string toString(bool includeTag = true) const;
|
||||
|
|
|
@ -410,16 +410,31 @@ namespace geode::cocos {
|
|||
* or nullptr if index exceeds bounds
|
||||
*/
|
||||
template <class Type = cocos2d::CCNode>
|
||||
static Type* getChildOfType(cocos2d::CCNode* node, size_t index) {
|
||||
static Type* getChildOfType(cocos2d::CCNode* node, int index) {
|
||||
size_t indexCounter = 0;
|
||||
|
||||
for (size_t i = 0; i < node->getChildrenCount(); ++i) {
|
||||
auto obj = cast::typeinfo_cast<Type*>(node->getChildren()->objectAtIndex(i));
|
||||
if (obj != nullptr) {
|
||||
if (indexCounter == index) {
|
||||
return obj;
|
||||
// start from end for negative index
|
||||
if (index < 0) {
|
||||
index = -index - 1;
|
||||
for (size_t i = node->getChildrenCount() - 1; i >= 0; i--) {
|
||||
auto obj = cast::typeinfo_cast<Type*>(node->getChildren()->objectAtIndex(i));
|
||||
if (obj != nullptr) {
|
||||
if (indexCounter == index) {
|
||||
return obj;
|
||||
}
|
||||
++indexCounter;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (size_t i = 0; i < node->getChildrenCount(); i++) {
|
||||
auto obj = cast::typeinfo_cast<Type*>(node->getChildren()->objectAtIndex(i));
|
||||
if (obj != nullptr) {
|
||||
if (indexCounter == index) {
|
||||
return obj;
|
||||
}
|
||||
++indexCounter;
|
||||
}
|
||||
++indexCounter;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -548,86 +563,6 @@ namespace geode::cocos {
|
|||
*/
|
||||
GEODE_DLL bool fileExistsInSearchPaths(char const* filename);
|
||||
|
||||
template <typename T>
|
||||
struct CCArrayIterator {
|
||||
public:
|
||||
CCArrayIterator(T* p) : m_ptr(p) {}
|
||||
|
||||
T* m_ptr;
|
||||
|
||||
auto& operator*() {
|
||||
return *m_ptr;
|
||||
}
|
||||
|
||||
auto& operator*() const {
|
||||
return *m_ptr;
|
||||
}
|
||||
|
||||
auto operator->() {
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
auto operator->() const {
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
auto& operator++() {
|
||||
++m_ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto& operator--() {
|
||||
--m_ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto& operator+=(size_t val) {
|
||||
m_ptr += val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto& operator-=(size_t val) {
|
||||
m_ptr -= val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator+(size_t val) const {
|
||||
return CCArrayIterator<T>(m_ptr + val);
|
||||
}
|
||||
|
||||
auto operator-(size_t val) const {
|
||||
return CCArrayIterator<T>(m_ptr - val);
|
||||
}
|
||||
|
||||
auto operator-(CCArrayIterator<T> const& other) const {
|
||||
return m_ptr - other.m_ptr;
|
||||
}
|
||||
|
||||
bool operator<(CCArrayIterator<T> const& other) const {
|
||||
return m_ptr < other.m_ptr;
|
||||
}
|
||||
|
||||
bool operator>(CCArrayIterator<T> const& other) const {
|
||||
return m_ptr > other.m_ptr;
|
||||
}
|
||||
|
||||
bool operator<=(CCArrayIterator<T> const& other) const {
|
||||
return m_ptr <= other.m_ptr;
|
||||
}
|
||||
|
||||
bool operator>=(CCArrayIterator<T> const& other) const {
|
||||
return m_ptr >= other.m_ptr;
|
||||
}
|
||||
|
||||
bool operator==(CCArrayIterator<T> const& other) const {
|
||||
return m_ptr == other.m_ptr;
|
||||
}
|
||||
|
||||
bool operator!=(CCArrayIterator<T> const& other) const {
|
||||
return m_ptr != other.m_ptr;
|
||||
}
|
||||
};
|
||||
|
||||
inline void ccDrawColor4B(cocos2d::ccColor4B const& color) {
|
||||
cocos2d::ccDrawColor4B(color.r, color.g, color.b, color.a);
|
||||
}
|
||||
|
@ -766,16 +701,6 @@ namespace std {
|
|||
return std::hash<T*>()(ref.data());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct iterator_traits<geode::cocos::CCArrayIterator<T>> {
|
||||
using difference_type = ptrdiff_t;
|
||||
using value_type = T;
|
||||
using pointer = T*;
|
||||
using reference = T&;
|
||||
using iterator_category =
|
||||
std::random_access_iterator_tag; // its random access but im too lazy to implement it
|
||||
};
|
||||
}
|
||||
|
||||
// more utils
|
||||
|
@ -807,9 +732,14 @@ namespace geode::cocos {
|
|||
using T = std::remove_pointer_t<_Type>;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using iterator = T**;
|
||||
using const_iterator = const T**;
|
||||
|
||||
CCArrayExt() : m_arr(cocos2d::CCArray::create()) {}
|
||||
|
||||
CCArrayExt(cocos2d::CCArray* arr) : m_arr(arr) {}
|
||||
CCArrayExt(cocos2d::CCArray* arr)
|
||||
: m_arr(arr) {}
|
||||
|
||||
CCArrayExt(CCArrayExt const& a) : m_arr(a.m_arr) {}
|
||||
|
||||
|
@ -819,18 +749,26 @@ namespace geode::cocos {
|
|||
|
||||
~CCArrayExt() {}
|
||||
|
||||
auto begin() {
|
||||
T** begin() const {
|
||||
if (!m_arr) {
|
||||
return CCArrayIterator<T*>(nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
return CCArrayIterator<T*>(reinterpret_cast<T**>(m_arr->data->arr));
|
||||
return reinterpret_cast<T**>(m_arr->data->arr);
|
||||
}
|
||||
|
||||
auto end() {
|
||||
T** end() const {
|
||||
if (!m_arr) {
|
||||
return CCArrayIterator<T*>(nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
return CCArrayIterator<T*>(reinterpret_cast<T**>(m_arr->data->arr) + m_arr->count());
|
||||
return reinterpret_cast<T**>(m_arr->data->arr) + m_arr->count();
|
||||
}
|
||||
|
||||
auto rbegin() const {
|
||||
return std::reverse_iterator(this->end());
|
||||
}
|
||||
|
||||
auto rend() const {
|
||||
return std::reverse_iterator(this->begin());
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
|
|
|
@ -289,23 +289,21 @@ namespace geode::utils::ranges {
|
|||
return member(*it);
|
||||
}
|
||||
|
||||
template <ValidConstContainer C>
|
||||
struct ConstReverseWrapper {
|
||||
C const& iter;
|
||||
template <class C>
|
||||
struct ReverseWrapper {
|
||||
C iter;
|
||||
|
||||
decltype(auto) begin() {
|
||||
return std::rbegin(iter);
|
||||
}
|
||||
|
||||
decltype(auto) end() {
|
||||
return std::rend(iter);
|
||||
}
|
||||
};
|
||||
|
||||
template <ValidConstContainer C>
|
||||
auto begin(ConstReverseWrapper<C> const& c) {
|
||||
return std::rbegin(c.iter);
|
||||
}
|
||||
|
||||
template <ValidConstContainer C>
|
||||
auto end(ConstReverseWrapper<C> const& c) {
|
||||
return std::rend(c.iter);
|
||||
}
|
||||
|
||||
template <ValidConstContainer C>
|
||||
ConstReverseWrapper<C> reverse(C const& iter) {
|
||||
return { iter };
|
||||
template <class C>
|
||||
auto reverse(C&& iter) {
|
||||
return ReverseWrapper<C>{std::forward<C>(iter)};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"geode": "@PROJECT_VERSION@",
|
||||
"geode": "@PROJECT_VERSION@@PROJECT_VERSION_SUFFIX@",
|
||||
"id": "geode.loader",
|
||||
"version": "@PROJECT_VERSION@@PROJECT_VERSION_SUFFIX@",
|
||||
"name": "Geode",
|
||||
|
|
|
@ -16,4 +16,10 @@ void CCArray::removeFirstObject(bool bReleaseObj) {
|
|||
this->removeObjectAtIndex(0, bReleaseObj);
|
||||
}
|
||||
|
||||
CCArray* CCArray::shallowCopy() {
|
||||
auto r = CCArray::createWithCapacity(this->capacity());
|
||||
r->addObjectsFromArray(this);
|
||||
return r;
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -20,7 +20,7 @@ private:
|
|||
Ref<cocos2d::CCObject> m_userObject;
|
||||
std::string m_id = "";
|
||||
std::unique_ptr<Layout> m_layout = nullptr;
|
||||
PositionHint m_positionHint = PositionHint::Default;
|
||||
std::unique_ptr<LayoutOptions> m_layoutOptions = nullptr;
|
||||
std::unordered_map<std::string, std::any> m_attributes;
|
||||
|
||||
friend class ProxyCCNode;
|
||||
|
@ -118,7 +118,13 @@ CCNode* CCNode::getChildByIDRecursive(std::string const& id) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void CCNode::setLayout(Layout* layout, bool apply) {
|
||||
void CCNode::setLayout(Layout* layout, bool apply, bool respectAnchor) {
|
||||
if (respectAnchor && this->isIgnoreAnchorPointForPosition()) {
|
||||
for (auto child : CCArrayExt<CCNode>(m_pChildren)) {
|
||||
child->setPosition(child->getPosition() + this->getScaledContentSize());
|
||||
}
|
||||
this->ignoreAnchorPointForPosition(false);
|
||||
}
|
||||
GeodeNodeMetadata::set(this)->m_layout.reset(layout);
|
||||
if (apply) {
|
||||
this->updateLayout();
|
||||
|
@ -129,26 +135,24 @@ 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::create();
|
||||
for (auto& child : CCArrayExt<CCNode>(m_pChildren)) {
|
||||
if (child->getPositionHint() != PositionHint::Absolute) {
|
||||
filtered->addObject(child);
|
||||
}
|
||||
}
|
||||
layout->apply(filtered, m_obContentSize);
|
||||
filtered->release();
|
||||
void CCNode::setLayoutOptions(LayoutOptions* options, bool apply) {
|
||||
GeodeNodeMetadata::set(this)->m_layoutOptions.reset(options);
|
||||
if (apply && m_pParent) {
|
||||
m_pParent->updateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
void CCNode::setPositionHint(PositionHint hint) {
|
||||
GeodeNodeMetadata::set(this)->m_positionHint = hint;
|
||||
LayoutOptions* CCNode::getLayoutOptions() {
|
||||
return GeodeNodeMetadata::set(this)->m_layoutOptions.get();
|
||||
}
|
||||
|
||||
PositionHint CCNode::getPositionHint() {
|
||||
return GeodeNodeMetadata::set(this)->m_positionHint;
|
||||
void CCNode::updateLayout(bool updateChildOrder) {
|
||||
if (updateChildOrder) {
|
||||
this->sortAllChildren();
|
||||
}
|
||||
if (auto layout = GeodeNodeMetadata::set(this)->m_layout.get()) {
|
||||
layout->apply(this);
|
||||
}
|
||||
}
|
||||
|
||||
void CCNode::setAttribute(std::string const& attr, std::any value) {
|
||||
|
|
|
@ -33,10 +33,13 @@ void setIDs(CCNode* node, int startIndex, Args... args) {
|
|||
}
|
||||
|
||||
static void switchToMenu(CCNode* node, CCMenu* menu) {
|
||||
if (!node || !menu) return;
|
||||
|
||||
auto worldPos = node->getParent()->convertToWorldSpace(node->getPosition());
|
||||
|
||||
node->retain();
|
||||
node->removeFromParent();
|
||||
node->setZOrder(0);
|
||||
|
||||
menu->addChild(node);
|
||||
node->setPosition(menu->convertToNodeSpace(worldPos));
|
||||
|
@ -55,6 +58,14 @@ static void switchChildrenToMenu(CCNode* parent, CCMenu* menu, Args... args) {
|
|||
|
||||
template <typename T, typename ...Args>
|
||||
static CCMenu* detachAndCreateMenu(CCNode* parent, const char* menuID, Layout* layout, T first, Args... args) {
|
||||
if (!first) {
|
||||
auto menu = CCMenu::create();
|
||||
menu->setID(menuID);
|
||||
menu->setLayout(layout);
|
||||
parent->addChild(menu);
|
||||
return menu;
|
||||
}
|
||||
|
||||
auto oldMenu = first->getParent();
|
||||
|
||||
first->retain();
|
||||
|
@ -64,14 +75,25 @@ static CCMenu* detachAndCreateMenu(CCNode* parent, const char* menuID, Layout* l
|
|||
newMenu->setPosition(parent->convertToNodeSpace(oldMenu->convertToWorldSpace(first->getPosition())));
|
||||
newMenu->setID(menuID);
|
||||
newMenu->setZOrder(oldMenu->getZOrder());
|
||||
newMenu->setLayout(layout);
|
||||
parent->addChild(newMenu);
|
||||
|
||||
first->setPosition(0, 0);
|
||||
first->setZOrder(0);
|
||||
newMenu->addChild(first);
|
||||
first->release();
|
||||
|
||||
(switchToMenu(args, newMenu), ...);
|
||||
|
||||
newMenu->setLayout(layout);
|
||||
|
||||
return newMenu;
|
||||
}
|
||||
|
||||
static CCSize getSizeSafe(CCNode* node) {
|
||||
if (node) {
|
||||
return node->getScaledContentSize();
|
||||
}
|
||||
else {
|
||||
return CCSizeZero;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,49 +6,118 @@
|
|||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
template<class... Args>
|
||||
static void reorderButtons(Args... args) {
|
||||
int ooa = 0;
|
||||
for (auto& arg : { args... }) {
|
||||
if (arg) {
|
||||
arg->setOrderOfArrival(ooa);
|
||||
ooa += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$register_ids(CreatorLayer) {
|
||||
setIDSafe<CCSprite>(this, 0, "background");
|
||||
|
||||
auto winSize = CCDirector::get()->getWinSize();
|
||||
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 0)) {
|
||||
menu->setID("creator-buttons-menu");
|
||||
|
||||
setIDSafe(menu, 0, "create-button");
|
||||
setIDSafe(menu, 1, "saved-button");
|
||||
setIDSafe(menu, 2, "scores-button");
|
||||
setIDSafe(menu, 3, "quests-button");
|
||||
setIDSafe(menu, 4, "daily-button");
|
||||
setIDSafe(menu, 5, "weekly-button");
|
||||
setIDSafe(menu, 6, "featured-button");
|
||||
setIDSafe(menu, 7, "hall-of-fame-button");
|
||||
setIDSafe(menu, 8, "map-packs-button");
|
||||
setIDSafe(menu, 9, "search-button");
|
||||
setIDSafe(menu, 10, "gauntlets-button");
|
||||
|
||||
// move vault button to its own menu
|
||||
if (auto lockBtn = setIDSafe(menu, -2, "vault-button")) {
|
||||
detachAndCreateMenu(
|
||||
auto menu = detachAndCreateMenu(
|
||||
this,
|
||||
"top-right-menu",
|
||||
ColumnLayout::create(5.f, 0.f)->setAlignment(Alignment::Begin),
|
||||
ColumnLayout::create()
|
||||
->setAxisReverse(true)
|
||||
->setAxisAlignment(AxisAlignment::End),
|
||||
lockBtn
|
||||
);
|
||||
menu->setPositionY(
|
||||
menu->getPositionY() - 150.f / 2 +
|
||||
lockBtn->getScaledContentSize().height / 2
|
||||
);
|
||||
menu->setContentSize({ 60.f, 150.f });
|
||||
menu->updateLayout();
|
||||
}
|
||||
|
||||
// move treasure room button to its own menu
|
||||
if (auto roomBtn = setIDSafe(menu, -1, "treasure-room-button")) {
|
||||
detachAndCreateMenu(
|
||||
auto menu = detachAndCreateMenu(
|
||||
this,
|
||||
"bottom-right-menu",
|
||||
ColumnLayout::create(5.f, 0.f)->setAlignment(Alignment::End),
|
||||
ColumnLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start),
|
||||
roomBtn
|
||||
);
|
||||
menu->setPositionY(
|
||||
menu->getPositionY() + 125.f / 2 -
|
||||
roomBtn->getScaledContentSize().height / 2
|
||||
);
|
||||
menu->setContentSize({ 60.f, 125.f });
|
||||
menu->updateLayout();
|
||||
}
|
||||
|
||||
// row order is inverted because of layout
|
||||
|
||||
reorderButtons(
|
||||
setIDSafe(menu, 6, "featured-button"),
|
||||
setIDSafe(menu, 7, "hall-of-fame-button"),
|
||||
setIDSafe(menu, 8, "map-packs-button"),
|
||||
|
||||
setIDSafe(menu, 9, "search-button"),
|
||||
setIDSafe(menu, 3, "quests-button"),
|
||||
setIDSafe(menu, 4, "daily-button"),
|
||||
setIDSafe(menu, 5, "weekly-button"),
|
||||
|
||||
setIDSafe(menu, 10, "gauntlets-button"),
|
||||
setIDSafe(menu, 0, "create-button"),
|
||||
setIDSafe(menu, 1, "saved-button"),
|
||||
setIDSafe(menu, 2, "scores-button")
|
||||
);
|
||||
|
||||
if (winSize.width / winSize.height <= 5.1f / 3.f) {
|
||||
menu->setContentSize({ winSize.width - 80.f, 310.f });
|
||||
}
|
||||
else {
|
||||
menu->setContentSize({ winSize.width - 120.f, 310.f });
|
||||
}
|
||||
menu->setLayout(
|
||||
RowLayout::create()
|
||||
->setGap(12.f)
|
||||
->setCrossAxisReverse(true)
|
||||
->setGrowCrossAxis(true)
|
||||
->setCrossAxisOverflow(false)
|
||||
);
|
||||
}
|
||||
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 1)) {
|
||||
menu->setID("exit-menu");
|
||||
setIDSafe(menu, 0, "exit-button");
|
||||
auto exitBtn = setIDSafe(menu, 0, "exit-button");
|
||||
menu->setPositionY(
|
||||
menu->getPositionY() - 125.f / 2 +
|
||||
getSizeSafe(exitBtn).height / 2
|
||||
);
|
||||
menu->setContentSize({ 60.f, 125.f });
|
||||
menu->setLayout(
|
||||
ColumnLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::End)
|
||||
);
|
||||
}
|
||||
|
||||
// add a menu to the bottom left corner that is empty but prolly a place mods
|
||||
// want to add stuff to
|
||||
auto menu = CCMenu::create();
|
||||
menu->setPosition(24.f, 0.f + 125.f / 2);
|
||||
menu->setID("bottom-left-menu");
|
||||
menu->setContentSize({ 60.f, 125.f });
|
||||
menu->setLayout(
|
||||
ColumnLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
);
|
||||
this->addChild(menu);
|
||||
}
|
||||
|
||||
struct CreatorLayerIDs : Modify<CreatorLayerIDs, CreatorLayer> {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <Geode/Bindings.hpp>
|
||||
#include <Geode/modify/EditLevelLayer.hpp>
|
||||
#include <Geode/utils/cocos.hpp>
|
||||
#include <Geode/ui/BasedButtonSprite.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
|
@ -18,22 +19,26 @@ $register_ids(EditLevelLayer) {
|
|||
"description-background",
|
||||
"description-input",
|
||||
"description-text-area",
|
||||
"level-action-menu",
|
||||
"level-edit-menu",
|
||||
"level-length",
|
||||
"level-song",
|
||||
"level-verified",
|
||||
"version-label",
|
||||
"level-id-label",
|
||||
"right-side-menu",
|
||||
"back-button-menu",
|
||||
"level-actions-menu",
|
||||
"back-menu",
|
||||
"info-button-menu"
|
||||
);
|
||||
|
||||
if (auto menu = this->getChildByID("level-action-menu")) {
|
||||
auto winSize = CCDirector::get()->getWinSize();
|
||||
|
||||
if (auto menu = this->getChildByID("level-edit-menu")) {
|
||||
setIDs(menu, 0, "edit-button", "play-button", "share-button");
|
||||
menu->setContentSize({ winSize.width - 160.f, 100.f });
|
||||
menu->setLayout(RowLayout::create()->setGap(25.f));
|
||||
}
|
||||
|
||||
if (auto menu = this->getChildByID("right-side-menu")) {
|
||||
if (auto menu = this->getChildByID("level-actions-menu")) {
|
||||
setIDs(
|
||||
menu,
|
||||
0,
|
||||
|
@ -44,12 +49,42 @@ $register_ids(EditLevelLayer) {
|
|||
"folder-button"
|
||||
);
|
||||
|
||||
detachAndCreateMenu(
|
||||
menu, "folder-menu", ColumnLayout::create(), menu->getChildByID("folder-button")
|
||||
auto folderMenu = detachAndCreateMenu(
|
||||
this, "folder-menu",
|
||||
ColumnLayout::create(),
|
||||
menu->getChildByID("folder-button")
|
||||
);
|
||||
folderMenu->setContentSize({ 50.f, 215.f });
|
||||
folderMenu->updateLayout();
|
||||
|
||||
menu->setPosition(
|
||||
menu->getPositionX() + static_cast<CCNode*>(
|
||||
menu->getChildren()->firstObject()
|
||||
)->getPositionX(),
|
||||
winSize.height / 2
|
||||
);
|
||||
menu->setContentSize({ 60.f, winSize.height - 15.f });
|
||||
menu->setLayout(
|
||||
ColumnLayout::create()
|
||||
->setGap(7.f)
|
||||
->setAxisAlignment(AxisAlignment::End)
|
||||
->setAxisReverse(true)
|
||||
);
|
||||
menu->setZOrder(1);
|
||||
}
|
||||
|
||||
if (auto menu = this->getChildByID("back-button-menu")) setIDSafe(menu, 0, "back-button");
|
||||
if (auto menu = this->getChildByID("back-menu")) {
|
||||
auto backBtn = setIDSafe(menu, 0, "back-button");
|
||||
menu->setPositionX(
|
||||
menu->getPositionX() + 100.f / 2 -
|
||||
getSizeSafe(backBtn).width / 2
|
||||
);
|
||||
menu->setContentSize({ 100.f, 50.f });
|
||||
menu->setLayout(
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
);
|
||||
}
|
||||
|
||||
if (auto menu = this->getChildByID("info-button-menu")) setIDSafe(menu, 0, "info-button");
|
||||
}
|
||||
|
|
273
loader/src/ids/EditorPauseLayer.cpp
Normal file
273
loader/src/ids/EditorPauseLayer.cpp
Normal file
|
@ -0,0 +1,273 @@
|
|||
#include "AddIDs.hpp"
|
||||
|
||||
#include <Geode/modify/EditorPauseLayer.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
// special class for this because making it a CCMenuItemToggler would be very UB
|
||||
// (not gonna reinterpret_cast that into the members)
|
||||
class GuidelinesButton : public CCMenuItemSpriteExtra {
|
||||
protected:
|
||||
bool init() {
|
||||
if (!CCMenuItemSpriteExtra::init(
|
||||
CCSprite::createWithSpriteFrameName("GJ_audioOffBtn_001.png"),
|
||||
nullptr,
|
||||
this, nullptr
|
||||
)) return false;
|
||||
|
||||
this->updateSprite();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void updateSprite() {
|
||||
this->setNormalImage(CCSprite::createWithSpriteFrameName(
|
||||
GameManager::get()->m_showSongMarkers ?
|
||||
"GJ_audioOnBtn_001.png" :
|
||||
"GJ_audioOffBtn_001.png"
|
||||
));
|
||||
}
|
||||
|
||||
void activate() override {
|
||||
CCMenuItemSpriteExtra::activate();
|
||||
GameManager::get()->m_showSongMarkers ^= 1;
|
||||
this->updateSprite();
|
||||
}
|
||||
|
||||
public:
|
||||
static GuidelinesButton* create() {
|
||||
auto ret = new GuidelinesButton();
|
||||
if (ret && ret->init()) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
$register_ids(EditorPauseLayer) {
|
||||
auto winSize = CCDirector::get()->getWinSize();
|
||||
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 0)) {
|
||||
menu->setID("resume-menu");
|
||||
|
||||
setIDs(
|
||||
menu, 0,
|
||||
"resume-button",
|
||||
"save-and-play-button",
|
||||
"save-and-exit-button",
|
||||
"save-button",
|
||||
"exit-button"
|
||||
);
|
||||
|
||||
menu->setContentSize({ 100.f, 220.f });
|
||||
menu->setLayout(
|
||||
ColumnLayout::create()
|
||||
->setGap(12.5f)
|
||||
->setAxisReverse(true)
|
||||
);
|
||||
}
|
||||
|
||||
setIDs(
|
||||
this, 2,
|
||||
"ignore-damage-label",
|
||||
"follow-player-label",
|
||||
"select-filter-label",
|
||||
"show-grid-label",
|
||||
"show-object-info-label",
|
||||
"show-ground-label",
|
||||
"preview-mode-label",
|
||||
|
||||
"object-count-label",
|
||||
"length-label",
|
||||
"length-name-label"
|
||||
);
|
||||
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 1)) {
|
||||
menu->setID("bottom-menu");
|
||||
|
||||
setIDs(
|
||||
menu, 0,
|
||||
"guidelines-enable-button",
|
||||
"help-button",
|
||||
"guidelines-disable-button",
|
||||
|
||||
"uncheck-portals-button",
|
||||
"reset-unused-button",
|
||||
"create-edges-button",
|
||||
"create-outlines-button",
|
||||
"create-base-button",
|
||||
"build-helper-button",
|
||||
|
||||
"align-x-button",
|
||||
"align-y-button",
|
||||
"select-all-button",
|
||||
"select-all-left-button",
|
||||
"select-all-right-button",
|
||||
|
||||
"ignore-damage-toggle",
|
||||
"follow-player-toggle",
|
||||
"select-filter-toggle",
|
||||
"show-grid-toggle",
|
||||
"show-object-info-toggle",
|
||||
"show-ground-toggle",
|
||||
"preview-mode-toggle",
|
||||
|
||||
"keys-button",
|
||||
"settings-button"
|
||||
);
|
||||
|
||||
auto smallActionsMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"small-actions-menu",
|
||||
ColumnLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
->setAxisReverse(true),
|
||||
menu->getChildByID("align-x-button"),
|
||||
menu->getChildByID("align-y-button"),
|
||||
menu->getChildByID("select-all-button"),
|
||||
menu->getChildByID("select-all-left-button"),
|
||||
menu->getChildByID("select-all-right-button")
|
||||
);
|
||||
smallActionsMenu->setContentSize({ 100.f, 240.f });
|
||||
smallActionsMenu->setPositionY(130.f);
|
||||
smallActionsMenu->updateLayout();
|
||||
|
||||
auto actionsMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"actions-menu",
|
||||
ColumnLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
->setAxisReverse(true),
|
||||
menu->getChildByID("keys-button"),
|
||||
menu->getChildByID("build-helper-button"),
|
||||
menu->getChildByID("create-base-button"),
|
||||
menu->getChildByID("create-outlines-button"),
|
||||
menu->getChildByID("create-edges-button"),
|
||||
menu->getChildByID("reset-unused-button"),
|
||||
menu->getChildByID("uncheck-portals-button")
|
||||
);
|
||||
if (auto keysBtn = actionsMenu->getChildByID("keys-button")) {
|
||||
keysBtn->setLayoutOptions(AxisLayoutOptions::create()->setPrevGap(10.f));
|
||||
}
|
||||
actionsMenu->setContentSize({ 100.f, 240.f });
|
||||
actionsMenu->setPositionY(130.f);
|
||||
actionsMenu->updateLayout();
|
||||
|
||||
auto optionsMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"options-menu",
|
||||
RowLayout::create()
|
||||
->setGap(0.f)
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
->setGrowCrossAxis(true)
|
||||
->setCrossAxisAlignment(AxisAlignment::Start)
|
||||
->setCrossAxisOverflow(false),
|
||||
menu->getChildByID("preview-mode-toggle"),
|
||||
this->getChildByID("preview-mode-label"),
|
||||
menu->getChildByID("show-ground-toggle"),
|
||||
this->getChildByID("show-ground-label"),
|
||||
menu->getChildByID("show-object-info-toggle"),
|
||||
this->getChildByID("show-object-info-label"),
|
||||
menu->getChildByID("show-grid-toggle"),
|
||||
this->getChildByID("show-grid-label"),
|
||||
menu->getChildByID("select-filter-toggle"),
|
||||
this->getChildByID("select-filter-label"),
|
||||
menu->getChildByID("follow-player-toggle"),
|
||||
this->getChildByID("follow-player-label"),
|
||||
menu->getChildByID("ignore-damage-toggle"),
|
||||
this->getChildByID("ignore-damage-label")
|
||||
);
|
||||
for (auto node : CCArrayExt<CCNode>(optionsMenu->getChildren())) {
|
||||
if (auto label = typeinfo_cast<CCLabelBMFont*>(node)) {
|
||||
label->setLayoutOptions(
|
||||
AxisLayoutOptions::create()
|
||||
->setSameLine(true)
|
||||
->setBreakLine(true)
|
||||
->setPrevGap(5.f)
|
||||
->setMinScale(.1f)
|
||||
->setMaxScale(.5f)
|
||||
->setScalePriority(1)
|
||||
);
|
||||
}
|
||||
}
|
||||
optionsMenu->setContentSize({ 120.f, winSize.height - 100.f });
|
||||
optionsMenu->setPosition(70.f, winSize.height / 2 - 50.f + 10.f);
|
||||
optionsMenu->updateLayout();
|
||||
|
||||
auto settingsMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"settings-menu",
|
||||
RowLayout::create()
|
||||
->setAxisReverse(true),
|
||||
menu->getChildByID("settings-button")
|
||||
);
|
||||
settingsMenu->setContentSize({ 95.f, 50.f });
|
||||
settingsMenu->updateLayout();
|
||||
|
||||
auto guidelinesMenu = menu;
|
||||
|
||||
// replace the two guidelines buttons with a single toggle
|
||||
guidelinesMenu->getChildByID("guidelines-enable-button")->removeFromParent();
|
||||
guidelinesMenu->getChildByID("guidelines-disable-button")->removeFromParent();
|
||||
|
||||
auto glToggle = GuidelinesButton::create();
|
||||
glToggle->setID("guidelines-enable-toggle");
|
||||
guidelinesMenu->insertBefore(glToggle, nullptr);
|
||||
m_guidelinesOffButton = m_guidelinesOnButton = glToggle;
|
||||
this->updateSongButton();
|
||||
|
||||
guidelinesMenu->setID("guidelines-menu");
|
||||
guidelinesMenu->setContentSize({ winSize.width / 2, 50.f });
|
||||
guidelinesMenu->setLayout(RowLayout::create());
|
||||
|
||||
auto topMenu = CCMenu::create();
|
||||
topMenu->setContentSize({ winSize.width / 2, 50.f });
|
||||
topMenu->setPosition(winSize.width / 2, winSize.height - 30.f);
|
||||
topMenu->setID("top-menu");
|
||||
topMenu->setLayout(RowLayout::create());
|
||||
this->addChild(topMenu);
|
||||
}
|
||||
|
||||
if (auto menu = detachAndCreateMenu(
|
||||
this, "info-menu",
|
||||
ColumnLayout::create()
|
||||
->setGap(10.f)
|
||||
->setAxisAlignment(AxisAlignment::End)
|
||||
->setAxisReverse(true)
|
||||
->setCrossAxisOverflow(false)
|
||||
->setCrossAxisLineAlignment(AxisAlignment::Start),
|
||||
this->getChildByID("object-count-label"),
|
||||
this->getChildByID("length-label"),
|
||||
this->getChildByID("length-name-label")
|
||||
)) {
|
||||
for (auto child : CCArrayExt<CCNode>(menu->getChildren())) {
|
||||
child->setLayoutOptions(
|
||||
AxisLayoutOptions::create()
|
||||
->setMinScale(.1f)
|
||||
->setMaxScale(.6f)
|
||||
->setBreakLine(true)
|
||||
);
|
||||
}
|
||||
menu->setContentSize({ 165.f, 100.f });
|
||||
menu->setPosition(85.f, winSize.height - 55.f);
|
||||
menu->updateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
struct EditorPauseLayerIDs : Modify<EditorPauseLayerIDs, EditorPauseLayer> {
|
||||
static void onModify(auto& self) {
|
||||
if (!self.setHookPriority("EditorPauseLayer::init", GEODE_ID_PRIORITY)) {
|
||||
log::warn("Failed to set EditorPauseLayer::init hook priority, node IDs may not work properly");
|
||||
}
|
||||
}
|
||||
|
||||
bool init(LevelEditorLayer* lel) {
|
||||
if (!EditorPauseLayer::init(lel)) return false;
|
||||
|
||||
NodeIDs::get()->provide(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
|
@ -11,6 +11,8 @@ $register_ids(EditorUI) {
|
|||
setIDSafe(this, this->getChildrenCount() - 2, "layer-index-label");
|
||||
setIDSafe(this, this->getChildrenCount() - 1, "object-info-label");
|
||||
|
||||
auto winSize = CCDirector::get()->getWinSize();
|
||||
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 0)) {
|
||||
menu->setID("toolbar-categories-menu");
|
||||
|
||||
|
@ -28,7 +30,7 @@ $register_ids(EditorUI) {
|
|||
|
||||
"undo-button",
|
||||
"redo-button",
|
||||
"delete-button",
|
||||
"delete-trash-button",
|
||||
|
||||
"music-playback-button",
|
||||
|
||||
|
@ -42,51 +44,105 @@ $register_ids(EditorUI) {
|
|||
"unlink-button"
|
||||
);
|
||||
|
||||
detachAndCreateMenu(
|
||||
auto toolbarTogglesMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"toolbar-toggles-menu",
|
||||
GridLayout::create(2, GridAlignment::Begin, GridDirection::Column),
|
||||
RowLayout::create()
|
||||
->setCrossAxisOverflow(false)
|
||||
->setGrowCrossAxis(true)
|
||||
->setAxisAlignment(AxisAlignment::Center)
|
||||
->setCrossAxisAlignment(AxisAlignment::Center),
|
||||
menu->getChildByID("swipe-button"),
|
||||
menu->getChildByID("rotate-button"),
|
||||
menu->getChildByID("free-move-button"),
|
||||
menu->getChildByID("snap-button"),
|
||||
menu->getChildByID("rotate-button")
|
||||
menu->getChildByID("snap-button")
|
||||
);
|
||||
toolbarTogglesMenu->setPosition(
|
||||
winSize.width - 47.f,
|
||||
45.f
|
||||
);
|
||||
toolbarTogglesMenu->setContentSize({ 90.f, 90.f });
|
||||
toolbarTogglesMenu->updateLayout();
|
||||
|
||||
detachAndCreateMenu(
|
||||
auto undoMenuWidth = winSize.width / 2 - 90.f;
|
||||
auto undoMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"top-left-menu",
|
||||
RowLayout::create(),
|
||||
"undo-menu",
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
->setGap(10.f),
|
||||
menu->getChildByID("undo-button"),
|
||||
menu->getChildByID("redo-button"),
|
||||
menu->getChildByID("delete-button")
|
||||
menu->getChildByID("delete-trash-button")
|
||||
);
|
||||
|
||||
detachAndCreateMenu(
|
||||
this, "playback-menu", RowLayout::create(), menu->getChildByID("music-playback-button")
|
||||
undoMenu->setContentSize({ undoMenuWidth, 50.f });
|
||||
undoMenu->setPositionX(
|
||||
undoMenu->getPositionX() + undoMenuWidth / 2 -
|
||||
getSizeSafe(undoMenu->getChildByID("undo-button")).width / 2
|
||||
);
|
||||
undoMenu->updateLayout();
|
||||
|
||||
detachAndCreateMenu(
|
||||
auto playBackMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"playback-menu",
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start),
|
||||
menu->getChildByID("music-playback-button")
|
||||
);
|
||||
playBackMenu->setContentSize({ 100.f, 50.f });
|
||||
playBackMenu->setPositionX(
|
||||
playBackMenu->getPositionX() + 100.f / 2 -
|
||||
getSizeSafe(playBackMenu->getChildByID("music-playback-button")).width / 2
|
||||
);
|
||||
playBackMenu->updateLayout();
|
||||
|
||||
auto playTestMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"playtest-menu",
|
||||
RowLayout::create(),
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start),
|
||||
menu->getChildByID("playtest-button"),
|
||||
menu->getChildByID("stop-playtest-button")
|
||||
);
|
||||
playTestMenu->setContentSize({ 100.f, 50.f });
|
||||
playTestMenu->setPositionX(
|
||||
playTestMenu->getPositionX() + 100.f / 2 -
|
||||
getSizeSafe(playTestMenu->getChildByID("playtest-button")).width / 2
|
||||
);
|
||||
playTestMenu->updateLayout();
|
||||
|
||||
detachAndCreateMenu(
|
||||
auto zoomMenuHeight = winSize.height - 245.f;
|
||||
auto zoomMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"zoom-menu",
|
||||
ColumnLayout::create(),
|
||||
menu->getChildByID("zoom-in-button"),
|
||||
menu->getChildByID("zoom-out-button")
|
||||
ColumnLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start),
|
||||
menu->getChildByID("zoom-out-button"),
|
||||
menu->getChildByID("zoom-in-button")
|
||||
);
|
||||
zoomMenu->setPositionY(150.f * winSize.height / 320);
|
||||
zoomMenu->setContentSize({ 50.f, zoomMenuHeight });
|
||||
zoomMenu->updateLayout();
|
||||
|
||||
detachAndCreateMenu(
|
||||
auto linkMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"link-menu",
|
||||
ColumnLayout::create(),
|
||||
menu->getChildByID("link-button"),
|
||||
menu->getChildByID("unlink-button")
|
||||
ColumnLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
->setGrowCrossAxis(true),
|
||||
menu->getChildByID("unlink-button"),
|
||||
menu->getChildByID("link-button")
|
||||
);
|
||||
linkMenu->setPositionY(150.f * winSize.height / 320);
|
||||
linkMenu->setContentSize({ 125.f, zoomMenuHeight });
|
||||
linkMenu->updateLayout();
|
||||
|
||||
menu->setPosition(42.f, 45.f);
|
||||
menu->setContentSize({ 100.f, 90.f });
|
||||
menu->setLayout(
|
||||
ColumnLayout::create()
|
||||
->setGap(4.f)
|
||||
->setAxisReverse(true)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -108,24 +164,43 @@ $register_ids(EditorUI) {
|
|||
"delete-help-icon"
|
||||
);
|
||||
|
||||
detachAndCreateMenu(
|
||||
auto deleteButtonMenu = detachAndCreateMenu(
|
||||
menu,
|
||||
"delete-button-menu",
|
||||
GridLayout::create(2, GridAlignment::Begin, GridDirection::Column),
|
||||
ColumnLayout::create()
|
||||
->setCrossAxisOverflow(false)
|
||||
->setGrowCrossAxis(true)
|
||||
->setAxisReverse(true)
|
||||
->setCrossAxisReverse(true)
|
||||
->setAxisAlignment(AxisAlignment::End)
|
||||
->setCrossAxisAlignment(AxisAlignment::Center),
|
||||
menu->getChildByID("delete-button"),
|
||||
menu->getChildByID("delete-all-of-button"),
|
||||
menu->getChildByID("delete-startpos-button")
|
||||
);
|
||||
|
||||
detachAndCreateMenu(
|
||||
deleteButtonMenu->setPosition(-88.5f, 0.f);
|
||||
deleteButtonMenu->setContentSize({ winSize.width / 2 - 120.f, 80.f });
|
||||
deleteButtonMenu->updateLayout();
|
||||
|
||||
auto filterMenuWidth = winSize.width / 2 - 150.f;
|
||||
auto deleteFilterMenu = detachAndCreateMenu(
|
||||
menu,
|
||||
"delete-filter-menu",
|
||||
GridLayout::create(2, GridAlignment::Begin, GridDirection::Column),
|
||||
ColumnLayout::create()
|
||||
->setCrossAxisOverflow(false)
|
||||
->setGrowCrossAxis(true)
|
||||
->setAxisReverse(true)
|
||||
->setCrossAxisReverse(true)
|
||||
->setAxisAlignment(AxisAlignment::End)
|
||||
->setCrossAxisAlignment(AxisAlignment::Start),
|
||||
menu->getChildByID("delete-filter-none"),
|
||||
menu->getChildByID("delete-filter-static"),
|
||||
menu->getChildByID("delete-filter-detail"),
|
||||
menu->getChildByID("delete-filter-custom")
|
||||
);
|
||||
deleteFilterMenu->setPosition(48.5f + filterMenuWidth / 2, 0.f);
|
||||
deleteFilterMenu->setContentSize({ filterMenuWidth, 80.f });
|
||||
deleteFilterMenu->updateLayout();
|
||||
}
|
||||
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 2)) {
|
||||
|
@ -134,20 +209,27 @@ $register_ids(EditorUI) {
|
|||
setIDs(
|
||||
menu,
|
||||
0,
|
||||
"static-tab-1",
|
||||
"static-tab-2",
|
||||
"static-tab-3",
|
||||
"block-tab",
|
||||
"half-block-tab",
|
||||
"outline-tab",
|
||||
"slope-tab",
|
||||
"hazard-tab",
|
||||
"3d-tab",
|
||||
"portal-tab",
|
||||
"deco-tab-1",
|
||||
"deco-tab-2",
|
||||
"ground-deco-tab",
|
||||
"air-deco-tab",
|
||||
"pulse-deco-tab",
|
||||
"sawblade-tab",
|
||||
"trigger-tab",
|
||||
"custom-tab"
|
||||
);
|
||||
|
||||
menu->setPosition(winSize.width / 2, 100.f);
|
||||
menu->setContentSize({ winSize.width, 50.f });
|
||||
menu->setLayout(
|
||||
RowLayout::create()
|
||||
->setGap(0.f)
|
||||
);
|
||||
}
|
||||
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 3)) {
|
||||
|
@ -174,18 +256,33 @@ $register_ids(EditorUI) {
|
|||
"all-layers-button"
|
||||
);
|
||||
|
||||
detachAndCreateMenu(
|
||||
auto topRightMenuWidth = winSize.width / 2 - 140.f;
|
||||
auto topRightMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"top-right-menu",
|
||||
RowLayout::create()->setAlignment(Alignment::End),
|
||||
"settings-menu",
|
||||
RowLayout::create()
|
||||
->setAxisReverse(true)
|
||||
->setAxisAlignment(AxisAlignment::End),
|
||||
menu->getChildByID("pause-button"),
|
||||
menu->getChildByID("settings-button")
|
||||
);
|
||||
topRightMenu->setContentSize({ topRightMenuWidth, 60.f });
|
||||
topRightMenu->setPositionX(
|
||||
topRightMenu->getPositionX() - topRightMenuWidth / 2 +
|
||||
getSizeSafe(topRightMenu->getChildByID("pause-button")).width / 2
|
||||
);
|
||||
topRightMenu->updateLayout();
|
||||
|
||||
detachAndCreateMenu(
|
||||
auto rightMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"editor-buttons-menu",
|
||||
GridLayout::create(4, GridAlignment::End, GridDirection::Column),
|
||||
ColumnLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::End)
|
||||
->setCrossAxisAlignment(AxisAlignment::End)
|
||||
->setGap(-3.5f)
|
||||
->setGrowCrossAxis(true)
|
||||
->setCrossAxisOverflow(false)
|
||||
->setAxisReverse(true),
|
||||
menu->getChildByID("copy-paste-button"),
|
||||
menu->getChildByID("edit-object-button"),
|
||||
menu->getChildByID("paste-color-button"),
|
||||
|
@ -199,16 +296,35 @@ $register_ids(EditorUI) {
|
|||
menu->getChildByID("copy-values-button"),
|
||||
menu->getChildByID("hsv-button")
|
||||
);
|
||||
for (auto btn : CCArrayExt<CCNode>(rightMenu->getChildren())) {
|
||||
btn->setContentSize({ 40.f, 40.f });
|
||||
}
|
||||
rightMenu->setContentSize({ 210.f, 160.f });
|
||||
rightMenu->setPosition(
|
||||
winSize.width - 210.f / 2 - 5.f,
|
||||
winSize.height / 2 + 42.5f
|
||||
);
|
||||
rightMenu->updateLayout();
|
||||
|
||||
detachAndCreateMenu(
|
||||
this->getChildByID("layer-index-label")->setLayoutOptions(
|
||||
AxisLayoutOptions::create()
|
||||
->setAutoScale(false)
|
||||
->setLength(25.f)
|
||||
);
|
||||
|
||||
auto layerMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"layer-menu",
|
||||
RowLayout::create(),
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start),
|
||||
menu->getChildByID("all-layers-button"),
|
||||
menu->getChildByID("prev-layer-button"),
|
||||
this->getChildByID("layer-index-label"),
|
||||
menu->getChildByID("next-layer-button")
|
||||
);
|
||||
layerMenu->setPositionX(winSize.width - 110.f / 2);
|
||||
layerMenu->setContentSize({ 110.f, 30.f });
|
||||
layerMenu->updateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,10 @@ $register_ids(GJGarageLayer) {
|
|||
setIDSafe(this, 2, "username-label");
|
||||
setIDSafe(this, 6, "player-icon");
|
||||
|
||||
auto winSize = CCDirector::get()->getWinSize();
|
||||
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 0)) {
|
||||
menu->setID("icon-select-menu");
|
||||
menu->setID("category-menu");
|
||||
|
||||
setIDs(
|
||||
menu,
|
||||
|
@ -26,6 +28,13 @@ $register_ids(GJGarageLayer) {
|
|||
"trail-button",
|
||||
"death-effect-button"
|
||||
);
|
||||
|
||||
menu->setContentSize({ 320.f, 50.f });
|
||||
menu->setLayout(
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
->setGap(-4.f)
|
||||
);
|
||||
}
|
||||
|
||||
setIDs(
|
||||
|
@ -47,13 +56,99 @@ $register_ids(GJGarageLayer) {
|
|||
"color-selection-menu"
|
||||
);
|
||||
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 11)) {
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 1)) {
|
||||
menu->setID("top-left-menu");
|
||||
|
||||
setIDs(menu, 0, "back-button", "shop-button", "shards-button");
|
||||
|
||||
detachAndCreateMenu(
|
||||
menu, "shards-button-menu", ColumnLayout::create(), menu->getChildByID("shards-button")
|
||||
auto backBtn = menu->getChildByID("back-button");
|
||||
auto backMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"back-menu",
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start),
|
||||
backBtn
|
||||
);
|
||||
backMenu->setContentSize({ 100.f, 50.f });
|
||||
backMenu->setPositionX(
|
||||
backMenu->getPositionX() + 100.f / 2 -
|
||||
getSizeSafe(backBtn).width / 2
|
||||
);
|
||||
backMenu->updateLayout();
|
||||
|
||||
auto shardsBtn = menu->getChildByID("shards-button");
|
||||
auto shardsMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"shards-menu",
|
||||
ColumnLayout::create()
|
||||
->setAxisReverse(true)
|
||||
->setAxisAlignment(AxisAlignment::End),
|
||||
shardsBtn
|
||||
);
|
||||
shardsMenu->setContentSize({ 50.f, 100.f });
|
||||
shardsMenu->setPositionY(
|
||||
shardsMenu->getPositionY() - 100.f / 2 +
|
||||
getSizeSafe(shardsBtn).height / 2
|
||||
);
|
||||
shardsMenu->updateLayout();
|
||||
}
|
||||
|
||||
auto bottomLeftMenu = CCMenu::create();
|
||||
bottomLeftMenu->setID("bottom-left-menu");
|
||||
bottomLeftMenu->setContentSize({ 50.f, 70.f });
|
||||
bottomLeftMenu->setPosition(30.f, 115.f);
|
||||
bottomLeftMenu->setLayout(
|
||||
ColumnLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
);
|
||||
this->addChild(bottomLeftMenu);
|
||||
|
||||
auto bottomRightMenu = CCMenu::create();
|
||||
bottomRightMenu->setID("bottom-right-menu");
|
||||
bottomRightMenu->setContentSize({ 50.f, 110.f });
|
||||
bottomRightMenu->setPosition(winSize.width - 30.f, 135.f);
|
||||
bottomRightMenu->setLayout(
|
||||
ColumnLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
);
|
||||
this->addChild(bottomRightMenu);
|
||||
|
||||
// aspect ratio responsiveness
|
||||
if (winSize.width / winSize.height <= 5.1f / 3.f) {
|
||||
bottomLeftMenu->setPosition(15.f, 115.f);
|
||||
bottomRightMenu->setPosition(winSize.width - 15.f, 135.f);
|
||||
|
||||
if (auto shardsMenu = this->getChildByID("shards-menu")) {
|
||||
shardsMenu->setContentSize({ 110.f, 50.f });
|
||||
shardsMenu->setPosition(
|
||||
shardsMenu->getPosition() + ccp(50.f, 30.f)
|
||||
);
|
||||
shardsMenu->setLayout(
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (winSize.width / winSize.height <= 4.1f / 3.f) {
|
||||
bottomLeftMenu->setContentSize({ 90.f, 50.f });
|
||||
bottomLeftMenu->setPosition(
|
||||
15.f + 110.f / 2,
|
||||
85.f
|
||||
);
|
||||
bottomLeftMenu->setLayout(
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
);
|
||||
|
||||
bottomRightMenu->setContentSize({ 90.f, 50.f });
|
||||
bottomRightMenu->setPosition(
|
||||
winSize.width - 15.f - 110.f / 2,
|
||||
85.f
|
||||
);
|
||||
bottomRightMenu->setLayout(
|
||||
RowLayout::create()
|
||||
->setAxisReverse(true)
|
||||
->setAxisAlignment(AxisAlignment::End)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,28 +7,153 @@
|
|||
USE_GEODE_NAMESPACE();
|
||||
|
||||
$register_ids(LevelBrowserLayer) {
|
||||
auto winSize = CCDirector::get()->getWinSize();
|
||||
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 0)) {
|
||||
menu->setID("go-back-menu");
|
||||
setIDSafe(menu, 0, "back-button");
|
||||
menu->setID("back-menu");
|
||||
auto btn = setIDSafe(menu, 0, "back-button");
|
||||
menu->setContentSize({ 100.f, 50.f });
|
||||
menu->setPositionX(
|
||||
menu->getPositionX() + 100.f / 2 -
|
||||
getSizeSafe(btn).width / 2
|
||||
);
|
||||
menu->setLayout(
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
);
|
||||
}
|
||||
|
||||
if (m_searchObject->m_searchType == SearchType::MyLevels) {
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 2)) {
|
||||
menu->setID("new-level-menu");
|
||||
setIDSafe(menu, 0, "new-level-button");
|
||||
auto newLvlBtn = setIDSafe(menu, 0, "new-level-button");
|
||||
|
||||
if (auto myLevelsBtn = setIDSafe(menu, 1, "my-levels-button")) {
|
||||
detachAndCreateMenu(
|
||||
auto menu = detachAndCreateMenu(
|
||||
this,
|
||||
"my-levels-menu",
|
||||
ColumnLayout::create(5.f, 0.f)->setAlignment(Alignment::End),
|
||||
ColumnLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start),
|
||||
myLevelsBtn
|
||||
);
|
||||
menu->setPositionY(
|
||||
menu->getPositionY() + 125.f / 2 -
|
||||
myLevelsBtn->getScaledContentSize().height / 2
|
||||
);
|
||||
menu->setContentSize({ 50.f, 125.f });
|
||||
menu->updateLayout();
|
||||
}
|
||||
|
||||
menu->setLayout(ColumnLayout::create(5.f, 0.f)->setAlignment(Alignment::End));
|
||||
menu->setLayout(
|
||||
ColumnLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
);
|
||||
menu->setPositionY(
|
||||
menu->getPositionY() + 130.f / 2 -
|
||||
getSizeSafe(newLvlBtn).height / 2
|
||||
);
|
||||
menu->setContentSize({ 50.f, 130.f });
|
||||
menu->updateLayout();
|
||||
}
|
||||
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 1)) {
|
||||
if (auto searchBtn = setIDSafe(menu, 5, "search-button")) {
|
||||
auto clearBtn = setIDSafe(menu, 6, "clear-search-button");
|
||||
// this is a hacky fix because for some reason adding children
|
||||
// before the clear button is made visible is inconsistent
|
||||
if (clearBtn) {
|
||||
searchBtn->setZOrder(-1);
|
||||
clearBtn->setZOrder(-1);
|
||||
}
|
||||
auto searchMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"search-menu",
|
||||
ColumnLayout::create()
|
||||
->setAxisReverse(true)
|
||||
->setCrossAxisReverse(true)
|
||||
->setGrowCrossAxis(true)
|
||||
->setCrossAxisOverflow(false)
|
||||
->setCrossAxisAlignment(AxisAlignment::Start)
|
||||
->setAxisAlignment(AxisAlignment::End),
|
||||
searchBtn,
|
||||
clearBtn
|
||||
);
|
||||
auto width = 45.f * winSize.aspect();
|
||||
searchMenu->setPosition(
|
||||
searchMenu->getPositionX() + width / 2 -
|
||||
searchBtn->getScaledContentSize().width / 2,
|
||||
searchMenu->getPositionY() - 80.f / 2 +
|
||||
searchBtn->getScaledContentSize().height / 2
|
||||
);
|
||||
searchMenu->setContentSize({ width, 80.f });
|
||||
searchMenu->updateLayout();
|
||||
}
|
||||
|
||||
if (auto pageBtn = setIDSafe(menu, 2, "page-button")) {
|
||||
auto folderBtn = setIDSafe(menu, 3, "folder-button");
|
||||
auto lastPageBtn = setIDSafe(menu, 4, "last-page-button");
|
||||
auto pageMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"page-menu",
|
||||
ColumnLayout::create()
|
||||
->setAxisReverse(true)
|
||||
->setGrowCrossAxis(true)
|
||||
->setAxisAlignment(AxisAlignment::End),
|
||||
pageBtn,
|
||||
folderBtn,
|
||||
lastPageBtn
|
||||
);
|
||||
pageMenu->setContentSize({ 40.f, 110.f });
|
||||
pageMenu->setAnchorPoint({ 1.f, .5f });
|
||||
pageMenu->setPosition(
|
||||
pageMenu->getPositionX() + 20.f,
|
||||
pageMenu->getPositionY() - 110.f / 2 + 12.5f
|
||||
);
|
||||
pageMenu->updateLayout();
|
||||
}
|
||||
|
||||
auto navMenuWidth = 50.f * winSize.aspect();
|
||||
|
||||
if (auto prevPageBtn = setIDSafe(menu, 0, "prev-page-button")) {
|
||||
auto navMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"prev-page-menu",
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start),
|
||||
prevPageBtn
|
||||
);
|
||||
prevPageBtn->setZOrder(-1);
|
||||
navMenu->setContentSize({ navMenuWidth, 40.f });
|
||||
navMenu->setPositionX(
|
||||
navMenu->getPositionX() + navMenuWidth / 2 -
|
||||
prevPageBtn->getScaledContentSize().width / 2
|
||||
);
|
||||
navMenu->updateLayout();
|
||||
}
|
||||
|
||||
auto nextPageBtn = setIDSafe(menu, 0, "next-page-button");
|
||||
|
||||
menu->setID("next-page-menu");
|
||||
menu->setLayout(
|
||||
RowLayout::create()
|
||||
->setAxisReverse(true)
|
||||
->setAxisAlignment(AxisAlignment::End)
|
||||
);
|
||||
menu->setContentSize({ navMenuWidth, 40.f });
|
||||
menu->setPositionX(
|
||||
winSize.width - navMenuWidth / 2 - 5.f
|
||||
);
|
||||
menu->updateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
auto bottomMenu = CCMenu::create();
|
||||
bottomMenu->setID("bottom-menu");
|
||||
bottomMenu->setContentSize({ 325.f + 20.f * winSize.aspect(), 50.f });
|
||||
bottomMenu->setPosition(winSize.width / 2, 28.f);
|
||||
bottomMenu->setZOrder(15);
|
||||
bottomMenu->setLayout(RowLayout::create());
|
||||
this->addChild(bottomMenu);
|
||||
}
|
||||
|
||||
struct LevelBrowserLayerIDs : Modify<LevelBrowserLayerIDs, LevelBrowserLayer> {
|
||||
|
|
|
@ -35,26 +35,52 @@ $register_ids(LevelInfoLayer) {
|
|||
setIDSafe<CustomSongWidget>(this, 0, "custom-songs-widget");
|
||||
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 0)) {
|
||||
menu->setID("exit-menu");
|
||||
setIDSafe(menu, 0, "exit-button");
|
||||
menu->setID("play-menu");
|
||||
setIDSafe(menu, 0, "play-button");
|
||||
}
|
||||
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 2)) {
|
||||
menu->setID("back-menu");
|
||||
auto backBtn = setIDSafe(menu, 0, "back-button");
|
||||
menu->setPositionX(
|
||||
menu->getPositionX() + 100.f / 2 -
|
||||
getSizeSafe(backBtn).width / 2
|
||||
);
|
||||
menu->setContentSize({ 100.f, 50.f });
|
||||
menu->setLayout(
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
);
|
||||
}
|
||||
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 1)) {
|
||||
menu->setID("right-side-menu");
|
||||
|
||||
if (auto name = setIDSafe(menu, 0, "creator-name")) {
|
||||
detachAndCreateMenu(
|
||||
this, "creator-info-menu", ColumnLayout::create()->setAlignment(Alignment::Begin), name
|
||||
auto menu = detachAndCreateMenu(
|
||||
this,
|
||||
"creator-info-menu",
|
||||
ColumnLayout::create()
|
||||
->setAxisReverse(true)
|
||||
->setAxisAlignment(AxisAlignment::End),
|
||||
name
|
||||
);
|
||||
menu->setPositionY(
|
||||
menu->getPositionY() - 40.f / 2 +
|
||||
name->getScaledContentSize().height / 2
|
||||
);
|
||||
menu->setContentSize({ 60.f, 40.f });
|
||||
menu->updateLayout();
|
||||
}
|
||||
|
||||
auto leftSideMenu = CCMenu::create();
|
||||
leftSideMenu->setPosition(winSize / 2 + ccp(-254.f, 30.f));
|
||||
leftSideMenu->setPosition(30.f, winSize.height / 2);
|
||||
leftSideMenu->setLayout(ColumnLayout::create());
|
||||
leftSideMenu->setID("left-side-menu");
|
||||
leftSideMenu->setContentSize({ 50.f, 225.f });
|
||||
this->addChild(leftSideMenu);
|
||||
|
||||
menu->setPosition(winSize / 2 + ccp(254.f, 0.f));
|
||||
menu->setPosition(winSize.width - 30.f, winSize.height / 2);
|
||||
|
||||
for (auto child : CCArrayExt<CCNode>(menu->getChildren())) {
|
||||
if (child->getPositionX() < 0.f) {
|
||||
|
@ -73,6 +99,20 @@ $register_ids(LevelInfoLayer) {
|
|||
setIDSafe(menu, 4, "like-button");
|
||||
setIDSafe(menu, 5, "rate-button");
|
||||
|
||||
menu->setPosition(
|
||||
menu->getPositionX() + static_cast<CCNode*>(
|
||||
menu->getChildren()->firstObject()
|
||||
)->getPositionX(),
|
||||
winSize.height / 2
|
||||
);
|
||||
menu->setContentSize({ 60.f, winSize.height - 15.f });
|
||||
menu->setLayout(
|
||||
ColumnLayout::create()
|
||||
->setGap(3.f)
|
||||
->setAxisAlignment(AxisAlignment::End)
|
||||
->setAxisReverse(true)
|
||||
);
|
||||
|
||||
setIDSafe(leftSideMenu, 0, "copy-button");
|
||||
|
||||
menu->updateLayout();
|
||||
|
|
|
@ -162,12 +162,15 @@ $register_ids(LevelSettingsLayer) {
|
|||
menu->getChildByID("2-player-toggle")
|
||||
);
|
||||
|
||||
detachAndCreateMenu(
|
||||
auto fontButtonMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"font-button-menu",
|
||||
RowLayout::create()->setAlignment(Alignment::End),
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::End),
|
||||
menu->getChildByID("font-button")
|
||||
);
|
||||
fontButtonMenu->setPositionY(fontButtonMenu->getPositionY() - 100.f / 2);
|
||||
fontButtonMenu->setContentSize({ 50.f, 100.f });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <Geode/modify/MenuLayer.hpp>
|
||||
#include <Geode/utils/cocos.hpp>
|
||||
#include <Geode/ui/BasedButtonSprite.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
|
@ -10,6 +11,8 @@ $register_ids(MenuLayer) {
|
|||
setIDSafe(this, 0, "main-menu-bg");
|
||||
setIDSafe<CCSprite>(this, 0, "main-title");
|
||||
|
||||
auto winSize = CCDirector::get()->getWinSize();
|
||||
|
||||
// controller
|
||||
if (PlatformToolbox::isControllerConnected()) {
|
||||
setIDSafe<CCSprite>(this, 1, "play-gamepad-icon");
|
||||
|
@ -28,24 +31,42 @@ $register_ids(MenuLayer) {
|
|||
else {
|
||||
setIDSafe<CCLabelBMFont>(this, 0, "player-username");
|
||||
}
|
||||
|
||||
// main menu
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 0)) {
|
||||
menu->setID("main-menu");
|
||||
auto playBtn = setIDSafe(menu, 0, "play-button");
|
||||
auto iconBtn = setIDSafe(menu, 1, "icon-kit-button");
|
||||
|
||||
setIDSafe(menu, 2, "editor-button");
|
||||
|
||||
if (auto pfp = setIDSafe(menu, 3, "profile-button")) {
|
||||
auto profileMenu = detachAndCreateMenu(
|
||||
this, "profile-menu",
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start),
|
||||
pfp
|
||||
);
|
||||
profileMenu->setContentSize({ 150.f, 50.f });
|
||||
profileMenu->setPositionX(
|
||||
profileMenu->getPositionX() + 150.f / 2 -
|
||||
pfp->getScaledContentSize().height / 2
|
||||
);
|
||||
profileMenu->updateLayout();
|
||||
}
|
||||
|
||||
// the buttons are added in order play, icon, editor which doesn't work
|
||||
// well with setLayout that deals with children in order
|
||||
menu->swapChildIndices(playBtn, iconBtn);
|
||||
|
||||
setIDSafe(menu, 2, "editor-button");
|
||||
|
||||
if (auto pfp = setIDSafe(menu, 3, "profile-button")) {
|
||||
pfp->setPositionHint(PositionHint::Absolute);
|
||||
}
|
||||
|
||||
menu->setLayout(RowLayout::create(18.f, 0.f));
|
||||
menu->setContentSize({ winSize.width - 140.f, 65.f });
|
||||
menu->setLayout(
|
||||
RowLayout::create()
|
||||
->setGap(18.f)
|
||||
->setCrossAxisOverflow(true)
|
||||
);
|
||||
}
|
||||
|
||||
// bottom menu
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 1)) {
|
||||
menu->setID("bottom-menu");
|
||||
|
@ -57,11 +78,22 @@ $register_ids(MenuLayer) {
|
|||
// move daily chest to its own menu
|
||||
|
||||
if (auto dailyChest = setIDSafe(menu, -1, "daily-chest-button")) {
|
||||
detachAndCreateMenu(this, "right-side-menu", ColumnLayout::create(0.f, 0.f), dailyChest);
|
||||
auto menu = detachAndCreateMenu(
|
||||
this,
|
||||
"right-side-menu",
|
||||
ColumnLayout::create(),
|
||||
dailyChest
|
||||
);
|
||||
menu->setContentSize({ 65.f, 180.f });
|
||||
menu->updateLayout();
|
||||
}
|
||||
|
||||
menu->setLayout(RowLayout::create(5.f, ach->getPositionY()));
|
||||
menu->setContentSize({ winSize.width - 220.f, 65.f });
|
||||
menu->setLayout(
|
||||
RowLayout::create()
|
||||
);
|
||||
}
|
||||
|
||||
// social media menu
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 2)) {
|
||||
menu->setID("social-media-menu");
|
||||
|
@ -70,19 +102,62 @@ $register_ids(MenuLayer) {
|
|||
setIDSafe(menu, 2, "twitter-button");
|
||||
setIDSafe(menu, 3, "youtube-button");
|
||||
}
|
||||
|
||||
// more games menu
|
||||
if (auto menu = getChildOfType<CCMenu>(this, 3)) {
|
||||
menu->setID("more-games-menu");
|
||||
setIDSafe(menu, 0, "more-games-button");
|
||||
auto moreGamesBtn = setIDSafe(menu, 0, "more-games-button");
|
||||
|
||||
// move close button to its own menu
|
||||
|
||||
if (auto closeBtn = setIDSafe(menu, 1, "close-button")) {
|
||||
detachAndCreateMenu(
|
||||
this, "close-menu", RowLayout::create(5.f, 0.f)->setAlignment(Alignment::Begin), closeBtn
|
||||
auto closeMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"close-menu",
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::Start),
|
||||
closeBtn
|
||||
);
|
||||
closeMenu->setContentSize({ 200.f, 50.f });
|
||||
closeMenu->setPositionX(
|
||||
closeMenu->getPositionX() + 200.f / 2 -
|
||||
closeBtn->getScaledContentSize().width / 2
|
||||
);
|
||||
closeMenu->updateLayout();
|
||||
}
|
||||
|
||||
menu->setContentSize({ 100.f, 50.f });
|
||||
menu->setPositionX(
|
||||
menu->getPositionX() - 100.f / 2 +
|
||||
getSizeSafe(moreGamesBtn).width / 2
|
||||
);
|
||||
menu->setLayout(
|
||||
RowLayout::create()
|
||||
->setAxisAlignment(AxisAlignment::End)
|
||||
->setAxisReverse(true)
|
||||
);
|
||||
}
|
||||
|
||||
// add a menu to the top right corner and middle left that are empty
|
||||
// but prolly a place mods want to add stuff
|
||||
|
||||
auto topRightMenu = CCMenu::create();
|
||||
topRightMenu->setPosition(winSize.width - 200.f / 2, winSize.height - 50.f / 2);
|
||||
topRightMenu->setID("top-right-menu");
|
||||
topRightMenu->setContentSize({ 200.f, 50.f });
|
||||
topRightMenu->setLayout(
|
||||
RowLayout::create()
|
||||
->setAxisReverse(true)
|
||||
->setAxisAlignment(AxisAlignment::End)
|
||||
);
|
||||
this->addChild(topRightMenu);
|
||||
|
||||
auto middleLeftMenu = CCMenu::create();
|
||||
middleLeftMenu->setPosition(25.f, 215.f);
|
||||
middleLeftMenu->setID("side-menu");
|
||||
middleLeftMenu->setContentSize({ 50.f, 120.f });
|
||||
middleLeftMenu->setLayout(ColumnLayout::create());
|
||||
this->addChild(middleLeftMenu);
|
||||
}
|
||||
|
||||
// MenuLayer::init is hooked in ../hooks/MenuLayer.cpp
|
||||
|
|
|
@ -11,6 +11,6 @@ static constexpr geode::VersionInfo LOADER_VERSION = {
|
|||
@PROJECT_VERSION_MAJOR@,
|
||||
@PROJECT_VERSION_MINOR@,
|
||||
@PROJECT_VERSION_PATCH@,
|
||||
@PROJECT_VERSION_TYPE@,
|
||||
@PROJECT_VERSION_TAG_CONSTR@,
|
||||
};
|
||||
static constexpr const char* LOADER_MOD_JSON = R"JSON_SEPARATOR(@LOADER_MOD_JSON@)JSON_SEPARATOR";
|
||||
|
|
|
@ -97,8 +97,7 @@ Result<ModInfo> ModInfo::Impl::createFromSchemaV010(ModJson const& rawJson) {
|
|||
root.has("unloadable").into(impl->m_supportsUnloading);
|
||||
root.has("early-load").into(impl->m_needsEarlyLoad);
|
||||
if (root.has("api")) {
|
||||
// TODO: figure out what got wiped with merge
|
||||
// impl->isAPI = true;
|
||||
impl->m_isAPI = true;
|
||||
}
|
||||
|
||||
for (auto& dep : root.has("dependencies").iterate()) {
|
||||
|
@ -194,11 +193,9 @@ Result<ModInfo> ModInfo::Impl::create(ModJson const& json) {
|
|||
|
||||
return Err(
|
||||
"[mod.json] targets a version (" + schema.toString() +
|
||||
") that isn't "
|
||||
"supported by this version (v" +
|
||||
") that isn't supported by this version (v" +
|
||||
LOADER_VERSION_STR +
|
||||
") of geode. "
|
||||
"This is probably a bug; report it to "
|
||||
") of geode. This is probably a bug; report it to "
|
||||
"the Geode Development Team."
|
||||
);
|
||||
}
|
||||
|
|
|
@ -79,9 +79,7 @@ void ModListCell::setupInfo(
|
|||
this->addChild(versionLabel);
|
||||
|
||||
if (auto tag = info.version().getTag()) {
|
||||
auto tagLabel = TagNode::create(
|
||||
versionTagToString(tag.value()).c_str()
|
||||
);
|
||||
auto tagLabel = TagNode::create(tag.value().toString().c_str());
|
||||
tagLabel->setAnchorPoint({ .0f, .5f });
|
||||
tagLabel->setScale(.3f);
|
||||
tagLabel->setPosition(
|
||||
|
|
|
@ -10,31 +10,57 @@ USE_GEODE_NAMESPACE();
|
|||
|
||||
// VersionTag
|
||||
|
||||
std::optional<VersionTag> geode::versionTagFromString(std::string const& str) {
|
||||
switch (hash(str.c_str())) {
|
||||
case hash("alpha"): return VersionTag::Alpha;
|
||||
case hash("beta"): return VersionTag::Beta;
|
||||
case hash("prerelease"): return VersionTag::Prerelease;
|
||||
default: return std::nullopt;
|
||||
Result<VersionTag> VersionTag::parse(std::stringstream& str) {
|
||||
std::string iden;
|
||||
while ('a' <= str.peek() && str.peek() <= 'z') {
|
||||
iden += str.get();
|
||||
}
|
||||
if (str.fail()) {
|
||||
return Err("Unable to parse tag");
|
||||
}
|
||||
VersionTag tag = VersionTag::Alpha;
|
||||
switch (hash(iden.c_str())) {
|
||||
case hash("alpha"): tag = VersionTag::Alpha; break;
|
||||
case hash("beta"): tag = VersionTag::Beta; break;
|
||||
case hash("prerelease"): case hash("pr"): tag = VersionTag::Prerelease; break;
|
||||
default: return Err("Invalid tag \"" + iden + "\"");
|
||||
}
|
||||
if (str.peek() == '.') {
|
||||
str.get();
|
||||
size_t num;
|
||||
str >> num;
|
||||
if (str.fail()) {
|
||||
return Err("Unable to parse tag number");
|
||||
}
|
||||
tag.number = num;
|
||||
}
|
||||
return Ok(tag);
|
||||
}
|
||||
|
||||
std::string geode::versionTagToSuffixString(VersionTag tag) {
|
||||
switch (tag) {
|
||||
case VersionTag::Alpha: return "-alpha";
|
||||
case VersionTag::Beta: return "-beta";
|
||||
case VersionTag::Prerelease: return "-prerelease";
|
||||
std::string VersionTag::toSuffixString() const {
|
||||
std::string res = "";
|
||||
switch (value) {
|
||||
case Alpha: res += "-alpha"; break;
|
||||
case Beta: res += "-beta"; break;
|
||||
case Prerelease: res += "-prerelease"; break;
|
||||
}
|
||||
return "";
|
||||
if (number) {
|
||||
res += "." + std::to_string(number.value());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string geode::versionTagToString(VersionTag tag) {
|
||||
switch (tag) {
|
||||
case VersionTag::Alpha: return "Alpha";
|
||||
case VersionTag::Beta: return "Beta";
|
||||
case VersionTag::Prerelease: return "Prerelease";
|
||||
std::string VersionTag::toString() const {
|
||||
std::string res = "";
|
||||
switch (value) {
|
||||
case Alpha: res += "Alpha"; break;
|
||||
case Beta: res += "Beta"; break;
|
||||
case Prerelease: res += "Prerelease"; break;
|
||||
}
|
||||
return "";
|
||||
if (number) {
|
||||
res += " " + std::to_string(number.value());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// VersionInfo
|
||||
|
@ -77,18 +103,13 @@ Result<VersionInfo> VersionInfo::parse(std::string const& string) {
|
|||
std::optional<VersionTag> tag;
|
||||
if (str.peek() == '-') {
|
||||
str.get();
|
||||
std::string iden;
|
||||
str >> iden;
|
||||
if (str.fail()) {
|
||||
return Err("Unable to parse tag");
|
||||
}
|
||||
if (auto t = versionTagFromString(iden)) {
|
||||
tag = t;
|
||||
}
|
||||
else {
|
||||
return Err("Invalid tag \"" + iden + "\"");
|
||||
}
|
||||
GEODE_UNWRAP_INTO(tag, VersionTag::parse(str));
|
||||
}
|
||||
|
||||
if (!str.eof()) {
|
||||
return Err("Expected end of version, found '" + std::string(1, str.get()) + "'");
|
||||
}
|
||||
|
||||
return Ok(VersionInfo(major, minor, patch, tag));
|
||||
}
|
||||
|
||||
|
@ -97,7 +118,7 @@ std::string VersionInfo::toString(bool includeTag) const {
|
|||
return fmt::format(
|
||||
"v{}.{}.{}{}",
|
||||
m_major, m_minor, m_patch,
|
||||
versionTagToSuffixString(m_tag.value())
|
||||
m_tag.value().toSuffixString()
|
||||
);
|
||||
}
|
||||
return fmt::format("v{}.{}.{}", m_major, m_minor, m_patch);
|
||||
|
|
Loading…
Add table
Reference in a new issue