removing deprecated things, part 1 (does not compile)

This commit is contained in:
altalk23 2024-11-04 20:14:23 +03:00
parent 4dcac338f9
commit 50ab4ebed7
45 changed files with 580 additions and 3306 deletions

View file

@ -5,7 +5,7 @@
#include "loader/Log.hpp" #include "loader/Log.hpp"
#include "loader/Mod.hpp" #include "loader/Mod.hpp"
#include "loader/ModEvent.hpp" #include "loader/ModEvent.hpp"
#include "loader/Setting.hpp" #include "loader/SettingV3.hpp"
#include "loader/Dirs.hpp" #include "loader/Dirs.hpp"
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>

View file

@ -6,7 +6,8 @@
#include "ui/EnterLayerEvent.hpp" #include "ui/EnterLayerEvent.hpp"
#include "ui/BasedButtonSprite.hpp" #include "ui/BasedButtonSprite.hpp"
#include "ui/IconButtonSprite.hpp" #include "ui/IconButtonSprite.hpp"
#include "ui/InputNode.hpp" #include "ui/Layout.hpp"
#include "ui/SpacerNode.hpp"
#include "ui/General.hpp" #include "ui/General.hpp"
#include "ui/ListView.hpp" #include "ui/ListView.hpp"
#include "ui/MDPopup.hpp" #include "ui/MDPopup.hpp"

View file

@ -37,7 +37,6 @@
#include "../kazmath/include/kazmath/kazmath.h" #include "../kazmath/include/kazmath/kazmath.h"
#include "../script_support/CCScriptSupport.h" #include "../script_support/CCScriptSupport.h"
#include "../include/CCProtocols.h" #include "../include/CCProtocols.h"
#include "Layout.hpp"
#include "../../loader/Event.hpp" #include "../../loader/Event.hpp"
#include <Geode/utils/casts.hpp> #include <Geode/utils/casts.hpp>
@ -45,6 +44,12 @@
#include <matjson.hpp> #include <matjson.hpp>
#endif #endif
namespace geode {
class Layout;
class LayoutOptions;
enum class Anchor;
}
NS_CC_BEGIN NS_CC_BEGIN
class CCCamera; class CCCamera;
@ -871,25 +876,13 @@ public:
private: private:
friend class geode::modifier::FieldContainer; friend class geode::modifier::FieldContainer;
[[deprecated("Will be removed, it's an ABI break")]]
GEODE_DLL geode::modifier::FieldContainer* getFieldContainer();
GEODE_DLL geode::modifier::FieldContainer* getFieldContainer(char const* forClass); GEODE_DLL geode::modifier::FieldContainer* getFieldContainer(char const* forClass);
GEODE_DLL void addEventListenerInternal( GEODE_DLL void addEventListenerInternal(
std::string const& id, std::string const& id,
geode::EventListenerProtocol* protocol geode::EventListenerProtocol* protocol
); );
#ifdef GEODE_EXPORTING public:
[[deprecated("Will be removed, it's an ABI break")]]
GEODE_DLL std::optional<matjson::Value> getAttributeInternal(std::string const& attribute);
#endif
public:
#ifdef GEODE_EXPORTING
[[deprecated("Will be removed, it's an ABI break")]]
GEODE_DLL void setAttribute(std::string const& attribute, matjson::Value const& value);
#endif
/** /**
* Get the string ID of this node * Get the string ID of this node
* @returns The ID, or an empty string if the node has no ID. * @returns The ID, or an empty string if the node has no ID.
@ -990,13 +983,13 @@ public:
* CCLayers / CCMenus, this will change where the children are located * CCLayers / CCMenus, this will change where the children are located
* @note Geode addition * @note Geode addition
*/ */
GEODE_DLL void setLayout(Layout* layout, bool apply = true, bool respectAnchor = true); GEODE_DLL void setLayout(geode::Layout* layout, bool apply = true, bool respectAnchor = true);
/** /**
* Get the Layout for this node * Get the Layout for this node
* @returns The current layout, or nullptr if no layout is set * @returns The current layout, or nullptr if no layout is set
* @note Geode addition * @note Geode addition
*/ */
GEODE_DLL Layout* getLayout(); GEODE_DLL geode::Layout* getLayout();
/** /**
* Update the layout of this node using the current Layout. If no layout is * Update the layout of this node using the current Layout. If no layout is
* set, nothing happens * set, nothing happens
@ -1011,13 +1004,13 @@ public:
* @param apply Whether to update the layout of the parent node * @param apply Whether to update the layout of the parent node
* @note Geode addition * @note Geode addition
*/ */
GEODE_DLL void setLayoutOptions(LayoutOptions* options, bool apply = true); GEODE_DLL void setLayoutOptions(geode::LayoutOptions* options, bool apply = true);
/** /**
* Get the layout options for this node * Get the layout options for this node
* @returns The current layout options, or nullptr if no options are set * @returns The current layout options, or nullptr if no options are set
* @note Geode addition * @note Geode addition
*/ */
GEODE_DLL LayoutOptions* getLayoutOptions(); GEODE_DLL geode::LayoutOptions* getLayoutOptions();
/** /**
* Adds a child at an anchored position with an offset. The node is placed * Adds a child at an anchored position with an offset. The node is placed
* in its parent where the anchor specifies, and then the offset is used to * in its parent where the anchor specifies, and then the offset is used to
@ -1029,7 +1022,7 @@ public:
* if no other layout is already specified * if no other layout is already specified
* @note Geode addition * @note Geode addition
*/ */
GEODE_DLL void addChildAtPosition(CCNode* child, Anchor anchor, CCPoint const& offset = CCPointZero, bool useAnchorLayout = true); GEODE_DLL void addChildAtPosition(CCNode* child, geode::Anchor anchor, CCPoint const& offset = CCPointZero, bool useAnchorLayout = true);
/** /**
* Adds a child at an anchored position with an offset. The node is placed * Adds a child at an anchored position with an offset. The node is placed
* in its parent where the anchor specifies, and then the offset is used to * in its parent where the anchor specifies, and then the offset is used to
@ -1044,7 +1037,7 @@ public:
*/ */
GEODE_DLL void addChildAtPosition( GEODE_DLL void addChildAtPosition(
CCNode* child, CCNode* child,
Anchor anchor, geode::Anchor anchor,
CCPoint const& offset, CCPoint const& offset,
CCPoint const& nodeAnchor, CCPoint const& nodeAnchor,
bool useAnchorLayout = true bool useAnchorLayout = true
@ -1057,7 +1050,7 @@ public:
* @param offset Where to place the child relative to the anchor * @param offset Where to place the child relative to the anchor
* @note Geode addition * @note Geode addition
*/ */
GEODE_DLL void updateAnchoredPosition(Anchor anchor, CCPoint const& offset = CCPointZero); GEODE_DLL void updateAnchoredPosition(geode::Anchor anchor, CCPoint const& offset = CCPointZero);
/** /**
* Updates the anchored position of a child. Requires the child to already * Updates the anchored position of a child. Requires the child to already
* have a parent; if the child already has AnchorLayoutOptions set, those * have a parent; if the child already has AnchorLayoutOptions set, those
@ -1068,7 +1061,7 @@ public:
* @note Geode addition * @note Geode addition
*/ */
GEODE_DLL void updateAnchoredPosition( GEODE_DLL void updateAnchoredPosition(
Anchor anchor, geode::Anchor anchor,
CCPoint const& offset, CCPoint const& offset,
CCPoint const& nodeAnchor CCPoint const& nodeAnchor
); );

View file

@ -59,7 +59,6 @@ THE SOFTWARE.
// base_nodes // base_nodes
#include "../base_nodes/CCNode.h" #include "../base_nodes/CCNode.h"
#include "../base_nodes/CCAtlasNode.h" #include "../base_nodes/CCAtlasNode.h"
#include "../base_nodes/SpacerNode.hpp"
// cocoa // cocoa
#include "../cocoa/CCAffineTransform.h" #include "../cocoa/CCAffineTransform.h"

View file

@ -9,7 +9,6 @@
#include "Loader.hpp" // very nice circular dependency fix #include "Loader.hpp" // very nice circular dependency fix
#include "Hook.hpp" #include "Hook.hpp"
#include "ModMetadata.hpp" #include "ModMetadata.hpp"
#include "Setting.hpp"
#include "SettingV3.hpp" #include "SettingV3.hpp"
#include "Types.hpp" #include "Types.hpp"
#include "Loader.hpp" #include "Loader.hpp"
@ -108,8 +107,6 @@ namespace geode {
std::string getID() const; std::string getID() const;
std::string getName() const; std::string getName() const;
[[deprecated("Use Mod::getDevelopers instead")]]
std::string getDeveloper() const;
std::vector<std::string> getDevelopers() const; std::vector<std::string> getDevelopers() const;
std::optional<std::string> getDescription() const; std::optional<std::string> getDescription() const;
std::optional<std::string> getDetails() const; std::optional<std::string> getDetails() const;
@ -137,17 +134,6 @@ namespace geode {
std::vector<Mod*> getDependants() const; std::vector<Mod*> getDependants() const;
#endif #endif
/**
* Check if this Mod has updates available on the mods index. If
* you're using this for automatic update checking, use
* `openInfoPopup` or `openIndexPopup` from the `ui/GeodeUI.hpp`
* header to open the Mod's page to let the user install the update
* @returns The latest available version on the index if there are
* updates for this mod
*/
[[deprecated("Use Mod::checkUpdates instead; this function always returns nullopt")]]
std::optional<VersionInfo> hasAvailableUpdate() const;
using CheckUpdatesTask = Task<Result<std::optional<VersionInfo>, std::string>>; using CheckUpdatesTask = Task<Result<std::optional<VersionInfo>, std::string>>;
/** /**
* Check if this Mod has updates available on the mods index. If * Check if this Mod has updates available on the mods index. If
@ -189,12 +175,6 @@ namespace geode {
std::vector<std::string> getSettingKeys() const; std::vector<std::string> getSettingKeys() const;
bool hasSetting(std::string_view const key) const; bool hasSetting(std::string_view const key) const;
// todo in v4: remove these
[[deprecated("Use Mod::getSettingV3")]]
std::optional<Setting> getSettingDefinition(std::string_view const key) const;
[[deprecated("Use Mod::getSettingV3")]]
SettingValue* getSetting(std::string_view const key) const;
// todo in v4: possibly rename this to getSetting? // todo in v4: possibly rename this to getSetting?
/** /**
* Get the definition of a setting, or null if the setting was not found, * Get the definition of a setting, or null if the setting was not found,
@ -204,36 +184,6 @@ namespace geode {
*/ */
std::shared_ptr<SettingV3> getSettingV3(std::string_view const key) const; std::shared_ptr<SettingV3> getSettingV3(std::string_view const key) const;
/**
* Register a custom setting's value class. See Mod::addCustomSetting
* for a convenience wrapper that creates the value in-place to avoid
* code duplication. Also see
* [the tutorial page](https://docs.geode-sdk.org/mods/settings) for
* more information about custom settings
* @param key The setting's key
* @param value The SettingValue class that shall handle this setting
* @see addCustomSetting
*/
[[deprecated("Use Mod::registerCustomSettingType")]]
void registerCustomSetting(std::string_view const key, std::unique_ptr<SettingValue> value);
/**
* Register a custom setting's value class. The new SettingValue class
* will be created in-place using `std::make_unique`. See
* [the tutorial page](https://docs.geode-sdk.org/mods/settings) for
* more information about custom settings
* @param key The setting's key
* @param value The value of the custom setting
* @example
* $on_mod(Loaded) {
* Mod::get()->addCustomSetting<MySettingValue>("setting-key", DEFAULT_VALUE);
* }
*/
template <class T, class V>
[[deprecated("Use Mod::registerCustomSettingType")]]
void addCustomSetting(std::string_view const key, V const& value) {
this->registerCustomSetting(key, std::make_unique<T>(std::string(key), this->getID(), value));
}
/** /**
* Register a custom setting type. See * Register a custom setting type. See
* [the setting docs](https://docs.geode-sdk.org/mods/settings) for more * [the setting docs](https://docs.geode-sdk.org/mods/settings) for more

View file

@ -2,7 +2,6 @@
#include "../utils/Result.hpp" #include "../utils/Result.hpp"
#include "../utils/VersionInfo.hpp" #include "../utils/VersionInfo.hpp"
#include "Setting.hpp"
#include "Types.hpp" #include "Types.hpp"
#include <matjson.hpp> #include <matjson.hpp>
@ -123,13 +122,6 @@ namespace geode {
* character set. * character set.
*/ */
[[nodiscard]] std::string getName() const; [[nodiscard]] std::string getName() const;
/**
* The name of the head developer.
* If the mod has multiple * developers, this will return the first
* developer in the list.
*/
[[nodiscard, deprecated("Use ModMetadata::getDevelopers() instead")]]
std::string getDeveloper() const;
/** /**
* The developers of this mod * The developers of this mod
*/ */
@ -155,11 +147,6 @@ namespace geode {
* (see MDTextArea for more info) * (see MDTextArea for more info)
*/ */
[[nodiscard]] std::optional<std::string> getSupportInfo() const; [[nodiscard]] std::optional<std::string> getSupportInfo() const;
/**
* Git Repository of the mod
*/
[[nodiscard, deprecated("Use ModMetadata::getLinks instead")]]
std::optional<std::string> getRepository() const;
/** /**
* Get the links (related websites / servers / etc.) for this mod * Get the links (related websites / servers / etc.) for this mod
*/ */
@ -180,11 +167,6 @@ namespace geode {
* Mod spritesheet names * Mod spritesheet names
*/ */
[[nodiscard]] std::vector<std::string> getSpritesheets() const; [[nodiscard]] std::vector<std::string> getSpritesheets() const;
/**
* Mod settings
* @note Not a map because insertion order must be preserved
*/
[[nodiscard, deprecated("Use getSettingsV3")]] std::vector<std::pair<std::string, Setting>> getSettings() const;
/** /**
* Mod settings * Mod settings
* @note Not a map because insertion order must be preserved * @note Not a map because insertion order must be preserved
@ -237,8 +219,6 @@ namespace geode {
void setDependencies(std::vector<Dependency> const& value); void setDependencies(std::vector<Dependency> const& value);
void setIncompatibilities(std::vector<Incompatibility> const& value); void setIncompatibilities(std::vector<Incompatibility> const& value);
void setSpritesheets(std::vector<std::string> const& value); void setSpritesheets(std::vector<std::string> const& value);
[[deprecated("This function does NOTHING")]]
void setSettings(std::vector<std::pair<std::string, Setting>> const& value);
void setSettings(std::vector<std::pair<std::string, matjson::Value>> const& value); void setSettings(std::vector<std::pair<std::string, matjson::Value>> const& value);
void setTags(std::unordered_set<std::string> const& value); void setTags(std::unordered_set<std::string> const& value);
void setNeedsEarlyLoad(bool const& value); void setNeedsEarlyLoad(bool const& value);

View file

@ -1,324 +0,0 @@
#pragma once
#include "Types.hpp"
#include "../DefaultInclude.hpp"
#include "../utils/Result.hpp"
#include "../utils/file.hpp"
#include <matjson.hpp>
#include <optional>
#include <unordered_set>
#include <cocos2d.h>
#pragma warning(push)
#pragma warning(disable : 4275)
namespace geode {
class SettingNode;
class SettingValue;
struct JsonMaybeObject;
struct JsonMaybeValue;
/**
* A Setting for a boolean value. Represented in-game as a simple toggle
*/
struct GEODE_DLL BoolSetting final {
using ValueType = bool;
std::optional<std::string> name;
std::optional<std::string> description;
bool defaultValue;
static Result<BoolSetting> parse(JsonMaybeObject& obj);
};
/**
* A Setting for an integer value. The value can be limited using the min
* and max options
*/
struct GEODE_DLL IntSetting final {
using ValueType = int64_t;
std::optional<std::string> name;
std::optional<std::string> description;
ValueType defaultValue;
std::optional<ValueType> min;
std::optional<ValueType> max;
struct {
bool arrows = true;
bool bigArrows = false;
size_t arrowStep = 1;
size_t bigArrowStep = 5;
bool slider = true;
std::optional<ValueType> sliderStep = std::nullopt;
bool input = true;
} controls;
static Result<IntSetting> parse(JsonMaybeObject& obj);
};
/**
* A Setting for a float value. The value can be limited using the min
* and max options
*/
struct GEODE_DLL FloatSetting final {
using ValueType = double;
std::optional<std::string> name;
std::optional<std::string> description;
ValueType defaultValue;
std::optional<ValueType> min;
std::optional<ValueType> max;
struct {
bool arrows = true;
bool bigArrows = false;
size_t arrowStep = 1;
size_t bigArrowStep = 5;
bool slider = true;
std::optional<ValueType> sliderStep = std::nullopt;
bool input = true;
} controls;
static Result<FloatSetting> parse(JsonMaybeObject& obj);
};
/**
* A Setting for a string value
*/
struct GEODE_DLL StringSetting final {
using ValueType = std::string;
std::optional<std::string> name;
std::optional<std::string> description;
ValueType defaultValue;
struct Data {
/**
* A regex the string must successfully match against
*/
std::optional<std::string> match;
/**
* The CCTextInputNode's allowed character filter
*/
std::optional<std::string> filter;
/**
* A list of options the user can choose from
*/
std::optional<std::vector<std::string>> options;
};
std::unique_ptr<Data> controls;
std::array<uint8_t, sizeof(Data::match) + sizeof(Data::filter) - sizeof(controls)> m_padding;
StringSetting();
StringSetting(StringSetting const& other);
StringSetting(StringSetting&& other) noexcept;
StringSetting& operator=(StringSetting const& other);
StringSetting& operator=(StringSetting&& other) noexcept;
~StringSetting();
static Result<StringSetting> parse(JsonMaybeObject& obj);
};
/**
* A Setting for a file input. Lets the user select a file from their
* local device
*/
struct GEODE_DLL FileSetting final {
using ValueType = std::filesystem::path;
using Filter = utils::file::FilePickOptions::Filter;
std::optional<std::string> name;
std::optional<std::string> description;
ValueType defaultValue;
struct {
std::vector<Filter> filters;
} controls;
static Result<FileSetting> parse(JsonMaybeObject& obj);
};
/**
* A Setting for an RGB color. See ColorAlphaSetting for a setting that
* also allows customizing alpha
*/
struct GEODE_DLL ColorSetting final {
using ValueType = cocos2d::ccColor3B;
std::optional<std::string> name;
std::optional<std::string> description;
ValueType defaultValue;
static Result<ColorSetting> parse(JsonMaybeObject& obj);
};
/**
* A Setting for an RGBA color. See ColorSetting for a setting that doesn't
* have alpha
*/
struct GEODE_DLL ColorAlphaSetting final {
using ValueType = cocos2d::ccColor4B;
std::optional<std::string> name;
std::optional<std::string> description;
ValueType defaultValue;
static Result<ColorAlphaSetting> parse(JsonMaybeObject& obj);
};
/**
* A custom setting, defined by the mod. See
* [the tutorial page](https://docs.geode-sdk.org/mods/settings) for more
* information about how to create custom settings
*/
struct GEODE_DLL CustomSetting final {
std::shared_ptr<ModJson> json;
};
using SettingKind = std::variant<
BoolSetting,
IntSetting,
FloatSetting,
StringSetting,
FileSetting,
ColorSetting,
ColorAlphaSetting,
CustomSetting
>;
/**
* Represents a saved value for a mod that can be customized by the user
* through an in-game UI. This class is for modeling the setting's
* definition - what values are accepted, its name etc.
* See [the tutorial page](https://docs.geode-sdk.org/mods/settings)
* for more information about how settings work
* @see SettingValue
* @see SettingNode
*/
struct GEODE_DLL Setting final {
private:
std::string m_key;
std::string m_modID;
SettingKind m_kind;
Setting() = default;
public:
static Result<Setting> parse(
std::string const& key,
std::string const& mod,
JsonMaybeValue& obj
);
Setting(
std::string const& key,
std::string const& mod,
SettingKind const& kind
);
template<class T>
std::optional<T> get() {
if (std::holds_alternative<T>(m_kind)) {
return std::get<T>(m_kind);
}
return std::nullopt;
}
std::unique_ptr<SettingValue> createDefaultValue() const;
bool isCustom() const;
std::string getDisplayName() const;
std::optional<std::string> getDescription() const;
std::string getModID() const;
};
/**
* Stores the actual, current value of a Setting. See
* [the tutorial page](https://docs.geode-sdk.org/mods/settings) for more
* information, and how to create custom settings
*/
class GEODE_DLL SettingValue {
protected:
std::string m_key;
std::string m_modID;
SettingValue(std::string const& key, std::string const& mod);
void valueChanged();
public:
virtual ~SettingValue() = default;
virtual bool load(matjson::Value const& json) = 0;
virtual bool save(matjson::Value& json) const = 0;
virtual SettingNode* createNode(float width) = 0;
std::string getKey() const;
std::string getModID() const;
};
template<class T>
class GeodeSettingValue final : public SettingValue {
public:
using ValueType = typename T::ValueType;
protected:
ValueType m_value;
T m_definition;
using Valid = std::pair<ValueType, std::optional<std::string>>;
GEODE_DLL Valid toValid(ValueType const& value) const;
public:
GeodeSettingValue(std::string const& key, std::string const& modID, T const& definition)
: SettingValue(key, modID),
m_definition(definition),
m_value(definition.defaultValue) {}
bool load(matjson::Value const& json) override;
bool save(matjson::Value& json) const;
GEODE_DLL SettingNode* createNode(float width) override;
T castDefinition() const {
return m_definition;
}
Setting getDefinition() const {
return Setting(m_key, m_modID, m_definition);
}
GEODE_DLL ValueType getValue() const;
GEODE_DLL void setValue(ValueType const& value);
GEODE_DLL Result<> validate(ValueType const& value) const;
};
using BoolSettingValue = GeodeSettingValue<BoolSetting>;
using IntSettingValue = GeodeSettingValue<IntSetting>;
using FloatSettingValue = GeodeSettingValue<FloatSetting>;
using StringSettingValue = GeodeSettingValue<StringSetting>;
using FileSettingValue = GeodeSettingValue<FileSetting>;
using ColorSettingValue = GeodeSettingValue<ColorSetting>;
using ColorAlphaSettingValue = GeodeSettingValue<ColorAlphaSetting>;
// todo: remove in v3
template<class T>
struct [[deprecated("Use SettingTypeForValueType from SettingV3 instead")]] GEODE_DLL SettingValueSetter {
static T get(SettingValue* setting);
static void set(SettingValue* setting, T const& value);
};
template<class T>
bool GeodeSettingValue<T>::load(matjson::Value const& json) {
if (!json.is<ValueType>()) return false;
m_value = json.as<ValueType>();
return true;
}
template<class T>
bool GeodeSettingValue<T>::save(matjson::Value& json) const {
json = m_value;
return true;
}
}
#pragma warning(pop)

View file

@ -1,63 +0,0 @@
#pragma once
#include "Event.hpp"
#include "Loader.hpp"
#include "Setting.hpp"
#include "Mod.hpp"
#include "SettingV3.hpp"
#include <optional>
namespace geode {
struct GEODE_DLL [[deprecated("Use SettingChangedEventV3 from SettingV3.hpp instead")]] SettingChangedEvent : public Event {
Mod* mod;
SettingValue* value;
SettingChangedEvent(Mod* mod, SettingValue* value);
};
class GEODE_DLL [[deprecated("Use SettingChangedEventV3 from SettingV3.hpp instead")]] SettingChangedFilter : public EventFilter<SettingChangedEvent> {
protected:
std::string m_modID;
std::optional<std::string> m_targetKey;
public:
using Callback = void(SettingValue*);
ListenerResult handle(utils::MiniFunction<Callback> fn, SettingChangedEvent* event);
/**
* Listen to changes on a setting, or all settings
* @param modID Mod whose settings to listen to
* @param settingID Setting to listen to, or all settings if nullopt
*/
SettingChangedFilter(
std::string const& modID,
std::optional<std::string> const& settingKey
);
SettingChangedFilter(SettingChangedFilter const&) = default;
};
/**
* Listen for built-in setting changes
*/
template<class T>
class [[deprecated("Use SettingChangedEventV3 from SettingV3.hpp instead")]] GeodeSettingChangedFilter : public SettingChangedFilter {
public:
using Callback = void(T);
ListenerResult handle(utils::MiniFunction<Callback> fn, SettingChangedEvent* event) {
if (
m_modID == event->mod->getID() &&
(!m_targetKey || m_targetKey.value() == event->value->getKey())
) {
fn(SettingValueSetter<T>::get(event->value));
}
return ListenerResult::Propagate;
}
GeodeSettingChangedFilter(
std::string const& modID,
std::string const& settingID
) : SettingChangedFilter(modID, settingID) {}
GeodeSettingChangedFilter(GeodeSettingChangedFilter const&) = default;
};
}

View file

@ -1,32 +0,0 @@
#pragma once
#include "Setting.hpp"
#include <cocos2d.h>
namespace geode {
class SettingNode;
struct SettingNodeDelegate {
virtual void settingValueChanged(SettingNode* node) {}
virtual void settingValueCommitted(SettingNode* node) {}
};
class GEODE_DLL SettingNode : public cocos2d::CCNode {
protected:
SettingValue* m_value;
SettingNodeDelegate* m_delegate = nullptr;
bool init(SettingValue* value);
void dispatchChanged();
void dispatchCommitted();
public:
void setDelegate(SettingNodeDelegate* delegate);
virtual void commit() = 0;
virtual bool hasUncommittedChanges() = 0;
virtual bool hasNonDefaultValue() = 0;
virtual void resetToDefault() = 0;
};
}

View file

@ -3,15 +3,12 @@
#include "../DefaultInclude.hpp" #include "../DefaultInclude.hpp"
#include <optional> #include <optional>
#include <cocos2d.h> #include <cocos2d.h>
// todo: remove this header in 4.0.0
#include "Setting.hpp"
#include "../utils/cocos.hpp" #include "../utils/cocos.hpp"
#include "../utils/file.hpp"
// this unfortunately has to be included because of C++ templates // this unfortunately has to be included because of C++ templates
#include "../utils/JsonValidation.hpp" #include "../utils/JsonValidation.hpp"
#include "../utils/function.hpp" #include "../utils/function.hpp"
// todo in v4: this can be removed as well as the friend decl in LegacyCustomSettingV3
class LegacyCustomSettingToV3Node;
class ModSettingsPopup; class ModSettingsPopup;
namespace geode { namespace geode {
@ -183,17 +180,6 @@ namespace geode {
* Reset this setting's value back to its original value * Reset this setting's value back to its original value
*/ */
virtual void reset() = 0; virtual void reset() = 0;
[[deprecated(
"This function will be removed alongside legacy settings in 4.0.0! "
"You should NOT be implementing it for your own custom setting classes"
)]]
virtual std::optional<Setting> convertToLegacy() const;
[[deprecated(
"This function will be removed alongside legacy settings in 4.0.0! "
"You should NOT be implementing it for your own custom setting classes"
)]]
virtual std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const;
}; };
using SettingGenerator = std::function<Result<std::shared_ptr<SettingV3>>( using SettingGenerator = std::function<Result<std::shared_ptr<SettingV3>>(
@ -357,37 +343,6 @@ namespace geode {
void reset() override; void reset() override;
}; };
// todo in v4: remove this class completely
class GEODE_DLL LegacyCustomSettingV3 final : public SettingV3 {
private:
class Impl;
std::shared_ptr<Impl> m_impl;
friend class ::geode::ModSettingsManager;
friend class ::LegacyCustomSettingToV3Node;
private:
class PrivateMarker {};
friend class SettingV3;
public:
LegacyCustomSettingV3(PrivateMarker);
static Result<std::shared_ptr<LegacyCustomSettingV3>> parse(std::string const& key, std::string const& modID, matjson::Value const& json);
std::shared_ptr<SettingValue> getValue() const;
void setValue(std::shared_ptr<SettingValue> value);
bool load(matjson::Value const& json) override;
bool save(matjson::Value& json) const override;
SettingNodeV3* createNode(float width) override;
bool isDefaultValue() const override;
void reset() override;
std::optional<Setting> convertToLegacy() const override;
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
};
class GEODE_DLL BoolSettingV3 final : public SettingBaseValueV3<bool> { class GEODE_DLL BoolSettingV3 final : public SettingBaseValueV3<bool> {
private: private:
class Impl; class Impl;
@ -404,9 +359,6 @@ namespace geode {
Result<> isValid(bool value) const override; Result<> isValid(bool value) const override;
SettingNodeV3* createNode(float width) override; SettingNodeV3* createNode(float width) override;
std::optional<Setting> convertToLegacy() const override;
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
}; };
class GEODE_DLL IntSettingV3 final : public SettingBaseValueV3<int64_t> { class GEODE_DLL IntSettingV3 final : public SettingBaseValueV3<int64_t> {
@ -436,9 +388,6 @@ namespace geode {
bool isInputEnabled() const; bool isInputEnabled() const;
SettingNodeV3* createNode(float width) override; SettingNodeV3* createNode(float width) override;
std::optional<Setting> convertToLegacy() const override;
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
}; };
class GEODE_DLL FloatSettingV3 final : public SettingBaseValueV3<double> { class GEODE_DLL FloatSettingV3 final : public SettingBaseValueV3<double> {
@ -468,9 +417,6 @@ namespace geode {
bool isInputEnabled() const; bool isInputEnabled() const;
SettingNodeV3* createNode(float width) override; SettingNodeV3* createNode(float width) override;
std::optional<Setting> convertToLegacy() const override;
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
}; };
class GEODE_DLL StringSettingV3 final : public SettingBaseValueV3<std::string, std::string_view> { class GEODE_DLL StringSettingV3 final : public SettingBaseValueV3<std::string, std::string_view> {
@ -493,9 +439,6 @@ namespace geode {
std::optional<std::vector<std::string>> getEnumOptions() const; std::optional<std::vector<std::string>> getEnumOptions() const;
SettingNodeV3* createNode(float width) override; SettingNodeV3* createNode(float width) override;
std::optional<Setting> convertToLegacy() const override;
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
}; };
class GEODE_DLL FileSettingV3 final : public SettingBaseValueV3<std::filesystem::path, std::filesystem::path const&> { class GEODE_DLL FileSettingV3 final : public SettingBaseValueV3<std::filesystem::path, std::filesystem::path const&> {
@ -519,9 +462,6 @@ namespace geode {
std::optional<std::vector<utils::file::FilePickOptions::Filter>> getFilters() const; std::optional<std::vector<utils::file::FilePickOptions::Filter>> getFilters() const;
SettingNodeV3* createNode(float width) override; SettingNodeV3* createNode(float width) override;
std::optional<Setting> convertToLegacy() const override;
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
}; };
class GEODE_DLL Color3BSettingV3 final : public SettingBaseValueV3<cocos2d::ccColor3B> { class GEODE_DLL Color3BSettingV3 final : public SettingBaseValueV3<cocos2d::ccColor3B> {
@ -540,9 +480,6 @@ namespace geode {
Result<> isValid(cocos2d::ccColor3B value) const override; Result<> isValid(cocos2d::ccColor3B value) const override;
SettingNodeV3* createNode(float width) override; SettingNodeV3* createNode(float width) override;
std::optional<Setting> convertToLegacy() const override;
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
}; };
class GEODE_DLL Color4BSettingV3 final : public SettingBaseValueV3<cocos2d::ccColor4B> { class GEODE_DLL Color4BSettingV3 final : public SettingBaseValueV3<cocos2d::ccColor4B> {
@ -561,9 +498,6 @@ namespace geode {
Result<> isValid(cocos2d::ccColor4B value) const override; Result<> isValid(cocos2d::ccColor4B value) const override;
SettingNodeV3* createNode(float width) override; SettingNodeV3* createNode(float width) override;
std::optional<Setting> convertToLegacy() const override;
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
}; };
class GEODE_DLL SettingNodeV3 : public cocos2d::CCNode { class GEODE_DLL SettingNodeV3 : public cocos2d::CCNode {

View file

@ -133,11 +133,6 @@ namespace geode {
*/ */
GEODE_DLL void openSupportPopup(Mod* mod); GEODE_DLL void openSupportPopup(Mod* mod);
GEODE_DLL void openSupportPopup(ModMetadata const& metadata); GEODE_DLL void openSupportPopup(ModMetadata const& metadata);
/**
* Open the store page for a mod (if it exists)
*/
[[deprecated("Will be removed, use openInfoPopup instead")]]
GEODE_DLL void openIndexPopup(Mod* mod);
/** /**
* Open the settings popup for a mod (if it has any settings) * Open the settings popup for a mod (if it has any settings)
*/ */

View file

@ -1,41 +0,0 @@
#pragma once
#include <Geode/DefaultInclude.hpp>
#include <Geode/binding/CCTextInputNode.hpp>
#include <cocos2d.h>
namespace geode {
class GEODE_DLL InputNode : public cocos2d::CCMenuItem {
protected:
cocos2d::extension::CCScale9Sprite* m_bgSprite;
CCTextInputNode* m_input;
bool init(float, float, char const*, char const*, std::string const&, int);
bool init(float, char const*, char const*, std::string const&, int);
public:
[[deprecated("Use geode::TextInput from the ui/TextInput.hpp header instead")]]
static InputNode* create(
float width, char const* placeholder, char const* fontFile, std::string const& filter,
int limit
);
[[deprecated("Use geode::TextInput from the ui/TextInput.hpp header instead")]]
static InputNode* create(
float width, char const* placeholder, std::string const& filter, int limit
);
[[deprecated("Use geode::TextInput from the ui/TextInput.hpp header instead")]]
static InputNode* create(float width, char const* placeholder, std::string const& filter);
[[deprecated("Use geode::TextInput from the ui/TextInput.hpp header instead")]]
static InputNode* create(float width, char const* placeholder, char const* fontFile);
[[deprecated("Use geode::TextInput from the ui/TextInput.hpp header instead")]]
static InputNode* create(float width, char const* placeholder);
CCTextInputNode* getInput() const;
cocos2d::extension::CCScale9Sprite* getBG() const;
void setEnabled(bool enabled) override;
void setString(std::string const&);
std::string getString();
};
}

View file

@ -1,448 +1,430 @@
#pragma once #pragma once
#include "../include/ccMacros.h" #include <cocos2d.h>
#include "../cocoa/CCAffineTransform.h" #include <Geode/platform/platform.hpp>
#include "../cocoa/CCArray.h" #include <optional>
#include <Geode/platform/platform.hpp> #include <memory>
#include <optional>
#include <memory> namespace geode {
NS_CC_BEGIN #pragma warning(push)
#pragma warning(disable: 4275)
class CCNode;
/**
#pragma warning(push) * Layouts automatically handle the positioning of nodes. Use CCNode::setLayout
#pragma warning(disable: 4275) * to apply a layout to a node, and then use CCNode::updateLayout to apply
* the layout's positioning. Geode comes with a few default layouts like
/** * RowLayout, ColumnLayout, and GridLayout, but if you need a different kind
* Layouts automatically handle the positioning of nodes. Use CCNode::setLayout * of layout you can inherit from the Layout class.
* to apply a layout to a node, and then use CCNode::updateLayout to apply */
* the layout's positioning. Geode comes with a few default layouts like class GEODE_DLL Layout : public cocos2d::CCObject {
* RowLayout, ColumnLayout, and GridLayout, but if you need a different kind protected:
* of layout you can inherit from the Layout class. cocos2d::CCArray* getNodesToPosition(cocos2d::CCNode* forNode) const;
*/
class GEODE_DLL Layout : public CCObject { bool m_ignoreInvisibleChildren = false;
protected:
CCArray* getNodesToPosition(CCNode* forNode) const; public:
/**
bool m_ignoreInvisibleChildren = false; * Automatically apply the layout's positioning on a set of nodes
* @param on Node to apply the layout on. Position's the node's children
public: * 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
* Automatically apply the layout's positioning on a set of nodes * rescaled to better fit its contents
* @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 virtual void apply(cocos2d::CCNode* on) = 0;
* respected as a boundary the layout shouldn't overflow. The node may be
* rescaled to better fit its contents /**
*/ * Get how much space this layout would like to take up for a given target
virtual void apply(CCNode* on) = 0; */
virtual cocos2d::CCSize getSizeHint(cocos2d::CCNode* on) const = 0;
/**
* Get how much space this layout would like to take up for a given target void ignoreInvisibleChildren(bool ignore);
*/ bool isIgnoreInvisibleChildren() const;
virtual CCSize getSizeHint(CCNode* on) const = 0;
virtual ~Layout() = default;
void ignoreInvisibleChildren(bool ignore); };
bool isIgnoreInvisibleChildren() const;
class GEODE_DLL LayoutOptions : public cocos2d::CCObject {
virtual ~Layout() = default; public:
}; virtual ~LayoutOptions() = default;
};
class GEODE_DLL LayoutOptions : public CCObject {
public: /**
virtual ~LayoutOptions() = default; * The direction of an AxisLayout
}; */
enum class Axis {
/** Row,
* The direction of an AxisLayout Column,
*/ };
enum class Axis {
Row, /**
Column, * Specifies the alignment of something in an AxisLayout
}; */
enum class AxisAlignment {
/** // Align items to the start
* Specifies the alignment of something in an AxisLayout // |ooo......|
*/ Start,
enum class AxisAlignment { // All items are centered
// Align items to the start // |...ooo...|
// |ooo......| Center,
Start, // Align items to the end
// All items are centered // |......ooo|
// |...ooo...| End,
Center, // Each item gets the same portion from the layout (disregards gap)
// Align items to the end // |.o..o..o.|
// |......ooo| Even,
End, // Space between each item is the same (disregards gap)
// Each item gets the same portion from the layout (disregards gap) // |o...o...o|
// |.o..o..o.| Between,
Even, };
// Space between each item is the same (disregards gap)
// |o...o...o| constexpr float AXISLAYOUT_DEFAULT_MIN_SCALE = 0.65f;
Between, constexpr int AXISLAYOUT_DEFAULT_PRIORITY = 0;
};
/**
constexpr float AXISLAYOUT_DEFAULT_MIN_SCALE = 0.65f; * Options for controlling the behaviour of individual nodes in an AxisLayout
constexpr int AXISLAYOUT_DEFAULT_PRIORITY = 0; * @example
* auto node = CCNode::create();
/** * // this node will have 10 units of spacing between it and the next one
* Options for controlling the behaviour of individual nodes in an AxisLayout * node->setLayoutOptions(
* @example * AxisLayoutOptions::create()
* auto node = CCNode::create(); * ->setNextGap(10.f)
* // this node will have 10 units of spacing between it and the next one * );
* node->setLayoutOptions( * someNodeWithALayout->addChild(node);
* AxisLayoutOptions::create() */
* ->setNextGap(10.f) class GEODE_DLL AxisLayoutOptions : public LayoutOptions {
* ); protected:
* someNodeWithALayout->addChild(node); class Impl;
*/
class GEODE_DLL AxisLayoutOptions : public LayoutOptions { std::unique_ptr<Impl> m_impl;
protected:
class Impl; AxisLayoutOptions();
std::unique_ptr<Impl> m_impl; public:
static AxisLayoutOptions* create();
AxisLayoutOptions();
virtual ~AxisLayoutOptions();
public:
static AxisLayoutOptions* create(); std::optional<bool> getAutoScale() const;
// @note Use hasExplicitMaxScale to know if the default scale has been overwritten
virtual ~AxisLayoutOptions(); float getMaxScale() const;
// @note Use hasExplicitMinScale to know if the default scale has been overwritten
std::optional<bool> getAutoScale() const; float getMinScale() const;
// @note Use hasExplicitMaxScale to know if the default scale has been overwritten bool hasExplicitMaxScale() const;
float getMaxScale() const; bool hasExplicitMinScale() const;
// @note Use hasExplicitMinScale to know if the default scale has been overwritten float getRelativeScale() const;
float getMinScale() const; std::optional<float> getLength() const;
bool hasExplicitMaxScale() const; std::optional<float> getPrevGap() const;
bool hasExplicitMinScale() const; std::optional<float> getNextGap() const;
float getRelativeScale() const; bool getBreakLine() const;
std::optional<float> getLength() const; bool getSameLine() const;
std::optional<float> getPrevGap() const; int getScalePriority() const;
std::optional<float> getNextGap() const; std::optional<AxisAlignment> getCrossAxisAlignment() const;
bool getBreakLine() const;
bool getSameLine() const; /**
int getScalePriority() const; * Set the limits to what the node can be scaled to. Passing `std::nullopt`
std::optional<AxisAlignment> getCrossAxisAlignment() const; * uses the parent layout's default min / max scales
*/
/** AxisLayoutOptions* setScaleLimits(std::optional<float> min, std::optional<float> max);
* Set the maximum scale this node can be if it's contained in an
* auto-scaled layout. Default is 1 /**
*/ * Set the relative scale of this node compared to other nodes if it's
[[deprecated("Use AxisLayoutOptions::setScaleLimits")]] * contained in an auto-scaled layout. Default is 1
AxisLayoutOptions* setMaxScale(float scale); */
AxisLayoutOptions* setRelativeScale(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 * Set auto-scaling for this node, overriding the layout's auto-scale
*/ * setting. If nullopt, the layout's auto-scale options will be used
[[deprecated("Use AxisLayoutOptions::setScaleLimits")]] */
AxisLayoutOptions* setMinScale(float scale); AxisLayoutOptions* setAutoScale(std::optional<bool> enabled);
/** /**
* Set the limits to what the node can be scaled to. Passing `std::nullopt` * Set an absolute length for this node. If nullopt, the length will be
* uses the parent layout's default min / max scales * dynamically calculated based on content size
*/ */
AxisLayoutOptions* setScaleLimits(std::optional<float> min, std::optional<float> max); AxisLayoutOptions* setLength(std::optional<float> length);
/** /**
* Set the relative scale of this node compared to other nodes if it's * Override the default gap in the layout between this node and the
* contained in an auto-scaled layout. Default is 1 * previous one. If nullopt, the default gap of the layout will be used
*/ */
AxisLayoutOptions* setRelativeScale(float scale); AxisLayoutOptions* setPrevGap(std::optional<float> gap);
/** /**
* Set auto-scaling for this node, overriding the layout's auto-scale * Override the default gap in the layout between this node and the next
* setting. If nullopt, the layout's auto-scale options will be used * one. If nullopt, the default gap of the layout will be used
*/ */
AxisLayoutOptions* setAutoScale(std::optional<bool> enabled); AxisLayoutOptions* setNextGap(std::optional<float> gap);
/** /**
* Set an absolute length for this node. If nullopt, the length will be * If enabled, the node will always cause a growable axis layout to break
* dynamically calculated based on content size * into a new line even if the current line could've fit the next node
*/ */
AxisLayoutOptions* setLength(std::optional<float> length); AxisLayoutOptions* setBreakLine(bool enable);
/** /**
* Override the default gap in the layout between this node and the * If enabled, the node will be forced to be on the same line as the
* previous one. If nullopt, the default gap of the layout will be used * previous node even if doing this would overflow
*/ */
AxisLayoutOptions* setPrevGap(std::optional<float> gap); AxisLayoutOptions* setSameLine(bool enable);
/** /**
* Override the default gap in the layout between this node and the next * Set the scale priority of this node. Nodes with higher priority will be
* one. If nullopt, the default gap of the layout will be used * scaled down first before nodes with lower priority when an auto-scaled
*/ * layout attempts to fit its contents. Default is
AxisLayoutOptions* setNextGap(std::optional<float> gap); * AXISLAYOUT_DEFAULT_PRIORITY
* @note For optimal performance, the priorities should all be close to
/** * each other with no gaps
* 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* setScalePriority(int priority);
*/
AxisLayoutOptions* setBreakLine(bool enable); /**
* Override the cross axis alignment for this node in the layout
/** */
* If enabled, the node will be forced to be on the same line as the AxisLayoutOptions* setCrossAxisAlignment(std::optional<AxisAlignment> alignment);
* previous node even if doing this would overflow };
*/
AxisLayoutOptions* setSameLine(bool enable); /**
* 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
* Set the scale priority of this node. Nodes with higher priority will be * RowLayout and ColumnLayout classes function as simple thin wrappers over
* scaled down first before nodes with lower priority when an auto-scaled * AxisLayout. The positioning of individual nodes in the layout can be
* layout attempts to fit its contents. Default is * further controlled using AxisLayoutOptions
* AXISLAYOUT_DEFAULT_PRIORITY * @warning Calculating layouts can get increasingly expensive for large
* @note For optimal performance, the priorities should all be close to * amounts of child nodes being fit into a small space - while this should
* each other with no gaps * 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
AxisLayoutOptions* setScalePriority(int priority); * call CCNode::updateLayout every frame for a menu with thousands of children
* @example
/** * auto menu = CCMenu::create();
* Override the cross axis alignment for this node in the layout * // 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
AxisLayoutOptions* setCrossAxisAlignment(std::optional<AxisAlignment> alignment); * // aligned to the left. The menu automatically will automatically grow in
}; * // height to fit all the rows
* menu->setLayout(
/** * RowLayout::create()
* A multi-purpose dynamic layout for arranging nodes along an axis. Can be * ->setGap(10.f)
* used to arrange nodes in a single line, a grid, or a flex layout. The * ->setGrowCrossAxis(true)
* RowLayout and ColumnLayout classes function as simple thin wrappers over * ->setAxisAlignment(AxisAlignment::Start)
* AxisLayout. The positioning of individual nodes in the layout can be * );
* further controlled using AxisLayoutOptions * menu->setContentSize({ 200.f, 0.f });
* @warning Calculating layouts can get increasingly expensive for large * menu->addChild(...);
* amounts of child nodes being fit into a small space - while this should * menu->updateLayout();
* 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 class GEODE_DLL AxisLayout : public Layout {
* call CCNode::updateLayout every frame for a menu with thousands of children protected:
* @example class Impl;
* auto menu = CCMenu::create();
* // The menu's children will be arranged horizontally, unless they overflow std::unique_ptr<Impl> m_impl;
* // 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 AxisLayout(Axis);
* // height to fit all the rows
* menu->setLayout( public:
* RowLayout::create() /**
* ->setGap(10.f) * Create a new AxisLayout. Note that this class is not automatically
* ->setGrowCrossAxis(true) * managed by default, so you must assign it to a CCNode or manually
* ->setAxisAlignment(AxisAlignment::Start) * manage the memory yourself. See the chainable setters on AxisLayout for
* ); * what options you can customize for the layout
* menu->setContentSize({ 200.f, 0.f }); * @param axis The direction of the layout
* menu->addChild(...); * @note For convenience, you can use the RowLayout and ColumnLayout
* menu->updateLayout(); * classes, which are just thin wrappers over AxisLayout
*/ * @returns Created AxisLayout
class GEODE_DLL AxisLayout : public Layout { */
protected: static AxisLayout* create(Axis axis = Axis::Row);
class Impl;
virtual ~AxisLayout();
std::unique_ptr<Impl> m_impl;
void apply(cocos2d::CCNode* on) override;
AxisLayout(Axis); cocos2d::CCSize getSizeHint(cocos2d::CCNode* on) const override;
public: Axis getAxis() const;
/** AxisAlignment getAxisAlignment() const;
* Create a new AxisLayout. Note that this class is not automatically AxisAlignment getCrossAxisAlignment() const;
* managed by default, so you must assign it to a CCNode or manually AxisAlignment getCrossAxisLineAlignment() const;
* manage the memory yourself. See the chainable setters on AxisLayout for float getGap() const;
* what options you can customize for the layout bool getAxisReverse() const;
* @param axis The direction of the layout bool getCrossAxisReverse() const;
* @note For convenience, you can use the RowLayout and ColumnLayout bool getAutoScale() const;
* classes, which are just thin wrappers over AxisLayout bool getGrowCrossAxis() const;
* @returns Created AxisLayout bool getCrossAxisOverflow() const;
*/ std::optional<float> getAutoGrowAxis() const;
static AxisLayout* create(Axis axis = Axis::Row); float getDefaultMinScale() const;
float getDefaultMaxScale() const;
virtual ~AxisLayout();
AxisLayout* setAxis(Axis axis);
void apply(CCNode* on) override; /**
CCSize getSizeHint(CCNode* on) const override; * Sets where to align the target node's children on the main axis (X-axis
* for Row, Y-axis for Column)
Axis getAxis() const; */
AxisAlignment getAxisAlignment() const; AxisLayout* setAxisAlignment(AxisAlignment align);
AxisAlignment getCrossAxisAlignment() const; /**
AxisAlignment getCrossAxisLineAlignment() const; * Sets where to align the target node's children on the cross-axis (Y-axis
float getGap() const; * for Row, X-axis for Column)
bool getAxisReverse() const; */
bool getCrossAxisReverse() const; AxisLayout* setCrossAxisAlignment(AxisAlignment align);
bool getAutoScale() const; /**
bool getGrowCrossAxis() const; * Sets where to align the target node's children on the cross-axis for
bool getCrossAxisOverflow() const; * each row (Y-axis for Row, X-axis for Column)
std::optional<float> getAutoGrowAxis() const; */
float getDefaultMinScale() const; AxisLayout* setCrossAxisLineAlignment(AxisAlignment align);
float getDefaultMaxScale() const; /**
* The spacing between the children of the node this layout applies to.
AxisLayout* setAxis(Axis axis); * Measured as the space between their edges, not centres. Does not apply
/** * on the main / cross axis if their alignment is AxisAlignment::Even
* Sets where to align the target node's children on the main axis (X-axis */
* for Row, Y-axis for Column) AxisLayout* setGap(float gap);
*/ /**
AxisLayout* setAxisAlignment(AxisAlignment align); * Whether to reverse the direction of the children in this layout or not
/** */
* Sets where to align the target node's children on the cross-axis (Y-axis AxisLayout* setAxisReverse(bool reverse);
* for Row, X-axis for Column) /**
*/ * Whether to reverse the direction of the rows on the cross-axis or not
AxisLayout* setCrossAxisAlignment(AxisAlignment align); */
/** AxisLayout* setCrossAxisReverse(bool reverse);
* Sets where to align the target node's children on the cross-axis for /**
* each row (Y-axis for Row, X-axis for Column) * 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* setCrossAxisLineAlignment(AxisAlignment align); */
/** AxisLayout* setAutoScale(bool enable);
* The spacing between the children of the node this layout applies to. /**
* Measured as the space between their edges, not centres. Does not apply * If true, if the main axis overflows extra nodes will be placed on new
* on the main / cross axis if their alignment is AxisAlignment::Even * rows/columns on the cross-axis
*/ */
AxisLayout* setGap(float gap); AxisLayout* setGrowCrossAxis(bool expand);
/** /**
* Whether to reverse the direction of the children in this layout or not * If true, the cross-axis content size of the target node will be
*/ * automatically adjusted to fit the children
AxisLayout* setAxisReverse(bool reverse); */
/** AxisLayout* setCrossAxisOverflow(bool allow);
* Whether to reverse the direction of the rows on the cross-axis or not /**
*/ * If not `std::nullopt`, then the axis will be automatically extended to
AxisLayout* setCrossAxisReverse(bool reverse); * fit all items in a single row whose minimum length is the specified.
/** * Useful for scrollable list layer contents
* 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* setAutoGrowAxis(std::optional<float> allowAndMinLength);
*/ /**
AxisLayout* setAutoScale(bool enable); * Set the default minimum/maximum scales for nodes in the layout
/** */
* If true, if the main axis overflows extra nodes will be placed on new AxisLayout* setDefaultScaleLimits(float min, float max);
* rows/columns on the cross-axis };
*/
AxisLayout* setGrowCrossAxis(bool expand); /**
/** * Simple layout for arranging nodes in a row (horizontal line)
* If true, the cross-axis content size of the target node will be */
* automatically adjusted to fit the children class GEODE_DLL RowLayout : public AxisLayout {
*/ protected:
AxisLayout* setCrossAxisOverflow(bool allow); RowLayout();
/**
* If not `std::nullopt`, then the axis will be automatically extended to public:
* fit all items in a single row whose minimum length is the specified. /**
* Useful for scrollable list layer contents * Create a new RowLayout. See the chainable setters on RowLayout for
*/ * what options you can customize for the layout
AxisLayout* setAutoGrowAxis(std::optional<float> allowAndMinLength); * @returns Created RowLayout
/** */
* Set the default minimum/maximum scales for nodes in the layout static RowLayout* create();
*/ };
AxisLayout* setDefaultScaleLimits(float min, float max);
}; /**
* Simple layout for arranging nodes in a column (vertical line)
/** */
* Simple layout for arranging nodes in a row (horizontal line) class GEODE_DLL ColumnLayout : public AxisLayout {
*/ protected:
class GEODE_DLL RowLayout : public AxisLayout { ColumnLayout();
protected:
RowLayout(); public:
/**
public: * Create a new ColumnLayout. See the chainable setters on RowLayout for
/** * what options you can customize for the layout
* Create a new RowLayout. See the chainable setters on RowLayout for * @returns Created ColumnLayout
* what options you can customize for the layout */
* @returns Created RowLayout static ColumnLayout* create();
*/ };
static RowLayout* create();
}; /**
* The relative position of a node to its parent in an AnchorLayout
/** */
* Simple layout for arranging nodes in a column (vertical line) enum class Anchor {
*/ Center,
class GEODE_DLL ColumnLayout : public AxisLayout { TopLeft,
protected: Top,
ColumnLayout(); TopRight,
Right,
public: BottomRight,
/** Bottom,
* Create a new ColumnLayout. See the chainable setters on RowLayout for BottomLeft,
* what options you can customize for the layout Left,
* @returns Created ColumnLayout };
*/
static ColumnLayout* create(); /**
}; * Options for customizing a node's position in an AnchorLayout
*/
/** class GEODE_DLL AnchorLayoutOptions : public LayoutOptions {
* The relative position of a node to its parent in an AnchorLayout protected:
*/ Anchor m_anchor = Anchor::Center;
enum class Anchor { cocos2d::CCPoint m_offset = cocos2d::CCPointZero;
Center,
TopLeft, public:
Top, static AnchorLayoutOptions* create();
TopRight,
Right, Anchor getAnchor() const;
BottomRight, cocos2d::CCPoint getOffset() const;
Bottom,
BottomLeft, AnchorLayoutOptions* setAnchor(Anchor anchor);
Left, AnchorLayoutOptions* setOffset(cocos2d::CCPoint const& offset);
}; };
/** /**
* Options for customizing a node's position in an AnchorLayout * A layout for positioning nodes at specific positions relative to their
*/ * parent's content size. See `Anchor` for available anchoring options. Useful
class GEODE_DLL AnchorLayoutOptions : public LayoutOptions { * for example for popups, where a popup using `AnchorLayout` can be
protected: * automatically resized without needing to manually shuffle nodes around
Anchor m_anchor = Anchor::Center; */
CCPoint m_offset = CCPointZero; class GEODE_DLL AnchorLayout : public Layout {
public:
public: static AnchorLayout* create();
static AnchorLayoutOptions* create();
void apply(cocos2d::CCNode* on) override;
Anchor getAnchor() const; cocos2d::CCSize getSizeHint(cocos2d::CCNode* on) const override;
CCPoint getOffset() const;
/**
AnchorLayoutOptions* setAnchor(Anchor anchor); * Get a position according to anchoring rules, with the same algorithm as
AnchorLayoutOptions* setOffset(CCPoint const& offset); * `AnchorLayout` uses to position its nodes
}; * @param in The node whose content size to use as a reference
* @param anchor The anchor position
/** * @param offset Offset from the anchor
* A layout for positioning nodes at specific positions relative to their * @returns A position in `in` for the anchored and offsetted location
* parent's content size. See `Anchor` for available anchoring options. Useful */
* for example for popups, where a popup using `AnchorLayout` can be static cocos2d::CCPoint getAnchoredPosition(cocos2d::CCNode* in, Anchor anchor, cocos2d::CCPoint const& offset);
* automatically resized without needing to manually shuffle nodes around };
*/
class GEODE_DLL AnchorLayout : public Layout { /**
public: * A layout for automatically copying the content size of a node to other nodes.
static AnchorLayout* create(); * Basically main use case is for FLAlertLayers (setting the size of the
* background and `m_buttonMenu` based on `m_mainLayer`)
void apply(CCNode* on) override; */
CCSize getSizeHint(CCNode* on) const override; class GEODE_DLL CopySizeLayout : public AnchorLayout {
protected:
/** cocos2d::CCArray* m_targets;
* Get a position according to anchoring rules, with the same algorithm as
* `AnchorLayout` uses to position its nodes public:
* @param in The node whose content size to use as a reference static CopySizeLayout* create();
* @param anchor The anchor position virtual ~CopySizeLayout();
* @param offset Offset from the anchor
* @returns A position in `in` for the anchored and offsetted location /**
*/ * Add a target to be automatically resized. Any targets' layouts will
static CCPoint getAnchoredPosition(CCNode* in, Anchor anchor, CCPoint const& offset); * also be updated when this layout is updated
}; */
CopySizeLayout* add(cocos2d::CCNode* target);
/** /**
* A layout for automatically copying the content size of a node to other nodes. * Remove a target from being automatically resized
* Basically main use case is for FLAlertLayers (setting the size of the */
* background and `m_buttonMenu` based on `m_mainLayer`) CopySizeLayout* remove(cocos2d::CCNode* target);
*/
class GEODE_DLL CopySizeLayout : public cocos2d::AnchorLayout { void apply(cocos2d::CCNode* in) override;
protected: cocos2d::CCSize getSizeHint(cocos2d::CCNode* in) const override;
cocos2d::CCArray* m_targets; };
public: #pragma warning(pop)
static CopySizeLayout* create();
virtual ~CopySizeLayout(); }
/**
* Add a target to be automatically resized. Any targets' layouts will
* also be updated when this layout is updated
*/
CopySizeLayout* add(cocos2d::CCNode* target);
/**
* Remove a target from being automatically resized
*/
CopySizeLayout* remove(cocos2d::CCNode* target);
void apply(cocos2d::CCNode* in) override;
cocos2d::CCSize getSizeHint(cocos2d::CCNode* in) const override;
};
#pragma warning(pop)
NS_CC_END

View file

@ -4,6 +4,7 @@
#include <Geode/binding/FLAlertLayer.hpp> #include <Geode/binding/FLAlertLayer.hpp>
#include <Geode/utils/MiniFunction.hpp> #include <Geode/utils/MiniFunction.hpp>
#include <Geode/utils/cocos.hpp> #include <Geode/utils/cocos.hpp>
#include <Geode/ui/Layout.hpp>
namespace geode { namespace geode {
template <class... InitArgs> template <class... InitArgs>
@ -104,7 +105,7 @@ namespace geode {
m_mainLayer->setPosition(winSize / 2); m_mainLayer->setPosition(winSize / 2);
m_mainLayer->setContentSize(m_size); m_mainLayer->setContentSize(m_size);
m_mainLayer->setLayout( m_mainLayer->setLayout(
cocos2d::CopySizeLayout::create() geode::CopySizeLayout::create()
->add(m_buttonMenu) ->add(m_buttonMenu)
->add(m_bgSprite) ->add(m_bgSprite)
); );
@ -119,7 +120,7 @@ namespace geode {
closeSpr, this, (cocos2d::SEL_MenuHandler)(&Popup::onClose) closeSpr, this, (cocos2d::SEL_MenuHandler)(&Popup::onClose)
); );
if (dynamic) { if (dynamic) {
m_buttonMenu->addChildAtPosition(m_closeBtn, cocos2d::Anchor::TopLeft, { 3.f, -3.f }); m_buttonMenu->addChildAtPosition(m_closeBtn, geode::Anchor::TopLeft, { 3.f, -3.f });
} }
else { else {
m_closeBtn->setPosition(-m_size.width / 2 + 3.f, m_size.height / 2 - 3.f); m_closeBtn->setPosition(-m_size.width / 2 + 3.f, m_size.height / 2 - 3.f);
@ -137,14 +138,6 @@ namespace geode {
} }
protected: protected:
[[deprecated("Use Popup::initAnchored instead, as it has more reasonable menu and layer content sizes")]]
bool init(
float width, float height, InitArgs... args, char const* bg = "GJ_square01.png",
cocos2d::CCRect bgRect = { 0, 0, 80, 80 }
) {
return this->initBase(width, height, std::forward<InitArgs>(args)..., bg, bgRect, false);
}
/** /**
* Init with AnchorLayout and the content size of `m_buttonMenu` and * Init with AnchorLayout and the content size of `m_buttonMenu` and
* `m_bgSprite` being tied to the size of `m_mainLayer` (rather than * `m_bgSprite` being tied to the size of `m_mainLayer` (rather than
@ -185,7 +178,7 @@ namespace geode {
m_title = cocos2d::CCLabelBMFont::create(title.c_str(), font); m_title = cocos2d::CCLabelBMFont::create(title.c_str(), font);
m_title->setZOrder(2); m_title->setZOrder(2);
if (m_dynamic) { if (m_dynamic) {
m_mainLayer->addChildAtPosition(m_title, cocos2d::Anchor::Top, ccp(0, -offset)); m_mainLayer->addChildAtPosition(m_title, geode::Anchor::Top, ccp(0, -offset));
} }
else { else {
auto winSize = cocos2d::CCDirector::get()->getWinSize(); auto winSize = cocos2d::CCDirector::get()->getWinSize();

View file

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "CCNode.h" #include <cocos2d.h>
NS_CC_BEGIN namespace geode {
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4275) #pragma warning(disable: 4275)
@ -22,7 +22,7 @@ NS_CC_BEGIN
* @note If you want to specify a minimum width for a SpacerNode, add * @note If you want to specify a minimum width for a SpacerNode, add
* AxisLayoutOptions for it and use setLength * AxisLayoutOptions for it and use setLength
*/ */
class GEODE_DLL SpacerNode : public CCNode { class GEODE_DLL SpacerNode : public cocos2d::CCNode {
protected: protected:
size_t m_grow; size_t m_grow;
@ -61,9 +61,9 @@ public:
*/ */
class GEODE_DLL SpacerNodeChild : public SpacerNode { class GEODE_DLL SpacerNodeChild : public SpacerNode {
protected: protected:
CCNode* m_child = nullptr; cocos2d::CCNode* m_child = nullptr;
bool init(CCNode* child, size_t grow); bool init(cocos2d::CCNode* child, size_t grow);
public: public:
/** /**
@ -73,11 +73,11 @@ public:
* factors (akin to CSS flew grow) * factors (akin to CSS flew grow)
* @param grow The grow factor for this node. Default is 1 * @param grow The grow factor for this node. Default is 1
*/ */
static SpacerNodeChild* create(CCNode* child, size_t grow = 1); static SpacerNodeChild* create(cocos2d::CCNode* child, size_t grow = 1);
void setContentSize(CCSize const& size) override; void setContentSize(cocos2d::CCSize const& size) override;
}; };
#pragma warning(pop) #pragma warning(pop)
NS_CC_END }

View file

@ -78,226 +78,6 @@ namespace geode {
struct JsonMaybeObject; struct JsonMaybeObject;
struct JsonMaybeValue; struct JsonMaybeValue;
struct GEODE_DLL
[[deprecated("Use JsonExpectedValue via the checkJson function instead")]]
JsonMaybeSomething {
protected:
JsonChecker& m_checker;
matjson::Value& m_json;
std::string m_hierarchy;
bool m_hasValue;
friend struct JsonMaybeObject;
friend struct JsonMaybeValue;
void setError(std::string const& error);
public:
matjson::Value& json();
JsonMaybeSomething(
JsonChecker& checker, matjson::Value& json, std::string const& hierarchy, bool hasValue
);
bool isError() const;
std::string getError() const;
operator bool() const;
};
struct GEODE_DLL
[[deprecated("Use JsonExpectedValue via the checkJson function instead")]]
JsonMaybeValue : public JsonMaybeSomething {
bool m_inferType = true;
JsonMaybeValue(
JsonChecker& checker, matjson::Value& json, std::string const& hierarchy, bool hasValue
);
JsonMaybeSomething& self();
template <matjson::Type T>
JsonMaybeValue& as() {
if (this->isError()) return *this;
if (!jsonConvertibleTo(self().m_json.type(), T)) {
this->setError(
self().m_hierarchy + ": Invalid type \"" + jsonValueTypeToString(self().m_json.type()) +
"\", expected \"" + jsonValueTypeToString(T) + "\""
);
}
m_inferType = false;
return *this;
}
JsonMaybeValue& array();
template <matjson::Type... T>
JsonMaybeValue& asOneOf() {
if (this->isError()) return *this;
bool isOneOf = (... || jsonConvertibleTo(self().m_json.type(), T));
if (!isOneOf) {
this->setError(
self().m_hierarchy + ": Invalid type \"" + jsonValueTypeToString(self().m_json.type()) +
"\", expected one of \"" + (jsonValueTypeToString(T), ...) + "\""
);
}
m_inferType = false;
return *this;
}
template <class T>
bool is() {
if (this->isError()) return false;
return self().m_json.is<T>();
}
template <class T>
JsonMaybeValue& validate(JsonValueValidator<T> validator) {
if (this->isError()) return *this;
if (self().m_json.is<T>()) {
if (!validator(self().m_json.as<T>())) {
this->setError(self().m_hierarchy + ": Invalid value format");
}
}
else {
this->setError(
self().m_hierarchy + ": Invalid type \"" +
std::string(jsonValueTypeToString(self().m_json.type())) + "\""
);
}
return *this;
}
template <class T>
JsonMaybeValue& inferType() {
if (this->isError() || !m_inferType) return *this;
return this->as<getJsonType<T>()>();
}
template <class T>
JsonMaybeValue& intoRaw(T& target) {
if (this->isError()) return *this;
target = self().m_json;
return *this;
}
template <class T>
JsonMaybeValue& into(T& target) {
return this->intoAs<T, T>(target);
}
template <class T>
JsonMaybeValue& into(std::optional<T>& target) {
return this->intoAs<T, std::optional<T>>(target);
}
template <class A, class T>
JsonMaybeValue& intoAs(T& target) {
this->inferType<A>();
if (this->isError()) return *this;
if (self().m_json.is<A>()) {
try {
target = self().m_json.as<A>();
}
catch(matjson::JsonException const& e) {
this->setError(
self().m_hierarchy + ": Error parsing JSON: " + std::string(e.what())
);
}
}
else {
this->setError(
self().m_hierarchy + ": Invalid type \"" +
std::string(jsonValueTypeToString(self().m_json.type())) + "\""
);
}
return *this;
}
template <class T>
T get() {
this->inferType<T>();
if (this->isError()) return T();
if (self().m_json.is<T>()) {
return self().m_json.as<T>();
}
return T();
}
JsonMaybeObject obj();
template <class T>
struct Iterator {
std::vector<T> m_values;
using iterator = typename std::vector<T>::iterator;
using const_iterator = typename std::vector<T>::const_iterator;
iterator begin() {
return m_values.begin();
}
iterator end() {
return m_values.end();
}
const_iterator begin() const {
return m_values.begin();
}
const_iterator end() const {
return m_values.end();
}
};
JsonMaybeValue at(size_t i);
Iterator<JsonMaybeValue> iterate();
Iterator<std::pair<std::string, JsonMaybeValue>> items();
};
struct
[[deprecated("Use JsonExpectedValue via the checkJson function instead")]]
GEODE_DLL JsonMaybeObject : JsonMaybeSomething {
std::set<std::string> m_knownKeys;
JsonMaybeObject(
JsonChecker& checker, matjson::Value& json, std::string const& hierarchy, bool hasValue
);
JsonMaybeSomething& self();
void addKnownKey(std::string const& key);
matjson::Value& json();
JsonMaybeValue emptyValue();
JsonMaybeValue has(std::string const& key);
JsonMaybeValue needs(std::string const& key);
void checkUnknownKeys();
};
struct
[[deprecated("Use JsonExpectedValue via the checkJson function instead")]]
GEODE_DLL JsonChecker {
std::variant<std::monostate, std::string> m_result;
matjson::Value& m_json;
JsonChecker(matjson::Value& json);
bool isError() const;
std::string getError() const;
JsonMaybeValue root(std::string const& hierarchy);
};
class GEODE_DLL JsonExpectedValue final { class GEODE_DLL JsonExpectedValue final {
protected: protected:
class Impl; class Impl;

View file

@ -186,8 +186,6 @@ namespace geode {
std::tie(other.m_major, other.m_minor, other.m_patch, other.m_tag); std::tie(other.m_major, other.m_minor, other.m_patch, other.m_tag);
} }
[[deprecated("Use toNonVString or toVString instead")]]
std::string toString(bool includeTag = true) const;
std::string toVString(bool includeTag = true) const; std::string toVString(bool includeTag = true) const;
std::string toNonVString(bool includeTag = true) const; std::string toNonVString(bool includeTag = true) const;

View file

@ -615,18 +615,6 @@ namespace geode::cocos {
return static_cast<T*>(x->getChildren()->objectAtIndex(i)); return static_cast<T*>(x->getChildren()->objectAtIndex(i));
} }
/**
* Get nth child that is a given type. Checks bounds.
* @returns Child at index cast to the given type,
* or nullptr if index exceeds bounds
*/
template <class Type = cocos2d::CCNode>
[[deprecated("Use CCNode::getChildByType instead")]]
static Type* getChildOfType(cocos2d::CCNode* node, int index) {
return node->getChildByType<Type>(index);
}
/** /**
* Return a node, or create a default one if it's * Return a node, or create a default one if it's
* nullptr. Syntactic sugar function * nullptr. Syntactic sugar function
@ -856,30 +844,6 @@ namespace geode::cocos {
return {color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f}; return {color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f};
} }
[[deprecated("This function may have unintended behavior, use cc3bFromHexString or manually expand the color instead")]]
constexpr cocos2d::ccColor3B cc3x(int hexValue) {
if (hexValue <= 0xf)
return cocos2d::ccColor3B{
static_cast<GLubyte>(hexValue * 17),
static_cast<GLubyte>(hexValue * 17),
static_cast<GLubyte>(hexValue * 17)};
if (hexValue <= 0xff)
return cocos2d::ccColor3B{
static_cast<GLubyte>(hexValue),
static_cast<GLubyte>(hexValue),
static_cast<GLubyte>(hexValue)};
if (hexValue <= 0xfff)
return cocos2d::ccColor3B{
static_cast<GLubyte>((hexValue >> 8 & 0xf) * 17),
static_cast<GLubyte>((hexValue >> 4 & 0xf) * 17),
static_cast<GLubyte>((hexValue >> 0 & 0xf) * 17)};
else
return cocos2d::ccColor3B{
static_cast<GLubyte>(hexValue >> 16 & 0xff),
static_cast<GLubyte>(hexValue >> 8 & 0xff),
static_cast<GLubyte>(hexValue >> 0 & 0xff)};
}
/** /**
* Parse a ccColor3B from a hexadecimal string. The string may contain * Parse a ccColor3B from a hexadecimal string. The string may contain
* a leading '#' * a leading '#'

View file

@ -17,15 +17,6 @@
namespace geode { namespace geode {
using ByteVector = std::vector<uint8_t>; using ByteVector = std::vector<uint8_t>;
// todo in v4: remove this
template <typename T>
[[deprecated("Use geode::toBytes instead")]]
ByteVector toByteArray(T const& a) {
ByteVector out;
out.resize(sizeof(T));
std::memcpy(out.data(), &a, sizeof(T));
return out;
}
template <typename T> template <typename T>
ByteVector toBytes(T const& a) { ByteVector toBytes(T const& a) {
ByteVector out; ByteVector out;

View file

@ -1026,14 +1026,6 @@ std::optional<AxisAlignment> AxisLayoutOptions::getCrossAxisAlignment() const {
return m_impl->m_crossAxisAlignment; return m_impl->m_crossAxisAlignment;
} }
AxisLayoutOptions* AxisLayoutOptions::setMaxScale(float scale) {
m_impl->m_scaleLimits.second = scale;
return this;
}
AxisLayoutOptions* AxisLayoutOptions::setMinScale(float scale) {
m_impl->m_scaleLimits.first = scale;
return this;
}
AxisLayoutOptions* AxisLayoutOptions::setScaleLimits(std::optional<float> min, std::optional<float> max) { AxisLayoutOptions* AxisLayoutOptions::setScaleLimits(std::optional<float> min, std::optional<float> max) {
m_impl->m_scaleLimits = { min, max }; m_impl->m_scaleLimits = { min, max };
return this; return this;

View file

@ -62,10 +62,6 @@ public:
return meta; return meta;
} }
FieldContainer* getFieldContainer() {
return nullptr;
}
FieldContainer* getFieldContainer(char const* forClass) { FieldContainer* getFieldContainer(char const* forClass) {
if (!m_classFieldContainers.count(forClass)) { if (!m_classFieldContainers.count(forClass)) {
m_classFieldContainers[forClass] = new FieldContainer(); m_classFieldContainers[forClass] = new FieldContainer();
@ -104,11 +100,6 @@ size_t modifier::getFieldIndexForClass(char const* name) {
return s_nextIndex[name]++; return s_nextIndex[name]++;
} }
// not const because might modify contents
FieldContainer* CCNode::getFieldContainer() {
return GeodeNodeMetadata::set(this)->getFieldContainer();
}
FieldContainer* CCNode::getFieldContainer(char const* forClass) { FieldContainer* CCNode::getFieldContainer(char const* forClass) {
return GeodeNodeMetadata::set(this)->getFieldContainer(forClass); return GeodeNodeMetadata::set(this)->getFieldContainer(forClass);
} }
@ -455,13 +446,4 @@ void CCNode::updateAnchoredPosition(Anchor anchor, CCPoint const& offset, CCPoin
} }
} }
#ifdef GEODE_EXPORTING
void CCNode::setAttribute(std::string const& attr, matjson::Value const& value) {}
std::optional<matjson::Value> CCNode::getAttributeInternal(std::string const& attr) {
return std::nullopt;
}
#endif
#pragma warning(pop) #pragma warning(pop)

View file

@ -7,7 +7,6 @@
#include <Geode/loader/Loader.hpp> #include <Geode/loader/Loader.hpp>
#include <Geode/loader/Log.hpp> #include <Geode/loader/Log.hpp>
#include <Geode/loader/Mod.hpp> #include <Geode/loader/Mod.hpp>
#include <Geode/loader/SettingEvent.hpp>
#include <Geode/utils/JsonValidation.hpp> #include <Geode/utils/JsonValidation.hpp>
#include <loader/LogImpl.hpp> #include <loader/LogImpl.hpp>
@ -30,8 +29,7 @@ $on_mod(Loaded) {
std::vector<matjson::Value> res; std::vector<matjson::Value> res;
auto args = *event->messageData; auto args = *event->messageData;
JsonChecker checker(args); auto root = checkJson(args, "[ipc/list-mods]");
auto root = checker.root("[ipc/list-mods]").obj();
auto includeRunTimeInfo = root.has("include-runtime-info").get<bool>(); auto includeRunTimeInfo = root.has("include-runtime-info").get<bool>();
auto dontIncludeLoader = root.has("dont-include-loader").get<bool>(); auto dontIncludeLoader = root.has("dont-include-loader").get<bool>();

View file

@ -20,10 +20,6 @@ std::string Mod::getName() const {
return m_impl->getName(); return m_impl->getName();
} }
std::string Mod::getDeveloper() const {
return m_impl->getDevelopers().empty() ? "" : m_impl->getDevelopers().front();
}
std::vector<std::string> Mod::getDevelopers() const { std::vector<std::string> Mod::getDevelopers() const {
return m_impl->getDevelopers(); return m_impl->getDevelopers();
} }
@ -101,9 +97,6 @@ std::vector<Mod*> Mod::getDependants() const {
} }
#endif #endif
std::optional<VersionInfo> Mod::hasAvailableUpdate() const {
return std::nullopt;
}
Mod::CheckUpdatesTask Mod::checkUpdates() const { Mod::CheckUpdatesTask Mod::checkUpdates() const {
return server::checkUpdates(this).map( return server::checkUpdates(this).map(
[](auto* result) -> Mod::CheckUpdatesTask::Value { [](auto* result) -> Mod::CheckUpdatesTask::Value {
@ -159,24 +152,10 @@ bool Mod::hasSetting(std::string_view const key) const {
return m_impl->hasSetting(key); return m_impl->hasSetting(key);
} }
std::optional<Setting> Mod::getSettingDefinition(std::string_view const key) const {
return m_impl->m_settings->getLegacyDefinition(std::string(key));
}
SettingValue* Mod::getSetting(std::string_view const key) const {
return m_impl->m_settings->getLegacy(std::string(key)).get();
}
std::shared_ptr<SettingV3> Mod::getSettingV3(std::string_view const key) const { std::shared_ptr<SettingV3> Mod::getSettingV3(std::string_view const key) const {
return m_impl->m_settings->get(std::string(key)); return m_impl->m_settings->get(std::string(key));
} }
void Mod::registerCustomSetting(std::string_view const key, std::unique_ptr<SettingValue> value) {
auto reg = m_impl->m_settings->registerLegacyCustomSetting(key, std::move(value));
if (!reg) {
log::error("Unable to register custom setting: {}", reg.unwrapErr());
}
}
Result<> Mod::registerCustomSettingType(std::string_view type, SettingGenerator generator) { Result<> Mod::registerCustomSettingType(std::string_view type, SettingGenerator generator) {
return m_impl->m_settings->registerCustomSettingType(type, generator); return m_impl->m_settings->registerCustomSettingType(type, generator);
} }

View file

@ -528,18 +528,6 @@ std::vector<ModMetadata::Incompatibility> ModMetadata::getIncompatibilities() co
std::vector<std::string> ModMetadata::getSpritesheets() const { std::vector<std::string> ModMetadata::getSpritesheets() const {
return m_impl->m_spritesheets; return m_impl->m_spritesheets;
} }
std::vector<std::pair<std::string, Setting>> ModMetadata::getSettings() const {
std::vector<std::pair<std::string, Setting>> res;
for (auto [key, sett] : m_impl->m_settings) {
auto checker = JsonChecker(sett);
auto value = checker.root("");
auto legacy = Setting::parse(key, m_impl->m_id, value);
if (!checker.isError() && legacy.isOk()) {
res.push_back(std::make_pair(key, *legacy));
}
}
return res;
}
std::vector<std::pair<std::string, matjson::Value>> ModMetadata::getSettingsV3() const { std::vector<std::pair<std::string, matjson::Value>> ModMetadata::getSettingsV3() const {
return m_impl->m_settings; return m_impl->m_settings;
} }

View file

@ -13,8 +13,6 @@ private:
std::unordered_map<std::string, SettingGenerator> m_types; std::unordered_map<std::string, SettingGenerator> m_types;
SharedSettingTypesPool() : m_types({ SharedSettingTypesPool() : m_types({
// todo in v4: remove this
{ "custom", &LegacyCustomSettingV3::parse },
{ "title", &TitleSettingV3::parse }, { "title", &TitleSettingV3::parse },
{ "bool", &BoolSettingV3::parse }, { "bool", &BoolSettingV3::parse },
{ "int", &IntSettingV3::parse }, { "int", &IntSettingV3::parse },
@ -202,19 +200,6 @@ Result<> ModSettingsManager::registerLegacyCustomSetting(std::string_view key, s
if (!m_impl->settings.count(id)) { if (!m_impl->settings.count(id)) {
return Err("No such setting '{}' in mod {}", id, m_impl->modID); return Err("No such setting '{}' in mod {}", id, m_impl->modID);
} }
auto& sett = m_impl->settings.at(id);
if (auto custom = typeinfo_pointer_cast<LegacyCustomSettingV3>(sett.v3)) {
if (!custom->getValue()) {
custom->setValue(std::move(ptr));
m_impl->loadSettingValueFromSave(id);
}
else {
return Err("Setting '{}' in mod {} has already been registed", id, m_impl->modID);
}
}
else {
return Err("Setting '{}' in mod {} is not a legacy custom setting", id, m_impl->modID);
}
return Ok(); return Ok();
} }
@ -244,33 +229,6 @@ std::shared_ptr<SettingV3> ModSettingsManager::get(std::string_view key) {
auto id = std::string(key); auto id = std::string(key);
return m_impl->settings.count(id) ? m_impl->settings.at(id).v3 : nullptr; return m_impl->settings.count(id) ? m_impl->settings.at(id).v3 : nullptr;
} }
std::shared_ptr<SettingValue> ModSettingsManager::getLegacy(std::string_view key) {
auto id = std::string(key);
if (!m_impl->settings.count(id)) {
return nullptr;
}
auto& info = m_impl->settings.at(id);
// If this setting has alreay been given a legacy interface, give that
if (info.legacy) {
return info.legacy;
}
// Uninitialized settings are null
if (!info.v3) {
return nullptr;
}
// Generate new legacy interface
if (auto legacy = info.v3->convertToLegacyValue()) {
info.legacy.swap(*legacy);
return info.legacy;
}
return nullptr;
}
std::optional<Setting> ModSettingsManager::getLegacyDefinition(std::string_view key) {
if (auto s = this->get(key)) {
return s->convertToLegacy();
}
return std::nullopt;
}
bool ModSettingsManager::restartRequired() const { bool ModSettingsManager::restartRequired() const {
return m_impl->restartRequired; return m_impl->restartRequired;

View file

@ -1,498 +0,0 @@
#include <ui/mods/settings/GeodeSettingNode.hpp>
#include <Geode/loader/Mod.hpp>
#include <Geode/loader/Setting.hpp>
#include <Geode/loader/SettingV3.hpp>
#include <Geode/loader/SettingEvent.hpp>
#include <Geode/loader/SettingNode.hpp>
#include <Geode/utils/general.hpp>
#include <Geode/utils/JsonValidation.hpp>
#include <regex>
using namespace geode::prelude;
template<class T>
static void parseCommon(T& sett, JsonMaybeObject& obj) {
obj.has("name").into(sett.name);
obj.has("description").into(sett.description);
if (auto defValue = obj.needs("default")) {
// Platform-specific default value
if (defValue.is<matjson::Object>()) {
auto def = defValue.obj();
if (auto plat = def.has(PlatformID::toShortString(GEODE_PLATFORM_TARGET, true))) {
plat.into(sett.defaultValue);
}
else {
defValue.into(sett.defaultValue);
}
}
else {
defValue.into(sett.defaultValue);
}
}
}
Result<BoolSetting> BoolSetting::parse(JsonMaybeObject& obj) {
BoolSetting sett;
parseCommon(sett, obj);
return Ok(sett);
}
Result<IntSetting> IntSetting::parse(JsonMaybeObject& obj) {
IntSetting sett;
parseCommon(sett, obj);
obj.has("min").into(sett.min);
obj.has("max").into(sett.max);
if (auto controls = obj.has("control").obj()) {
controls.has("arrows").into(sett.controls.arrows);
controls.has("big-arrows").into(sett.controls.bigArrows);
controls.has("arrow-step").into(sett.controls.arrowStep);
controls.has("big-arrow-step").into(sett.controls.bigArrowStep);
controls.has("slider").into(sett.controls.slider);
controls.has("slider-step").into(sett.controls.sliderStep);
controls.has("input").into(sett.controls.input);
}
return Ok(sett);
}
Result<FloatSetting> FloatSetting::parse(JsonMaybeObject& obj) {
FloatSetting sett;
parseCommon(sett, obj);
obj.has("min").into(sett.min);
obj.has("max").into(sett.max);
if (auto controls = obj.has("control").obj()) {
controls.has("arrows").into(sett.controls.arrows);
controls.has("big-arrows").into(sett.controls.bigArrows);
controls.has("arrow-step").into(sett.controls.arrowStep);
controls.has("big-arrow-step").into(sett.controls.bigArrowStep);
controls.has("slider").into(sett.controls.slider);
controls.has("slider-step").into(sett.controls.sliderStep);
controls.has("input").into(sett.controls.input);
}
return Ok(sett);
}
Result<StringSetting> StringSetting::parse(JsonMaybeObject& obj) {
StringSetting sett;
parseCommon(sett, obj);
obj.has("match").into(sett.controls->match);
obj.has("filter").into(sett.controls->filter);
obj.has("one-of").into(sett.controls->options);
return Ok(sett);
}
Result<FileSetting> FileSetting::parse(JsonMaybeObject& obj) {
FileSetting sett;
parseCommon(sett, obj);
if (auto controls = obj.has("control").obj()) {
for (auto& item : controls.has("filters").iterate()) {
if (auto iobj = item.obj()) {
Filter filter;
iobj.has("description").into(filter.description);
std::vector<matjson::Value> files;
iobj.has("files").into(files);
for (auto& i : files) {
filter.files.insert(i.as<std::string>());
}
sett.controls.filters.push_back(filter);
}
}
}
return Ok(sett);
}
Result<ColorSetting> ColorSetting::parse(JsonMaybeObject& obj) {
ColorSetting sett;
parseCommon(sett, obj);
return Ok(sett);
}
Result<ColorAlphaSetting> ColorAlphaSetting::parse(JsonMaybeObject& obj) {
ColorAlphaSetting sett;
parseCommon(sett, obj);
return Ok(sett);
}
Result<Setting> Setting::parse(
std::string const& key,
std::string const& mod,
JsonMaybeValue& value
) {
auto sett = Setting();
sett.m_key = key;
sett.m_modID = mod;
if (auto obj = value.obj()) {
std::string type;
obj.needs("type").into(type);
if (type.size()) {
switch (hash(type.c_str())) {
case hash("bool"): {
GEODE_UNWRAP_INTO(sett.m_kind, BoolSetting::parse(obj));
} break;
case hash("int"): {
GEODE_UNWRAP_INTO(sett.m_kind, IntSetting::parse(obj));
} break;
case hash("float"): {
GEODE_UNWRAP_INTO(sett.m_kind, FloatSetting::parse(obj));
} break;
case hash("string"): {
GEODE_UNWRAP_INTO(sett.m_kind, StringSetting::parse(obj));
} break;
case hash("rgb"): case hash("color"): {
GEODE_UNWRAP_INTO(sett.m_kind, ColorSetting::parse(obj));
} break;
case hash("rgba"): {
GEODE_UNWRAP_INTO(sett.m_kind, ColorAlphaSetting::parse(obj));
} break;
case hash("path"): case hash("file"): {
GEODE_UNWRAP_INTO(sett.m_kind, FileSetting::parse(obj));
} break;
case hash("custom"): {
sett.m_kind = CustomSetting {
.json = std::make_shared<ModJson>(obj.json())
};
// skip checking unknown keys
return Ok(sett);
} break;
default: return Err("Unknown setting type \"" + type + "\"");
}
}
// this is handled before the setting is parsed
obj.addKnownKey("platforms");
obj.checkUnknownKeys();
}
// if the type wasn't an object or a string, the JsonChecker that gave the
// JsonMaybeValue will fail eventually so we can continue on
return Ok(sett);
}
Setting::Setting(
std::string const& key,
std::string const& mod,
SettingKind const& kind
) : m_key(key), m_modID(mod), m_kind(kind) {}
std::unique_ptr<SettingValue> Setting::createDefaultValue() const {
return std::visit(makeVisitor {
[&](BoolSetting const& sett) -> std::unique_ptr<SettingValue> {
return std::make_unique<BoolSettingValue>(m_key, m_modID, sett);
},
[&](IntSetting const& sett) -> std::unique_ptr<SettingValue> {
return std::make_unique<IntSettingValue>(m_key, m_modID, sett);
},
[&](FloatSetting const& sett) -> std::unique_ptr<SettingValue> {
return std::make_unique<FloatSettingValue>(m_key, m_modID, sett);
},
[&](StringSetting const& sett) -> std::unique_ptr<SettingValue> {
return std::make_unique<StringSettingValue>(m_key, m_modID, sett);
},
[&](FileSetting const& sett) -> std::unique_ptr<SettingValue> {
return std::make_unique<FileSettingValue>(m_key, m_modID, sett);
},
[&](ColorSetting const& sett) -> std::unique_ptr<SettingValue> {
return std::make_unique<ColorSettingValue>(m_key, m_modID, sett);
},
[&](ColorAlphaSetting const& sett) -> std::unique_ptr<SettingValue> {
return std::make_unique<ColorAlphaSettingValue>(m_key, m_modID, sett);
},
[&](auto const& sett) -> std::unique_ptr<SettingValue> {
return nullptr;
},
}, m_kind);
}
bool Setting::isCustom() const {
return std::holds_alternative<CustomSetting>(m_kind);
}
std::string Setting::getDisplayName() const {
return std::visit(makeVisitor {
[&](CustomSetting const& sett) {
return std::string();
},
[&](auto const& sett) {
return sett.name.value_or(m_key);
},
}, m_kind);
}
std::optional<std::string> Setting::getDescription() const {
return std::visit(makeVisitor {
[&](CustomSetting const& sett) -> std::optional<std::string> {
return std::nullopt;
},
[&](auto const& sett) {
return sett.description;
},
}, m_kind);
}
std::string Setting::getModID() const {
return m_modID;
}
// StringSetting
StringSetting::StringSetting() : name(), description(), defaultValue(), controls(new Data()) {}
StringSetting::StringSetting(StringSetting const& other) : name(other.name), description(other.description),
defaultValue(other.defaultValue), controls(new Data(*other.controls)) {}
StringSetting::StringSetting(StringSetting&& other) noexcept : name(std::move(other.name)), description(std::move(other.description)),
defaultValue(std::move(other.defaultValue)), controls(std::move(other.controls)) {}
StringSetting& StringSetting::operator=(StringSetting const& other) {
name = other.name;
description = other.description;
defaultValue = other.defaultValue;
*controls = *other.controls;
return *this;
}
StringSetting& StringSetting::operator=(StringSetting&& other) noexcept {
name = std::move(other.name);
description = std::move(other.description);
defaultValue = std::move(other.defaultValue);
controls = std::move(other.controls);
return *this;
}
StringSetting::~StringSetting() = default;
// SettingValue
SettingValue::SettingValue(std::string const& key, std::string const& mod)
: m_key(key), m_modID(mod) {}
std::string SettingValue::getKey() const {
return m_key;
}
std::string SettingValue::getModID() const {
return m_modID;
}
void SettingValue::valueChanged() {
if (auto mod = Loader::get()->getLoadedMod(m_modID)) {
if (auto sett = mod->getSettingV3(m_key)) {
sett->markChanged();
}
}
}
// GeodeSettingValue & SettingValueSetter specializations
#define IMPL_NODE_AND_SETTERS(type_) \
template<> \
SettingNode* GeodeSettingValue< \
type_##Setting \
>::createNode(float width) { \
return type_##SettingNode::create(this, width); \
} \
template<> \
typename GeodeSettingValue<type_##Setting>::ValueType \
GeodeSettingValue<type_##Setting>::getValue() const { \
using S = typename SettingTypeForValueType<ValueType>::SettingType; \
if (auto mod = Loader::get()->getInstalledMod(m_modID)) { \
if (auto setting = typeinfo_pointer_cast<S>(mod->getSettingV3(m_key))) {\
return setting->getValue(); \
} \
} \
return m_value; \
} \
template<> \
void GeodeSettingValue< \
type_##Setting \
>::setValue(ValueType const& value) { \
using S = typename SettingTypeForValueType<ValueType>::SettingType; \
if (auto mod = Loader::get()->getInstalledMod(m_modID)) { \
if (auto setting = typeinfo_pointer_cast<S>(mod->getSettingV3(m_key))) {\
return setting->setValue(value); \
} \
} \
} \
template<> \
Result<> GeodeSettingValue< \
type_##Setting \
>::validate(ValueType const& value) const { \
using S = typename SettingTypeForValueType<ValueType>::SettingType; \
if (auto mod = Loader::get()->getInstalledMod(m_modID)) { \
if (auto setting = typeinfo_pointer_cast<S>(mod->getSettingV3(m_key))) {\
return setting->isValid(value); \
} \
} \
return Ok(); \
} \
template<> \
typename type_##Setting::ValueType SettingValueSetter< \
typename type_##Setting::ValueType \
>::get(SettingValue* setting) { \
using S = typename SettingTypeForValueType<typename type_##Setting::ValueType>::SettingType; \
if (auto mod = Loader::get()->getInstalledMod(setting->getModID())) { \
if (auto sett = typeinfo_pointer_cast<S>(mod->getSettingV3(setting->getKey()))) { \
return sett->getValue(); \
} \
} \
return typename type_##Setting::ValueType(); \
} \
template<> \
void SettingValueSetter< \
typename type_##Setting::ValueType \
>::set( \
SettingValue* setting, \
typename type_##Setting::ValueType const& value \
) { \
using S = typename SettingTypeForValueType<typename type_##Setting::ValueType>::SettingType; \
if (auto mod = Loader::get()->getInstalledMod(setting->getModID())) { \
if (auto sett = typeinfo_pointer_cast<S>(mod->getSettingV3(setting->getKey()))) { \
return sett->setValue(value); \
} \
} \
}
#define IMPL_TO_VALID(type_) \
template<> \
typename GeodeSettingValue<type_##Setting>::Valid \
GeodeSettingValue<type_##Setting>::toValid( \
typename type_##Setting::ValueType const& value \
) const
// instantiate values
namespace geode {
template class GeodeSettingValue<BoolSetting>;
template class GeodeSettingValue<IntSetting>;
template class GeodeSettingValue<FloatSetting>;
template class GeodeSettingValue<StringSetting>;
template class GeodeSettingValue<FileSetting>;
template class GeodeSettingValue<ColorSetting>;
template class GeodeSettingValue<ColorAlphaSetting>;
}
IMPL_TO_VALID(Bool) {
return { value, std::nullopt };
}
IMPL_TO_VALID(Int) {
if (m_definition.min && value < m_definition.min) {
return { m_definition.min.value(), fmt::format(
"Value must be more than or equal to {}",
m_definition.min.value()
) };
}
if (m_definition.max && value > m_definition.max) {
return { m_definition.max.value(), fmt::format(
"Value must be less than or equal to {}",
m_definition.max.value()
) };
}
return { value, std::nullopt };
}
IMPL_TO_VALID(Float) {
if (m_definition.min && value < m_definition.min) {
return { m_definition.min.value(), fmt::format(
"Value must be more than or equal to {}",
m_definition.min.value()
) };
}
if (m_definition.max && value > m_definition.max) {
return { m_definition.max.value(), fmt::format(
"Value must be less than or equal to {}",
m_definition.max.value()
) };
}
return { value, std::nullopt };
}
IMPL_TO_VALID(String) {
if (m_definition.controls->match) {
if (!std::regex_match(value, std::regex{m_definition.controls->match.value()})) {
return {
m_definition.defaultValue,
fmt::format(
"Value must match regex {}",
m_definition.controls->match.value()
)
};
}
}
else if (m_definition.controls->options) {
if (std::find(
m_definition.controls->options.value().begin(),
m_definition.controls->options.value().end(),
value
) == m_definition.controls->options.value().end()) {
return {
m_definition.defaultValue,
fmt::format(
"Value must be one of {}",
fmt::join(m_definition.controls->options.value(), ", ")
)
};
}
}
return { value, std::nullopt };
}
IMPL_TO_VALID(File) {
return { value, std::nullopt };
}
IMPL_TO_VALID(Color) {
return { value, std::nullopt };
}
IMPL_TO_VALID(ColorAlpha) {
return { value, std::nullopt };
}
IMPL_NODE_AND_SETTERS(Bool);
IMPL_NODE_AND_SETTERS(Int);
IMPL_NODE_AND_SETTERS(Float);
IMPL_NODE_AND_SETTERS(String);
IMPL_NODE_AND_SETTERS(File);
IMPL_NODE_AND_SETTERS(Color);
IMPL_NODE_AND_SETTERS(ColorAlpha);
// instantiate value setters
namespace geode {
template struct SettingValueSetter<typename BoolSetting::ValueType>;
template struct SettingValueSetter<typename IntSetting::ValueType>;
template struct SettingValueSetter<typename FloatSetting::ValueType>;
template struct SettingValueSetter<typename StringSetting::ValueType>;
template struct SettingValueSetter<typename FileSetting::ValueType>;
template struct SettingValueSetter<typename ColorSetting::ValueType>;
template struct SettingValueSetter<typename ColorAlphaSetting::ValueType>;
}
// SettingChangedEvent
SettingChangedEvent::SettingChangedEvent(Mod* mod, SettingValue* value)
: mod(mod), value(value) {}
// SettingChangedFilter
ListenerResult SettingChangedFilter::handle(
utils::MiniFunction<Callback> fn, SettingChangedEvent* event
) {
if (m_modID == event->mod->getID() &&
(!m_targetKey || m_targetKey.value() == event->value->getKey())
) {
fn(event->value);
}
return ListenerResult::Propagate;
}
SettingChangedFilter::SettingChangedFilter(
std::string const& modID,
std::optional<std::string> const& settingKey
) : m_modID(modID), m_targetKey(settingKey) {}

View file

@ -1,25 +0,0 @@
#include <Geode/loader/SettingNode.hpp>
#include <Geode/utils/cocos.hpp>
using namespace geode::prelude;
void SettingNode::dispatchChanged() {
if (m_delegate) {
m_delegate->settingValueChanged(this);
}
}
void SettingNode::dispatchCommitted() {
if (m_delegate) {
m_delegate->settingValueCommitted(this);
}
}
bool SettingNode::init(SettingValue* value) {
m_value = value;
return true;
}
void SettingNode::setDelegate(SettingNodeDelegate* delegate) {
m_delegate = delegate;
}

View file

@ -1,5 +1,4 @@
#include "SettingNodeV3.hpp" #include "SettingNodeV3.hpp"
#include <Geode/loader/SettingNode.hpp>
#include <Geode/utils/ColorProvider.hpp> #include <Geode/utils/ColorProvider.hpp>
#include <Geode/utils/ranges.hpp> #include <Geode/utils/ranges.hpp>
#include <Geode/loader/Dirs.hpp> #include <Geode/loader/Dirs.hpp>

View file

@ -1,7 +1,6 @@
#pragma once #pragma once
#include <Geode/loader/SettingV3.hpp> #include <Geode/loader/SettingV3.hpp>
#include <Geode/loader/SettingNode.hpp>
#include <Geode/binding/CCMenuItemToggler.hpp> #include <Geode/binding/CCMenuItemToggler.hpp>
#include <Geode/binding/ColorChannelSprite.hpp> #include <Geode/binding/ColorChannelSprite.hpp>
#include <Geode/binding/Slider.hpp> #include <Geode/binding/Slider.hpp>
@ -314,25 +313,3 @@ public:
bool hasNonDefaultValue() const override; bool hasNonDefaultValue() const override;
void onResetToDefault() override; void onResetToDefault() override;
}; };
// If these classes do get exposed in headers,
// LegacyCustomSettingToV3Node SHOULD NOT BE EXPOSED!!!!!! DO NOT DO THAT!!!!
class LegacyCustomSettingToV3Node : public SettingNodeV3, public SettingNodeDelegate {
protected:
SettingNode* m_original;
bool init(std::shared_ptr<LegacyCustomSettingV3> original, float width);
void onCommit() override;
void settingValueChanged(SettingNode*) override;
void settingValueCommitted(SettingNode*) override;
public:
static LegacyCustomSettingToV3Node* create(std::shared_ptr<LegacyCustomSettingV3> original, float width);
bool hasUncommittedChanges() const override;
bool hasNonDefaultValue() const override;
void onResetToDefault() override;
};

View file

@ -1,5 +1,4 @@
#include <Geode/loader/SettingV3.hpp> #include <Geode/loader/SettingV3.hpp>
#include <Geode/loader/SettingEvent.hpp>
#include <Geode/loader/ModSettingsManager.hpp> #include <Geode/loader/ModSettingsManager.hpp>
#include <Geode/utils/ranges.hpp> #include <Geode/utils/ranges.hpp>
#include <Geode/utils/string.hpp> #include <Geode/utils/string.hpp>
@ -574,19 +573,12 @@ void SettingV3::markChanged() {
} }
SettingChangedEventV3(shared_from_this()).post(); SettingChangedEventV3(shared_from_this()).post();
if (manager) { if (manager) {
// TODO: v4
// Use ModSettingsManager rather than convertToLegacyValue since it // Use ModSettingsManager rather than convertToLegacyValue since it
// caches the result and we want to have that for performance // caches the result and we want to have that for performance
SettingChangedEvent(this->getMod(), manager->getLegacy(this->getKey()).get()).post(); // SettingChangedEvent(this->getMod(), manager->getLegacy(this->getKey()).get()).post();
} }
} }
std::optional<Setting> SettingV3::convertToLegacy() const {
return std::nullopt;
}
std::optional<std::shared_ptr<SettingValue>> SettingV3::convertToLegacyValue() const {
return std::nullopt;
}
class TitleSettingV3::Impl final { class TitleSettingV3::Impl final {
public: public:
}; };
@ -666,15 +658,6 @@ bool LegacyCustomSettingV3::isDefaultValue() const {
} }
void LegacyCustomSettingV3::reset() {} void LegacyCustomSettingV3::reset() {}
std::optional<Setting> LegacyCustomSettingV3::convertToLegacy() const {
return Setting(this->getKey(), this->getModID(), SettingKind(CustomSetting {
.json = std::make_shared<ModJson>(m_impl->json)
}));
}
std::optional<std::shared_ptr<SettingValue>> LegacyCustomSettingV3::convertToLegacyValue() const {
return m_impl->legacyValue ? std::optional(m_impl->legacyValue) : std::nullopt;
}
class BoolSettingV3::Impl final { class BoolSettingV3::Impl final {
public: public:
}; };
@ -699,17 +682,6 @@ SettingNodeV3* BoolSettingV3::createNode(float width) {
); );
} }
std::optional<Setting> BoolSettingV3::convertToLegacy() const {
return Setting(this->getKey(), this->getModID(), SettingKind(BoolSetting {
.name = this->getName(),
.description = this->getDescription(),
.defaultValue = this->getDefaultValue(),
}));
}
std::optional<std::shared_ptr<SettingValue>> BoolSettingV3::convertToLegacyValue() const {
return this->convertToLegacy()->createDefaultValue();
}
class IntSettingV3::Impl final { class IntSettingV3::Impl final {
public: public:
std::optional<int64_t> minValue; std::optional<int64_t> minValue;
@ -819,28 +791,6 @@ SettingNodeV3* IntSettingV3::createNode(float width) {
); );
} }
std::optional<Setting> IntSettingV3::convertToLegacy() const {
return Setting(this->getKey(), this->getModID(), SettingKind(IntSetting {
.name = this->getName(),
.description = this->getDescription(),
.defaultValue = this->getDefaultValue(),
.min = this->getMinValue(),
.max = this->getMaxValue(),
.controls = {
.arrows = this->isArrowsEnabled(),
.bigArrows = this->isBigArrowsEnabled(),
.arrowStep = this->getArrowStepSize(),
.bigArrowStep = this->getBigArrowStepSize(),
.slider = this->isSliderEnabled(),
.sliderStep = this->getSliderSnap(),
.input = this->isInputEnabled(),
},
}));
}
std::optional<std::shared_ptr<SettingValue>> IntSettingV3::convertToLegacyValue() const {
return this->convertToLegacy()->createDefaultValue();
}
class FloatSettingV3::Impl final { class FloatSettingV3::Impl final {
public: public:
std::optional<double> minValue; std::optional<double> minValue;
@ -948,27 +898,6 @@ SettingNodeV3* FloatSettingV3::createNode(float width) {
); );
} }
std::optional<Setting> FloatSettingV3::convertToLegacy() const {
return Setting(this->getKey(), this->getModID(), SettingKind(FloatSetting {
.name = this->getName(),
.description = this->getDescription(),
.defaultValue = this->getDefaultValue(),
.min = this->getMinValue(),
.max = this->getMaxValue(),
.controls = {
.arrows = this->isArrowsEnabled(),
.bigArrows = this->isBigArrowsEnabled(),
.arrowStep = static_cast<size_t>(this->getArrowStepSize()),
.bigArrowStep = static_cast<size_t>(this->getBigArrowStepSize()),
.slider = this->isSliderEnabled(),
.sliderStep = this->getSliderSnap(),
.input = this->isInputEnabled(),
},
}));
}
std::optional<std::shared_ptr<SettingValue>> FloatSettingV3::convertToLegacyValue() const {
return this->convertToLegacy()->createDefaultValue();
}
class StringSettingV3::Impl final { class StringSettingV3::Impl final {
public: public:
@ -1026,20 +955,6 @@ SettingNodeV3* StringSettingV3::createNode(float width) {
); );
} }
std::optional<Setting> StringSettingV3::convertToLegacy() const {
auto setting = StringSetting();
setting.name = this->getName();
setting.description = this->getDescription();
setting.defaultValue = this->getDefaultValue();
setting.controls->filter = this->getAllowedCharacters();
setting.controls->match = this->getRegexValidator();
setting.controls->options = this->getEnumOptions();
return Setting(this->getKey(), this->getModID(), SettingKind(setting));
}
std::optional<std::shared_ptr<SettingValue>> StringSettingV3::convertToLegacyValue() const {
return this->convertToLegacy()->createDefaultValue();
}
class FileSettingV3::Impl final { class FileSettingV3::Impl final {
public: public:
bool folder = false; bool folder = false;
@ -1153,18 +1068,6 @@ SettingNodeV3* FileSettingV3::createNode(float width) {
); );
} }
std::optional<Setting> FileSettingV3::convertToLegacy() const {
auto setting = FileSetting();
setting.name = this->getName();
setting.description = this->getDescription();
setting.defaultValue = this->getDefaultValue();
setting.controls.filters = this->getFilters().value_or(std::vector<utils::file::FilePickOptions::Filter>());
return Setting(this->getKey(), this->getModID(), SettingKind(setting));
}
std::optional<std::shared_ptr<SettingValue>> FileSettingV3::convertToLegacyValue() const {
return this->convertToLegacy()->createDefaultValue();
}
class Color3BSettingV3::Impl final { class Color3BSettingV3::Impl final {
public: public:
}; };
@ -1189,17 +1092,6 @@ SettingNodeV3* Color3BSettingV3::createNode(float width) {
); );
} }
std::optional<Setting> Color3BSettingV3::convertToLegacy() const {
auto setting = ColorSetting();
setting.name = this->getName();
setting.description = this->getDescription();
setting.defaultValue = this->getDefaultValue();
return Setting(this->getKey(), this->getModID(), SettingKind(setting));
}
std::optional<std::shared_ptr<SettingValue>> Color3BSettingV3::convertToLegacyValue() const {
return this->convertToLegacy()->createDefaultValue();
}
class Color4BSettingV3::Impl final { class Color4BSettingV3::Impl final {
public: public:
}; };
@ -1223,14 +1115,3 @@ SettingNodeV3* Color4BSettingV3::createNode(float width) {
std::static_pointer_cast<Color4BSettingV3>(shared_from_this()), width std::static_pointer_cast<Color4BSettingV3>(shared_from_this()), width
); );
} }
std::optional<Setting> Color4BSettingV3::convertToLegacy() const {
auto setting = ColorAlphaSetting();
setting.name = this->getName();
setting.description = this->getDescription();
setting.defaultValue = this->getDefaultValue();
return Setting(this->getKey(), this->getModID(), SettingKind(setting));
}
std::optional<std::shared_ptr<SettingValue>> Color4BSettingV3::convertToLegacyValue() const {
return this->convertToLegacy()->createDefaultValue();
}

View file

@ -102,9 +102,7 @@ void updater::downloadLatestLoaderResources() {
log::debug("Downloading latest resources", Loader::get()->getVersion().toVString()); log::debug("Downloading latest resources", Loader::get()->getVersion().toVString());
fetchLatestGithubRelease( fetchLatestGithubRelease(
[](matjson::Value const& raw) { [](matjson::Value const& raw) {
auto json = raw; auto root = checkJson(raw, "[]");
JsonChecker checker(json);
auto root = checker.root("[]").obj();
// find release asset // find release asset
for (auto asset : root.needs("assets").iterate()) { for (auto asset : root.needs("assets").iterate()) {
@ -206,9 +204,7 @@ void updater::downloadLoaderResources(bool useLatestRelease) {
RUNNING_REQUESTS.erase("@downloadLoaderResources"); RUNNING_REQUESTS.erase("@downloadLoaderResources");
if (response->ok()) { if (response->ok()) {
if (auto ok = response->json()) { if (auto ok = response->json()) {
auto json = ok.unwrap(); auto root = checkJson(ok.unwrap(), "[]");
JsonChecker checker(json);
auto root = checker.root("[]").obj();
// find release asset // find release asset
for (auto asset : root.needs("assets").iterate()) { for (auto asset : root.needs("assets").iterate()) {
@ -362,9 +358,7 @@ void updater::checkForLoaderUpdates() {
// Check for updates in the background // Check for updates in the background
fetchLatestGithubRelease( fetchLatestGithubRelease(
[](matjson::Value const& raw) { [](matjson::Value const& raw) {
auto json = raw; auto root = checkJson(raw, "[]");
JsonChecker checker(json);
auto root = checker.root("[]").obj();
VersionInfo ver { 0, 0, 0 }; VersionInfo ver { 0, 0, 0 };
root.needs("tag_name").into(ver); root.needs("tag_name").into(ver);

View file

@ -258,9 +258,7 @@ Result<ServerDateTime> ServerDateTime::parse(std::string const& str) {
} }
Result<ServerModVersion> ServerModVersion::parse(matjson::Value const& raw) { Result<ServerModVersion> ServerModVersion::parse(matjson::Value const& raw) {
auto json = raw; auto root = checkJson(raw, "ServerModVersion");
JsonChecker checker(json);
auto root = checker.root("ServerModVersion").obj();
auto res = ServerModVersion(); auto res = ServerModVersion();
@ -356,9 +354,7 @@ Result<ServerModVersion> ServerModVersion::parse(matjson::Value const& raw) {
} }
Result<ServerModReplacement> ServerModReplacement::parse(matjson::Value const& raw) { Result<ServerModReplacement> ServerModReplacement::parse(matjson::Value const& raw) {
auto json = raw; auto root = checkJson(raw, "ServerModReplacement");
JsonChecker checker(json);
auto root = checker.root("ServerModReplacement").obj();
auto res = ServerModReplacement(); auto res = ServerModReplacement();
root.needs("id").into(res.id); root.needs("id").into(res.id);
@ -371,9 +367,7 @@ Result<ServerModReplacement> ServerModReplacement::parse(matjson::Value const& r
} }
Result<ServerModUpdate> ServerModUpdate::parse(matjson::Value const& raw) { Result<ServerModUpdate> ServerModUpdate::parse(matjson::Value const& raw) {
auto json = raw; auto root = checkJson(raw, "ServerModUpdate");
JsonChecker checker(json);
auto root = checker.root("ServerModUpdate").obj();
auto res = ServerModUpdate(); auto res = ServerModUpdate();
@ -391,9 +385,7 @@ Result<ServerModUpdate> ServerModUpdate::parse(matjson::Value const& raw) {
} }
Result<std::vector<ServerModUpdate>> ServerModUpdate::parseList(matjson::Value const& raw) { Result<std::vector<ServerModUpdate>> ServerModUpdate::parseList(matjson::Value const& raw) {
auto json = raw; auto payload = checkJson(raw, "ServerModUpdatesList");
JsonChecker checker(json);
auto payload = checker.root("ServerModUpdatesList").array();
std::vector<ServerModUpdate> list {}; std::vector<ServerModUpdate> list {};
for (auto item : payload.iterate()) { for (auto item : payload.iterate()) {
@ -421,9 +413,7 @@ bool ServerModUpdate::hasUpdateForInstalledMod() const {
} }
Result<ServerModMetadata> ServerModMetadata::parse(matjson::Value const& raw) { Result<ServerModMetadata> ServerModMetadata::parse(matjson::Value const& raw) {
auto json = raw; auto root = checkJson(raw, "ServerModMetadata");
JsonChecker checker(json);
auto root = checker.root("ServerModMetadata").obj();
auto res = ServerModMetadata(); auto res = ServerModMetadata();
root.needs("id").into(res.id); root.needs("id").into(res.id);
@ -501,9 +491,7 @@ std::string ServerModMetadata::formatDevelopersToString() const {
} }
Result<ServerModsList> ServerModsList::parse(matjson::Value const& raw) { Result<ServerModsList> ServerModsList::parse(matjson::Value const& raw) {
auto json = raw; auto payload = checkJson(raw, "ServerModsList");
JsonChecker checker(json);
auto payload = checker.root("ServerModsList").obj();
auto list = ServerModsList(); auto list = ServerModsList();
for (auto item : payload.needs("data").iterate()) { for (auto item : payload.needs("data").iterate()) {

View file

@ -3,7 +3,6 @@
#include "Geode/utils/VersionInfo.hpp" #include "Geode/utils/VersionInfo.hpp"
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#include <Geode/utils/web.hpp> #include <Geode/utils/web.hpp>
#include <Geode/loader/SettingEvent.hpp>
#include <chrono> #include <chrono>
#include <matjson.hpp> #include <matjson.hpp>
#include <vector> #include <vector>

View file

@ -1,7 +1,6 @@
#include "GeodeStyle.hpp" #include "GeodeStyle.hpp"
#include <Geode/utils/cocos.hpp> #include <Geode/utils/cocos.hpp>
#include <Geode/utils/ColorProvider.hpp> #include <Geode/utils/ColorProvider.hpp>
#include <Geode/loader/SettingEvent.hpp>
#include <Geode/binding/ButtonSprite.hpp> #include <Geode/binding/ButtonSprite.hpp>
#include <Geode/ui/LoadingSpinner.hpp> #include <Geode/ui/LoadingSpinner.hpp>

View file

@ -1,7 +1,7 @@
#include "ModDeveloperItem.hpp" #include "ModDeveloperItem.hpp"
#include <Geode/cocos/base_nodes/CCNode.h> #include <Geode/cocos/base_nodes/CCNode.h>
#include <Geode/cocos/base_nodes/Layout.hpp> #include <Geode/ui/Layout.hpp>
#include <Geode/cocos/cocoa/CCGeometry.h> #include <Geode/cocos/cocoa/CCGeometry.h>
#include <Geode/cocos/label_nodes/CCLabelBMFont.h> #include <Geode/cocos/label_nodes/CCLabelBMFont.h>
#include <Geode/cocos/platform/CCPlatformMacros.h> #include <Geode/cocos/platform/CCPlatformMacros.h>

View file

@ -1,7 +1,7 @@
#include "ModDeveloperList.hpp" #include "ModDeveloperList.hpp"
#include <Geode/cocos/base_nodes/CCNode.h> #include <Geode/cocos/base_nodes/CCNode.h>
#include <Geode/cocos/base_nodes/Layout.hpp> #include <Geode/ui/Layout.hpp>
#include <Geode/cocos/cocoa/CCGeometry.h> #include <Geode/cocos/cocoa/CCGeometry.h>
#include <Geode/cocos/platform/CCPlatformMacros.h> #include <Geode/cocos/platform/CCPlatformMacros.h>
#include <Geode/utils/cocos.hpp> #include <Geode/utils/cocos.hpp>

View file

@ -1,7 +1,7 @@
#include "ModProblemItem.hpp" #include "ModProblemItem.hpp"
#include <Geode/cocos/base_nodes/CCNode.h> #include <Geode/cocos/base_nodes/CCNode.h>
#include <Geode/cocos/base_nodes/Layout.hpp> #include <Geode/ui/Layout.hpp>
#include <Geode/cocos/cocoa/CCGeometry.h> #include <Geode/cocos/cocoa/CCGeometry.h>
#include <Geode/cocos/label_nodes/CCLabelBMFont.h> #include <Geode/cocos/label_nodes/CCLabelBMFont.h>
#include <Geode/cocos/platform/CCPlatformMacros.h> #include <Geode/cocos/platform/CCPlatformMacros.h>

View file

@ -1,7 +1,7 @@
#include "ModProblemList.hpp" #include "ModProblemList.hpp"
#include <Geode/cocos/base_nodes/CCNode.h> #include <Geode/cocos/base_nodes/CCNode.h>
#include <Geode/cocos/base_nodes/Layout.hpp> #include <Geode/ui/Layout.hpp>
#include <Geode/cocos/cocoa/CCGeometry.h> #include <Geode/cocos/cocoa/CCGeometry.h>
#include <Geode/cocos/platform/CCPlatformMacros.h> #include <Geode/cocos/platform/CCPlatformMacros.h>
#include <Geode/utils/cocos.hpp> #include <Geode/utils/cocos.hpp>

View file

@ -1,5 +1,5 @@
#include "ModErrorPopup.hpp" #include "ModErrorPopup.hpp"
#include "Geode/cocos/base_nodes/Layout.hpp" #include <Geode/ui/Layout.hpp>
#include "ui/mods/GeodeStyle.hpp" #include "ui/mods/GeodeStyle.hpp"
#include "ui/mods/list/ModProblemList.hpp" #include "ui/mods/list/ModProblemList.hpp"

View file

@ -1,558 +0,0 @@
#include "GeodeSettingNode.hpp"
#include "Geode/binding/FLAlertLayer.hpp"
#include "Geode/ui/Popup.hpp"
#include <Geode/binding/ButtonSprite.hpp>
#include <Geode/binding/CCTextInputNode.hpp>
#include <Geode/binding/ColorChannelSprite.hpp>
#include <Geode/binding/Slider.hpp>
#include <Geode/binding/CCMenuItemToggler.hpp>
#include <Geode/loader/Loader.hpp>
#include <Geode/loader/Dirs.hpp>
#include <Geode/utils/general.hpp>
#include <charconv>
#include <clocale>
#include <filesystem>
// Helpers
template<class T>
static float valueToSlider(T const& setting, typename T::ValueType value) {
auto min = setting.min ? setting.min.value() : -100;
auto max = setting.max ? setting.max.value() : +100;
auto range = max - min;
return static_cast<float>(clamp(static_cast<double>(value - min) / range, 0.0, 1.0));
}
template<class T>
static typename T::ValueType valueFromSlider(T const& setting, float num) {
auto min = setting.min ? setting.min.value() : -100;
auto max = setting.max ? setting.max.value() : +100;
auto range = max - min;
auto value = static_cast<typename T::ValueType>(num * range + min);
if (auto step = setting.controls.sliderStep) {
value = static_cast<typename T::ValueType>(
round(value / step.value()) * step.value()
);
}
return value;
}
template<class C, class T>
TextInput* createInput(C* node, GeodeSettingValue<T>* setting, float width) {
auto input = TextInput::create(width / 2 - 70.f, "Text", "chatFont.fnt");
input->setPosition({
-(width / 2 - 70.f) / 2,
setting->castDefinition().controls.slider ? 5.f : 0.f
});
input->setScale(.65f);
input->setDelegate(node);
return input;
}
template<class C, class T>
Slider* createSlider(C* node, GeodeSettingValue<T>* setting, float width) {
auto slider = Slider::create(
node, menu_selector(C::onSlider), .5f
);
slider->setPosition(-50.f, -15.f);
node->updateSlider();
return slider;
}
template<class C, class T>
std::pair<
CCMenuItemSpriteExtra*, CCMenuItemSpriteExtra*
> createArrows(C* node, GeodeSettingValue<T>* setting, float width, bool big) {
auto yPos = setting->castDefinition().controls.slider ? 5.f : 0.f;
auto decArrowSpr = CCSprite::createWithSpriteFrameName(
big ? "double-nav.png"_spr : "navArrowBtn_001.png"
);
decArrowSpr->setFlipX(true);
decArrowSpr->setScale(.3f);
auto decArrow = CCMenuItemSpriteExtra::create(
decArrowSpr, node, menu_selector(C::onArrow)
);
decArrow->setPosition(-width / 2 + (big ? 65.f : 80.f), yPos);
decArrow->setTag(big ?
-setting->castDefinition().controls.bigArrowStep :
-setting->castDefinition().controls.arrowStep
);
auto incArrowSpr = CCSprite::createWithSpriteFrameName(
big ? "double-nav.png"_spr : "navArrowBtn_001.png"
);
incArrowSpr->setScale(.3f);
auto incArrow = CCMenuItemSpriteExtra::create(
incArrowSpr, node, menu_selector(C::onArrow)
);
incArrow->setTag(big ?
setting->castDefinition().controls.bigArrowStep :
setting->castDefinition().controls.arrowStep
);
incArrow->setPosition(big ? 5.f : -10.f, yPos);
return { decArrow, incArrow };
}
// BoolSettingNode
void BoolSettingNode::valueChanged(bool updateText) {
GeodeSettingNode::valueChanged(updateText);
m_toggle->toggle(m_uncommittedValue);
}
void BoolSettingNode::onToggle(CCObject*) {
m_uncommittedValue = !m_toggle->isToggled();
this->valueChanged(true);
m_toggle->toggle(!m_uncommittedValue);
}
bool BoolSettingNode::setup(BoolSettingValue* setting, float width) {
m_toggle = CCMenuItemToggler::createWithStandardSprites(
this, menu_selector(BoolSettingNode::onToggle), .6f
);
m_toggle->toggle(m_uncommittedValue);
m_toggle->setPositionX(-10.f);
m_menu->addChild(m_toggle);
return true;
}
// IntSettingNode
float IntSettingNode::setupHeight(IntSettingValue* setting) const {
return setting->castDefinition().controls.slider ? 55.f : 40.f;
}
void IntSettingNode::onSlider(CCObject* slider) {
m_uncommittedValue = valueFromSlider(
setting()->castDefinition(),
static_cast<SliderThumb*>(slider)->getValue()
);
this->valueChanged(true);
}
void IntSettingNode::valueChanged(bool updateText) {
GeodeSettingNode::valueChanged(updateText);
if (updateText) {
this->updateLabel();
}
this->updateSlider();
}
void IntSettingNode::updateSlider() {
if (m_slider) {
m_slider->setValue(valueToSlider(
setting()->castDefinition(),
m_uncommittedValue
));
}
}
void IntSettingNode::updateLabel() {
if (m_input) {
// hacky way to make setString not called textChanged
m_input->setString(numToString(m_uncommittedValue), false);
}
else {
m_label->setString(numToString(m_uncommittedValue).c_str());
m_label->limitLabelWidth(m_width / 2 - 70.f, .5f, .1f);
}
}
void IntSettingNode::onArrow(CCObject* sender) {
m_uncommittedValue += sender->getTag();
this->valueChanged(true);
}
void IntSettingNode::textChanged(CCTextInputNode* input) {
auto res = numFromString<ValueType>(input->getString());
if (!res) return;
m_uncommittedValue = res.unwrap();
this->valueChanged(false);
}
bool IntSettingNode::setup(IntSettingValue* setting, float width) {
if (setting->castDefinition().controls.input) {
m_menu->addChild(m_input = createInput(this, setting, width));
m_input->setCommonFilter(CommonFilter::Int);
}
else {
m_label = CCLabelBMFont::create("", "bigFont.fnt");
m_label->setPosition({
-(width / 2 - 70.f) / 2,
setting->castDefinition().controls.slider ? 5.f : 0.f
});
m_label->limitLabelWidth(width / 2 - 70.f, .5f, .1f);
m_menu->addChild(m_label);
}
if (setting->castDefinition().controls.slider) {
m_menu->addChild(m_slider = createSlider(this, setting, width));
}
if (setting->castDefinition().controls.arrows) {
auto [dec, inc] = createArrows(this, setting, width, false);
m_menu->addChild(m_decArrow = dec);
m_menu->addChild(m_incArrow = inc);
}
if (setting->castDefinition().controls.bigArrows) {
auto [dec, inc] = createArrows(this, setting, width, true);
m_menu->addChild(m_bigDecArrow = dec);
m_menu->addChild(m_bigIncArrow = inc);
}
return true;
}
// FloatSettingNode
float FloatSettingNode::setupHeight(FloatSettingValue* setting) const {
return setting->castDefinition().controls.slider ? 55.f : 40.f;
}
void FloatSettingNode::onSlider(CCObject* slider) {
m_uncommittedValue = valueFromSlider(
setting()->castDefinition(),
static_cast<SliderThumb*>(slider)->getValue()
);
this->valueChanged(true);
}
void FloatSettingNode::valueChanged(bool updateText) {
GeodeSettingNode::valueChanged(updateText);
if (updateText) {
this->updateLabel();
}
this->updateSlider();
}
void FloatSettingNode::updateSlider() {
if (m_slider) {
m_slider->setValue(valueToSlider(
setting()->castDefinition(),
m_uncommittedValue
));
}
}
void FloatSettingNode::updateLabel() {
if (m_input) {
// hacky way to make setString not called textChanged
m_input->setString(numToString(m_uncommittedValue), false);
}
else {
m_label->setString(numToString(m_uncommittedValue).c_str());
m_label->limitLabelWidth(m_width / 2 - 70.f, .5f, .1f);
}
}
void FloatSettingNode::onArrow(CCObject* sender) {
m_uncommittedValue += sender->getTag();
this->valueChanged(true);
}
void FloatSettingNode::textChanged(CCTextInputNode* input) {
auto res = numFromString<ValueType>(input->getString());
if (!res) return;
m_uncommittedValue = res.unwrap();
this->valueChanged(false);
}
bool FloatSettingNode::setup(FloatSettingValue* setting, float width) {
if (setting->castDefinition().controls.input) {
m_menu->addChild(m_input = createInput(this, setting, width));
m_input->setCommonFilter(CommonFilter::Float);
}
else {
m_label = CCLabelBMFont::create("", "bigFont.fnt");
m_label->setPosition({
-(width / 2 - 70.f) / 2,
setting->castDefinition().controls.slider ? 5.f : 0.f
});
m_label->limitLabelWidth(width / 2 - 70.f, .5f, .1f);
m_menu->addChild(m_label);
}
if (setting->castDefinition().controls.slider) {
m_menu->addChild(m_slider = createSlider(this, setting, width));
}
if (setting->castDefinition().controls.arrows) {
auto [dec, inc] = createArrows(this, setting, width, false);
m_menu->addChild(m_decArrow = dec);
m_menu->addChild(m_incArrow = inc);
}
if (setting->castDefinition().controls.bigArrows) {
auto [dec, inc] = createArrows(this, setting, width, true);
m_menu->addChild(m_bigDecArrow = dec);
m_menu->addChild(m_bigIncArrow = inc);
}
return true;
}
// StringSettingNode
void StringSettingNode::updateLabel() {
if (m_input) m_input->setString(m_uncommittedValue, false);
if (m_label) {
m_label->setString(m_uncommittedValue.c_str());
m_label->limitLabelWidth(m_width / 2 - 80.f, .65f, .1f);
}
}
void StringSettingNode::textChanged(CCTextInputNode* input) {
m_uncommittedValue = input->getString();
this->valueChanged(false);
}
void StringSettingNode::valueChanged(bool updateText) {
GeodeSettingNode::valueChanged(updateText);
this->updateLabel();
}
void StringSettingNode::onArrow(CCObject* sender) {
m_selectedOption += sender->getTag();
if (m_selectedOption < 0) {
m_selectedOption = m_options.size() - 1;
}
else if (m_selectedOption >= m_options.size()) {
m_selectedOption = 0;
}
m_uncommittedValue = m_options[m_selectedOption];
this->valueChanged(true);
}
bool StringSettingNode::setup(StringSettingValue* setting, float width) {
m_width = width;
if (setting->castDefinition().controls->options.has_value()) {
m_options = setting->castDefinition().controls->options.value();
m_selectedOption = 0;
for (size_t i = 0; i < m_options.size(); i++) {
if (m_options[i] == setting->castDefinition().defaultValue) {
m_selectedOption = i;
break;
}
}
auto prevArrowSpr = CCSprite::createWithSpriteFrameName("navArrowBtn_001.png");
prevArrowSpr->setFlipX(true);
prevArrowSpr->setScale(.3f);
m_prevBtn = CCMenuItemSpriteExtra::create(
prevArrowSpr, this, menu_selector(StringSettingNode::onArrow)
);
m_prevBtn->setPosition(-width / 2 + 65.f, 0.f);
m_prevBtn->setTag(-1);
m_menu->addChild(m_prevBtn);
auto nextArrowSpr = CCSprite::createWithSpriteFrameName("navArrowBtn_001.png");
nextArrowSpr->setScale(.3f);
m_nextBtn = CCMenuItemSpriteExtra::create(
nextArrowSpr, this, menu_selector(StringSettingNode::onArrow)
);
m_nextBtn->setTag(1);
m_nextBtn->setPosition(5.f, 0.f);
m_menu->addChild(m_nextBtn);
m_label = CCLabelBMFont::create("", "bigFont.fnt");
m_label->setPosition({ -(width / 2 - 70.f) / 2, .0f });
m_menu->addChild(m_label);
}
else {
m_input = TextInput::create(width / 2 - 10.f, "Text", "chatFont.fnt");
m_input->setPosition({ -(width / 2 - 70.f) / 2, .0f });
m_input->setScale(.65f);
if (setting->castDefinition().controls->filter.has_value()) {
m_input->setFilter(setting->castDefinition().controls->filter.value());
}
m_input->setDelegate(this);
m_menu->addChild(m_input);
}
return true;
}
// FileSettingNode
void FileSettingNode::updateLabel() {
// hacky way to make setString not called textChanged
m_input->setString(m_uncommittedValue.string(), false);
}
void FileSettingNode::textChanged(CCTextInputNode* input) {
m_uncommittedValue = input->getString().c_str();
this->valueChanged(false);
}
void FileSettingNode::valueChanged(bool updateText) {
GeodeSettingNode::valueChanged(updateText);
this->updateLabel();
}
void FileSettingNode::onPickFile(CCObject*) {
m_pickListener.bind(this, &FileSettingNode::onPickFileFinished);
m_pickListener.setFilter(file::pick(
file::PickMode::OpenFile,
{
dirs::getGameDir(),
setting()->castDefinition().controls.filters
}));
}
void FileSettingNode::onPickFileFinished(FileTask::Event* event) {
if (!event->getValue()) {
return;
}
auto value = event->getValue();
if (value->isOk()) {
m_uncommittedValue = value->unwrap();
this->valueChanged(true);
} else {
FLAlertLayer::create(
"Failed",
fmt::format("Failed to pick file: {}", value->err().value()).c_str(),
"Ok"
)->show();
}
}
bool FileSettingNode::setup(FileSettingValue* setting, float width) {
m_input = TextInput::create(width / 2 - 30.f, "Path to File", "chatFont.fnt");
m_input->setPosition({ -(width / 2 - 80.f) / 2 - 15.f, .0f });
m_input->setScale(.65f);
m_input->setDelegate(this);
m_menu->addChild(m_input);
auto fileBtnSpr = CCSprite::createWithSpriteFrameName("gj_folderBtn_001.png");
fileBtnSpr->setScale(.5f);
auto fileBtn = CCMenuItemSpriteExtra::create(
fileBtnSpr, this, menu_selector(FileSettingNode::onPickFile)
);
fileBtn->setPosition(.0f, .0f);
m_menu->addChild(fileBtn);
return true;
}
// ColorSettingNode
void ColorSettingNode::valueChanged(bool updateText) {
GeodeSettingNode::valueChanged(updateText);
m_colorSpr->setColor(m_uncommittedValue);
}
void ColorSettingNode::updateColor(ccColor4B const& color) {
m_uncommittedValue = to3B(color);
this->valueChanged(true);
}
void ColorSettingNode::onSelectColor(CCObject*) {
auto popup = ColorPickPopup::create(m_uncommittedValue);
popup->setDelegate(this);
popup->setColorTarget(m_colorSpr);
popup->show();
}
bool ColorSettingNode::setup(ColorSettingValue* setting, float width) {
m_colorSpr = ColorChannelSprite::create();
m_colorSpr->setColor(m_uncommittedValue);
m_colorSpr->setScale(.65f);
auto button = CCMenuItemSpriteExtra::create(
m_colorSpr, this, menu_selector(ColorSettingNode::onSelectColor)
);
button->setPositionX(-10.f);
m_menu->addChild(button);
return true;
}
// ColorAlphaSettingNode
void ColorAlphaSettingNode::valueChanged(bool updateText) {
GeodeSettingNode::valueChanged(updateText);
m_colorSpr->setColor(to3B(m_uncommittedValue));
m_colorSpr->updateOpacity(m_uncommittedValue.a / 255.f);
}
void ColorAlphaSettingNode::updateColor(ccColor4B const& color) {
m_uncommittedValue = color;
this->valueChanged(true);
}
void ColorAlphaSettingNode::onSelectColor(CCObject*) {
auto popup = ColorPickPopup::create(m_uncommittedValue);
popup->setDelegate(this);
popup->setColorTarget(m_colorSpr);
popup->show();
}
bool ColorAlphaSettingNode::setup(ColorAlphaSettingValue* setting, float width) {
m_colorSpr = ColorChannelSprite::create();
m_colorSpr->setColor(to3B(m_uncommittedValue));
m_colorSpr->updateOpacity(m_uncommittedValue.a / 255.f);
m_colorSpr->setScale(.65f);
auto button = CCMenuItemSpriteExtra::create(
m_colorSpr, this, menu_selector(ColorAlphaSettingNode::onSelectColor)
);
button->setPositionX(-10.f);
m_menu->addChild(button);
return true;
}
// CustomSettingPlaceholderNode
void CustomSettingPlaceholderNode::commit() {
}
bool CustomSettingPlaceholderNode::hasUncommittedChanges() {
return false;
}
bool CustomSettingPlaceholderNode::hasNonDefaultValue() {
return false;
}
void CustomSettingPlaceholderNode::resetToDefault() {
}
bool CustomSettingPlaceholderNode::init(std::string const& key, float width) {
if (!SettingNode::init(nullptr))
return false;
constexpr auto sidePad = 40.f;
this->setContentSize({ width, 40.f });
auto info = CCLabelBMFont::create(
"You need to enable the mod to modify this setting.",
"bigFont.fnt"
);
info->setAnchorPoint({ .0f, .5f });
info->limitLabelWidth(width - sidePad, .5f, .1f);
info->setPosition({ sidePad / 2, m_obContentSize.height / 2 });
this->addChild(info);
return true;
}
CustomSettingPlaceholderNode* CustomSettingPlaceholderNode::create(
std::string const& key, float width
) {
auto ret = new CustomSettingPlaceholderNode;
if (ret->init(key, width)) {
ret->autorelease();
return ret;
}
delete ret;
return nullptr;
}

View file

@ -1,361 +0,0 @@
#pragma once
#include <Geode/loader/Event.hpp>
#include <Geode/utils/Result.hpp>
#include <Geode/binding/CCMenuItemSpriteExtra.hpp>
#include <Geode/binding/CCTextInputNode.hpp>
#include <Geode/binding/Slider.hpp>
#include <Geode/binding/SliderThumb.hpp>
#include <Geode/loader/Setting.hpp>
#include <Geode/loader/SettingNode.hpp>
#include <Geode/ui/BasedButtonSprite.hpp>
#include <Geode/ui/ColorPickPopup.hpp>
#include <Geode/ui/InputNode.hpp>
#include <Geode/ui/Popup.hpp>
#include <Geode/utils/cocos.hpp>
#include <Geode/utils/string.hpp>
#include <Geode/loader/Mod.hpp>
using namespace geode::prelude;
#define IMPL_SETT_CREATE(type_) \
static type_##SettingNode* create( \
type_##SettingValue* value, float width \
) { \
auto ret = new type_##SettingNode; \
if (ret->init(value, width)) { \
ret->autorelease(); \
return ret; \
} \
delete ret; \
return nullptr; \
}
template <class T>
class GeodeSettingNode : public SettingNode {
public:
using ValueType = typename T::ValueType;
protected:
float m_width;
float m_height;
ValueType m_uncommittedValue;
CCMenu* m_menu;
CCLabelBMFont* m_nameLabel;
CCLabelBMFont* m_errorLabel;
CCMenuItemSpriteExtra* m_resetBtn;
bool init(GeodeSettingValue<T>* setting, float width) {
if (!SettingNode::init(setting))
return false;
m_width = width;
m_height = this->setupHeight(setting);
this->setContentSize({ width, m_height });
constexpr auto sidePad = 40.f;
m_uncommittedValue = setting->getValue();
auto name = setting->getDefinition().getDisplayName();
m_nameLabel = CCLabelBMFont::create(name.c_str(), "bigFont.fnt");
m_nameLabel->setAnchorPoint({ .0f, .5f });
m_nameLabel->limitLabelWidth(width / 2 - 50.f, .5f, .1f);
m_nameLabel->setPosition({ sidePad / 2, m_obContentSize.height / 2 });
this->addChild(m_nameLabel);
m_errorLabel = CCLabelBMFont::create("", "bigFont.fnt");
m_errorLabel->setAnchorPoint({ .0f, .5f });
m_errorLabel->limitLabelWidth(width / 2 - 50.f, .25f, .1f);
m_errorLabel->setPosition({ sidePad / 2, m_obContentSize.height / 2 - 14.f });
m_errorLabel->setColor({ 255, 100, 100 });
m_errorLabel->setZOrder(5);
this->addChild(m_errorLabel);
m_menu = CCMenu::create();
m_menu->setPosition({ m_obContentSize.width - sidePad / 2, m_obContentSize.height / 2 }
);
this->addChild(m_menu);
float btnPos = 15.f;
if (setting->castDefinition().description) {
auto infoSpr = CCSprite::createWithSpriteFrameName("GJ_infoIcon_001.png");
infoSpr->setScale(.6f);
auto infoBtn = CCMenuItemSpriteExtra::create(
infoSpr, this, menu_selector(GeodeSettingNode::onDescription)
);
infoBtn->setPosition(
-m_obContentSize.width + sidePad + m_nameLabel->getScaledContentSize().width +
btnPos,
0.f
);
m_menu->addChild(infoBtn);
btnPos += 20.f;
}
auto resetBtnSpr = CCSprite::createWithSpriteFrameName("reset-gold.png"_spr);
resetBtnSpr->setScale(.5f);
m_resetBtn = CCMenuItemSpriteExtra::create(
resetBtnSpr, this, menu_selector(GeodeSettingNode::onReset)
);
m_resetBtn->setPosition(
-m_obContentSize.width + sidePad + m_nameLabel->getScaledContentSize().width +
btnPos,
.0f
);
m_menu->addChild(m_resetBtn);
m_menu->setTouchEnabled(true);
if (!this->setup(setting, width)) return false;
this->valueChanged();
return true;
}
void onDescription(CCObject*) {
FLAlertLayer::create(
setting()->getDefinition().getDisplayName().c_str(),
setting()->castDefinition().description.value(),
"OK"
)->show();
}
void onReset(CCObject*) {
createQuickPopup(
"Reset",
"Are you sure you want to <cr>reset</c> <cl>" +
setting()->getDefinition().getDisplayName() +
"</c> to <cy>default</c>?",
"Cancel", "Reset",
[this](auto, bool btn2) {
if (btn2) {
this->resetToDefault();
}
}
);
}
virtual float setupHeight(GeodeSettingValue<T>* setting) const {
return 40.f;
}
virtual bool setup(GeodeSettingValue<T>* setting, float width) = 0;
virtual void valueChanged(bool updateText = true) {
if (this->hasUncommittedChanges()) {
m_nameLabel->setColor({0x11, 0xdd, 0x00});
}
else {
m_nameLabel->setColor({0xff, 0xff, 0xff});
}
if (m_resetBtn) m_resetBtn->setVisible(this->hasNonDefaultValue());
auto isValid = setting()->validate(m_uncommittedValue);
if (!isValid) {
m_errorLabel->setVisible(true);
m_errorLabel->setString(isValid.unwrapErr().c_str());
}
else {
m_errorLabel->setVisible(false);
}
this->dispatchChanged();
}
GeodeSettingValue<T>* setting() {
return static_cast<GeodeSettingValue<T>*>(m_value);
}
public:
void commit() override {
setting()->setValue(m_uncommittedValue);
m_uncommittedValue = setting()->getValue();
this->valueChanged();
this->dispatchCommitted();
}
bool hasUncommittedChanges() override {
return m_uncommittedValue != setting()->getValue();
}
bool hasNonDefaultValue() override {
return m_uncommittedValue != setting()->castDefinition().defaultValue;
}
void resetToDefault() override {
m_uncommittedValue = setting()->castDefinition().defaultValue;
this->valueChanged();
}
};
class BoolSettingNode : public GeodeSettingNode<BoolSetting> {
protected:
CCMenuItemToggler* m_toggle;
void onToggle(CCObject*);
void valueChanged(bool updateText) override;
bool setup(BoolSettingValue* setting, float width) override;
public:
IMPL_SETT_CREATE(Bool);
};
class IntSettingNode :
public GeodeSettingNode<IntSetting>,
public TextInputDelegate
{
protected:
TextInput* m_input = nullptr;
CCLabelBMFont* m_label = nullptr;
Slider* m_slider = nullptr;
CCMenuItemSpriteExtra* m_decArrow = nullptr;
CCMenuItemSpriteExtra* m_incArrow = nullptr;
CCMenuItemSpriteExtra* m_bigDecArrow = nullptr;
CCMenuItemSpriteExtra* m_bigIncArrow = nullptr;
void valueChanged(bool updateText) override;
void textChanged(CCTextInputNode* input) override;
float setupHeight(IntSettingValue* setting) const override;
bool setup(IntSettingValue* setting, float width) override;
public:
void updateSlider();
void updateLabel();
void onSlider(CCObject* slider);
void onArrow(CCObject* sender);
IMPL_SETT_CREATE(Int);
};
class FloatSettingNode :
public GeodeSettingNode<FloatSetting>,
public TextInputDelegate
{
protected:
TextInput* m_input = nullptr;
CCLabelBMFont* m_label = nullptr;
Slider* m_slider = nullptr;
CCMenuItemSpriteExtra* m_decArrow = nullptr;
CCMenuItemSpriteExtra* m_incArrow = nullptr;
CCMenuItemSpriteExtra* m_bigDecArrow = nullptr;
CCMenuItemSpriteExtra* m_bigIncArrow = nullptr;
void valueChanged(bool updateText) override;
void textChanged(CCTextInputNode* input) override;
float setupHeight(FloatSettingValue* setting) const override;
bool setup(FloatSettingValue* setting, float width) override;
public:
void updateSlider();
void updateLabel();
void onSlider(CCObject* slider);
void onArrow(CCObject* sender);
IMPL_SETT_CREATE(Float);
};
class StringSettingNode :
public GeodeSettingNode<StringSetting>,
public TextInputDelegate
{
protected:
TextInput* m_input = nullptr;
CCLabelBMFont* m_label = nullptr;
CCMenuItemSpriteExtra* m_prevBtn = nullptr;
CCMenuItemSpriteExtra* m_nextBtn = nullptr;
std::vector<std::string> m_options;
int m_selectedOption = 0;
float m_width;
void textChanged(CCTextInputNode* input) override;
void valueChanged(bool updateText) override;
void updateLabel();
void onArrow(CCObject* sender);
bool setup(StringSettingValue* setting, float width) override;
public:
IMPL_SETT_CREATE(String);
};
class FileSettingNode :
public GeodeSettingNode<FileSetting>,
public TextInputDelegate
{
protected:
using FileTask = Task<Result<std::filesystem::path>>;
TextInput* m_input;
EventListener<FileTask> m_pickListener;
void textChanged(CCTextInputNode* input) override;
void valueChanged(bool updateText) override;
void updateLabel();
void onPickFile(CCObject*);
void onPickFileFinished(FileTask::Event* event);
bool setup(FileSettingValue* setting, float width) override;
public:
IMPL_SETT_CREATE(File);
};
class ColorSettingNode :
public GeodeSettingNode<ColorSetting>,
public ColorPickPopupDelegate {
protected:
ColorChannelSprite* m_colorSpr;
void valueChanged(bool updateText) override;
void updateColor(ccColor4B const& color) override;
void onSelectColor(CCObject*);
bool setup(ColorSettingValue* setting, float width) override;
public:
IMPL_SETT_CREATE(Color);
};
class ColorAlphaSettingNode :
public GeodeSettingNode<ColorAlphaSetting>,
public ColorPickPopupDelegate {
protected:
ColorChannelSprite* m_colorSpr;
void valueChanged(bool updateText) override;
void updateColor(ccColor4B const& color) override;
void onSelectColor(CCObject*);
bool setup(ColorAlphaSettingValue* setting, float width) override;
public:
IMPL_SETT_CREATE(ColorAlpha);
};
class CustomSettingPlaceholderNode : public SettingNode {
protected:
void commit() override;
bool hasUncommittedChanges() override;
bool hasNonDefaultValue() override;
void resetToDefault() override;
bool init(std::string const& key, float width);
public:
static CustomSettingPlaceholderNode* create(
std::string const& key, float width
);
};

View file

@ -1,7 +1,6 @@
#include "ModSettingsPopup.hpp" #include "ModSettingsPopup.hpp"
#include <Geode/binding/ButtonSprite.hpp> #include <Geode/binding/ButtonSprite.hpp>
#include <Geode/loader/Mod.hpp> #include <Geode/loader/Mod.hpp>
#include <Geode/loader/Setting.hpp>
#include <Geode/loader/ModSettingsManager.hpp> #include <Geode/loader/ModSettingsManager.hpp>
#include <Geode/ui/ScrollLayer.hpp> #include <Geode/ui/ScrollLayer.hpp>
#include <Geode/utils/cocos.hpp> #include <Geode/utils/cocos.hpp>

View file

@ -1,105 +0,0 @@
#include <Geode/binding/CCTextInputNode.hpp>
#include <Geode/binding/TextInputDelegate.hpp>
#include <Geode/ui/InputNode.hpp>
#include <Geode/ui/TextInput.hpp>
#include <Geode/utils/cocos.hpp>
using namespace geode::prelude;
std::string InputNode::getString() {
return m_input->getString();
}
void InputNode::setString(std::string const& str) {
m_input->setString(str);
}
CCTextInputNode* InputNode::getInput() const {
return m_input;
}
CCScale9Sprite* InputNode::getBG() const {
return m_bgSprite;
}
void InputNode::setEnabled(bool enabled) {
m_input->setMouseEnabled(enabled);
m_input->setTouchEnabled(enabled);
}
bool InputNode::init(
float width, float height, char const* placeholder, char const* font, std::string const& filter,
int maxCharCount
) {
if (!CCMenuItem::initWithTarget(this, nullptr)) return false;
m_bgSprite = cocos2d::extension::CCScale9Sprite::create(
"square02b_001.png", { 0.0f, 0.0f, 80.0f, 80.0f }
);
m_bgSprite->setScale(.5f);
m_bgSprite->setColor({ 0, 0, 0 });
m_bgSprite->setOpacity(75);
m_bgSprite->setContentSize({ width * 2, height * 2 });
m_bgSprite->setPosition(width / 2, height / 2);
this->addChild(m_bgSprite);
m_input = CCTextInputNode::create(width - 10.0f, height, placeholder, "Thonburi", 24, font);
m_input->setLabelPlaceholderColor({ 150, 150, 150 });
m_input->setLabelPlaceholderScale(.75f);
m_input->setMaxLabelScale(.85f);
m_input->setMaxLabelLength(maxCharCount);
m_input->setPosition(width / 2, height / 2);
m_input->setUserObject("fix-text-input", CCBool::create(true));
if (filter.length()) {
m_input->setAllowedChars(filter);
}
this->addChild(m_input);
this->setContentSize({ width, height });
this->setAnchorPoint({ .5f, .5f });
this->setCascadeColorEnabled(true);
this->setCascadeOpacityEnabled(true);
return true;
}
bool InputNode::init(
float width, char const* placeholder, char const* font, std::string const& filter,
int maxCharCount
) {
return init(width, 30.0f, placeholder, font, filter, maxCharCount);
}
InputNode* InputNode::create(
float width, char const* placeholder, char const* font, std::string const& filter,
int maxCharCount
) {
auto pRet = new InputNode();
if (pRet->init(width, placeholder, font, filter, maxCharCount)) {
pRet->autorelease();
return pRet;
}
delete pRet;
return nullptr;
}
InputNode* InputNode::create(float width, char const* placeholder, std::string const& filter) {
return create(width, placeholder, "bigFont.fnt", filter, 69);
}
InputNode* InputNode::create(
float width, char const* placeholder, std::string const& filter, int maxCharCount
) {
return create(width, placeholder, "bigFont.fnt", filter, maxCharCount);
}
InputNode* InputNode::create(float width, char const* placeholder, char const* font) {
return create(width, placeholder, font, "", 69);
}
InputNode* InputNode::create(float width, char const* placeholder) {
return create(width, placeholder, "bigFont.fnt");
}

View file

@ -317,21 +317,9 @@ struct MDParser {
auto split = splitOnce(s_lastImage, '?'); auto split = splitOnce(s_lastImage, '?');
s_lastImage = split.first; s_lastImage = split.first;
// TODO: remove this in v4.0.0 imgArguments = ranges::map<decltype(imgArguments)>(utils::string::split(split.second, "&"), [&](auto str) {
// check if this image is using the old format "my.mod/image.png&scale:0.5" return splitOnce(str, '=');
// this will be deprecated and then removed in the future });
if (utils::string::contains(s_lastImage, "&")) {
split = splitOnce(s_lastImage, '&');
s_lastImage = split.first;
imgArguments = ranges::map<decltype(imgArguments)>(utils::string::split(split.second, "&"), [&](auto str) {
return splitOnce(str, ':');
});
} else {
// new format "my.mod/image.png?scale=0.5"
imgArguments = ranges::map<decltype(imgArguments)>(utils::string::split(split.second, "&"), [&](auto str) {
return splitOnce(str, '=');
});
}
float spriteScale = 1.0f; float spriteScale = 1.0f;
float spriteWidth = 0.0f; float spriteWidth = 0.0f;

View file

@ -1,6 +1,5 @@
#include <Geode/Loader.hpp> #include <Geode/Loader.hpp>
#include <Geode/modify/MenuLayer.hpp> #include <Geode/modify/MenuLayer.hpp>
#include <Geode/loader/SettingNode.hpp>
#include <Geode/loader/Dispatch.hpp> #include <Geode/loader/Dispatch.hpp>
#include <Geode/Bindings.hpp> #include <Geode/Bindings.hpp>
#include "main.hpp" #include "main.hpp"
@ -30,119 +29,120 @@ constexpr Icon DEFAULT_ICON = Icon::Steve;
class MySettingValue; class MySettingValue;
class MySettingValue : public SettingValue { // TODO: v4 (port to new settings)
protected: // class MySettingValue : public SettingValue {
Icon m_icon; // protected:
// Icon m_icon;
public: // public:
MySettingValue(std::string const& key, std::string const& modID, Icon icon) // MySettingValue(std::string const& key, std::string const& modID, Icon icon)
: SettingValue(key, modID), m_icon(icon) {} // : SettingValue(key, modID), m_icon(icon) {}
bool load(matjson::Value const& json) override { // bool load(matjson::Value const& json) override {
if (!json.is<int>()) return false; // if (!json.is<int>()) return false;
m_icon = static_cast<Icon>(json.as<int>()); // m_icon = static_cast<Icon>(json.as<int>());
return true; // return true;
} // }
bool save(matjson::Value& json) const override { // bool save(matjson::Value& json) const override {
json = static_cast<int>(m_icon); // json = static_cast<int>(m_icon);
return true; // return true;
} // }
SettingNode* createNode(float width) override; // SettingNode* createNode(float width) override;
void setIcon(Icon icon) { // void setIcon(Icon icon) {
m_icon = icon; // m_icon = icon;
} // }
Icon getIcon() const { // Icon getIcon() const {
return m_icon; // return m_icon;
} // }
}; // };
class MySettingNode : public SettingNode { // class MySettingNode : public SettingNode {
protected: // protected:
Icon m_currentIcon; // Icon m_currentIcon;
std::vector<CCSprite*> m_sprites; // std::vector<CCSprite*> m_sprites;
bool init(MySettingValue* value, float width) { // bool init(MySettingValue* value, float width) {
if (!SettingNode::init(value)) // if (!SettingNode::init(value))
return false; // return false;
m_currentIcon = value->getIcon(); // m_currentIcon = value->getIcon();
this->setContentSize({ width, 40.f }); // this->setContentSize({ width, 40.f });
auto menu = CCMenu::create(); // auto menu = CCMenu::create();
menu->setPosition(width / 2, 20.f); // menu->setPosition(width / 2, 20.f);
float x = -75.f; // float x = -75.f;
for (auto& [spr, icon] : { // for (auto& [spr, icon] : {
std::pair { "GJ_square01.png", Icon::Steve, }, // std::pair { "GJ_square01.png", Icon::Steve, },
std::pair { "GJ_square02.png", Icon::Mike, }, // std::pair { "GJ_square02.png", Icon::Mike, },
std::pair { "GJ_square03.png", Icon::LazarithTheDestroyerOfForsakenSouls, }, // std::pair { "GJ_square03.png", Icon::LazarithTheDestroyerOfForsakenSouls, },
std::pair { "GJ_square04.png", Icon::Geoff, }, // std::pair { "GJ_square04.png", Icon::Geoff, },
}) { // }) {
auto btnSpr = CCSprite::create(spr); // auto btnSpr = CCSprite::create(spr);
btnSpr->setScale(.7f); // btnSpr->setScale(.7f);
m_sprites.push_back(btnSpr); // m_sprites.push_back(btnSpr);
if (icon == m_currentIcon) { // if (icon == m_currentIcon) {
btnSpr->setColor({ 0, 255, 0 }); // btnSpr->setColor({ 0, 255, 0 });
} else { // } else {
btnSpr->setColor({ 200, 200, 200 }); // btnSpr->setColor({ 200, 200, 200 });
} // }
auto btn = CCMenuItemSpriteExtra::create( // auto btn = CCMenuItemSpriteExtra::create(
btnSpr, this, menu_selector(MySettingNode::onSelect) // btnSpr, this, menu_selector(MySettingNode::onSelect)
); // );
btn->setTag(static_cast<int>(icon)); // btn->setTag(static_cast<int>(icon));
btn->setPosition(x, 0); // btn->setPosition(x, 0);
menu->addChild(btn); // menu->addChild(btn);
x += 50.f; // x += 50.f;
} // }
this->addChild(menu); // this->addChild(menu);
return true; // return true;
} // }
void onSelect(CCObject* sender) { // void onSelect(CCObject* sender) {
for (auto& spr : m_sprites) { // for (auto& spr : m_sprites) {
spr->setColor({ 200, 200, 200 }); // spr->setColor({ 200, 200, 200 });
} // }
m_currentIcon = static_cast<Icon>(sender->getTag()); // m_currentIcon = static_cast<Icon>(sender->getTag());
static_cast<CCSprite*>( // static_cast<CCSprite*>(
static_cast<CCMenuItemSpriteExtra*>(sender)->getNormalImage() // static_cast<CCMenuItemSpriteExtra*>(sender)->getNormalImage()
)->setColor({ 0, 255, 0 }); // )->setColor({ 0, 255, 0 });
this->dispatchChanged(); // this->dispatchChanged();
} // }
public: // public:
void commit() override { // void commit() override {
static_cast<MySettingValue*>(m_value)->setIcon(m_currentIcon); // static_cast<MySettingValue*>(m_value)->setIcon(m_currentIcon);
this->dispatchCommitted(); // this->dispatchCommitted();
} // }
bool hasUncommittedChanges() override { // bool hasUncommittedChanges() override {
return m_currentIcon != static_cast<MySettingValue*>(m_value)->getIcon(); // return m_currentIcon != static_cast<MySettingValue*>(m_value)->getIcon();
} // }
bool hasNonDefaultValue() override { // bool hasNonDefaultValue() override {
return m_currentIcon != DEFAULT_ICON; // return m_currentIcon != DEFAULT_ICON;
} // }
void resetToDefault() override { // void resetToDefault() override {
m_currentIcon = DEFAULT_ICON; // m_currentIcon = DEFAULT_ICON;
} // }
static MySettingNode* create(MySettingValue* value, float width) { // static MySettingNode* create(MySettingValue* value, float width) {
auto ret = new MySettingNode; // auto ret = new MySettingNode;
if (ret->init(value, width)) { // if (ret->init(value, width)) {
ret->autorelease(); // ret->autorelease();
return ret; // return ret;
} // }
delete ret; // delete ret;
return nullptr; // return nullptr;
} // }
}; // };
SettingNode* MySettingValue::createNode(float width) { // SettingNode* MySettingValue::createNode(float width) {
return MySettingNode::create(this, width); // return MySettingNode::create(this, width);
} // }
struct MyMenuLayer : Modify<MyMenuLayer, MenuLayer> { struct MyMenuLayer : Modify<MyMenuLayer, MenuLayer> {
void onMoreGames(CCObject*) { void onMoreGames(CCObject*) {
@ -161,7 +161,7 @@ struct MyMenuLayer : Modify<MyMenuLayer, MenuLayer> {
}; };
$on_mod(Loaded) { $on_mod(Loaded) {
Mod::get()->addCustomSetting<MySettingValue>("overcast-skies", DEFAULT_ICON); // Mod::get()->addCustomSetting<MySettingValue>("overcast-skies", DEFAULT_ICON);
(void)new EventListener(+[](GJGarageLayer* gl) { (void)new EventListener(+[](GJGarageLayer* gl) {
auto label = CCLabelBMFont::create("Dispatcher works!", "bigFont.fnt"); auto label = CCLabelBMFont::create("Dispatcher works!", "bigFont.fnt");