reworks on setting nodes; Custom setting types are now tested to work!
Some checks are pending
Build Binaries / Build Windows (push) Waiting to run
Build Binaries / Build macOS (push) Waiting to run
Build Binaries / Build Android (64-bit) (push) Waiting to run
Build Binaries / Build Android (32-bit) (push) Waiting to run
Build Binaries / Publish (push) Blocked by required conditions

This commit is contained in:
HJfod 2024-09-07 11:36:07 +03:00
parent fdcdfbd30c
commit 81d5dc0cae
7 changed files with 361 additions and 493 deletions

View file

@ -27,8 +27,8 @@ namespace geode {
protected:
void init(std::string const& key, std::string const& modID);
Result<> parseSharedProperties(std::string const& key, std::string const& modID, matjson::Value const& value, bool onlyNameAndDesc = false);
void parseSharedProperties(std::string const& key, std::string const& modID, JsonExpectedValue& value, bool onlyNameAndDesc = false);
Result<> parseBaseProperties(std::string const& key, std::string const& modID, matjson::Value const& value, bool onlyNameAndDesc = false);
void parseBaseProperties(std::string const& key, std::string const& modID, JsonExpectedValue& value, bool onlyNameAndDesc = false);
/**
* Mark that the value of this setting has changed. This should be
@ -103,46 +103,124 @@ namespace geode {
matjson::Value const& json
)>;
namespace detail {
template <class T, class V = T>
class GeodeSettingBaseValueV3 : public SettingV3 {
protected:
virtual T& getValueMut() const = 0;
template <class D>
void parseDefaultValue(JsonExpectedValue& json, D& defaultValue) {
auto value = json.needs("default");
// Check if this is a platform-specific default value
if (value.isObject() && value.has(GEODE_PLATFORM_SHORT_IDENTIFIER_NOARCH)) {
value.needs(GEODE_PLATFORM_SHORT_IDENTIFIER_NOARCH).into(defaultValue);
}
else {
value.into(defaultValue);
}
}
public:
using ValueType = T;
virtual T getDefaultValue() const = 0;
T getValue() const {
return this->getValueMut();
}
void setValue(V value) {
this->getValueMut() = this->isValid(value) ? value : this->getDefaultValue();
this->markChanged();
}
virtual Result<> isValid(V value) const = 0;
bool isDefaultValue() const override {
return this->getValue() == this->getDefaultValue();
}
void reset() override {
this->setValue(this->getDefaultValue());
}
/**
* A helper class for creating a basic setting with a simple value.
* Override the virtual function `isValid` to
* @tparam T The type of the setting's value. This type must be JSON-
* serializable and deserializable!
* @tparam V The type used for the `setValue` function, if it differs from T
*/
template <class T, class V = T>
class SettingBaseValueV3 : public SettingV3 {
private:
class Impl final {
private:
T defaultValue;
T value;
friend class SettingBaseValueV3;
};
}
std::shared_ptr<Impl> m_impl;
protected:
/**
* Parse shared value, including the default value for this setting
* @param key The key of the setting
* @param modID The ID of the mod this setting is being parsed for
* @param json The current JSON checking instance being used. If you
* aren't using Geode's JSON checking utilities, use the other overload
* of this function
*/
void parseBaseProperties(std::string const& key, std::string const& modID, JsonExpectedValue& json) {
SettingV3::parseBaseProperties(key, modID, json, false);
auto root = json.needs("default");
// Check if this is a platform-specific default value
if (root.isObject() && root.has(GEODE_PLATFORM_SHORT_IDENTIFIER_NOARCH)) {
root.needs(GEODE_PLATFORM_SHORT_IDENTIFIER_NOARCH).into(m_impl->defaultValue);
}
else {
root.into(m_impl->defaultValue);
}
m_impl->value = m_impl->defaultValue;
}
/**
* Parse shared value, including the default value for this setting
* @param key The key of the setting
* @param modID The ID of the mod this setting is being parsed for
* @param json The JSON value. If you are using Geode's JSON checking
* utilities (`checkJson` / `JsonExpectedValue`), you should use the
* other overload directly!
*/
Result<> parseBaseProperties(std::string const& key, std::string const& modID, matjson::Value const& json) {
auto root = checkJson(json, "SettingBaseValueV3");
this->parseBaseProperties(key, modID, root);
return root.ok();
}
/**
* Set the default value. This does not check that the value is
* actually valid!
*/
void setDefaultValue(V value) {
m_impl->defaultValue = value;
}
public:
SettingBaseValueV3() : m_impl(std::make_shared<Impl>()) {}
using ValueType = T;
using ValueAssignType = V;
/**
* Get the default value for this setting
*/
T getDefaultValue() const {
return m_impl->defaultValue;
}
/**
* Get the current value of this setting
*/
T getValue() const {
return m_impl->value;
}
/**
* Set the value of this setting. This will broadcast a new
* SettingChangedEventV3, letting any listeners now the value has changed
* @param value The new value for the setting. If the value is not a
* valid value for this setting (as determined by `isValue`), then the
* setting's value is reset to the default value
*/
void setValue(V value) {
m_impl->value = this->isValid(value) ? value : m_impl->defaultValue;
this->markChanged();
}
/**
* Check if a given value is valid for this setting. If not, an error
* describing why the value isn't valid is returned
*/
virtual Result<> isValid(V value) const {
return Ok();
}
bool isDefaultValue() const override {
return m_impl->value == m_impl->defaultValue;
}
void reset() override {
this->setValue(m_impl->defaultValue);
}
bool load(matjson::Value const& json) override {
if (json.template is<T>()) {
m_impl->value = json.template as<T>();
return true;
}
return false;
}
bool save(matjson::Value& json) const override {
json = m_impl->value;
return true;
}
};
class GEODE_DLL TitleSettingV3 final : public SettingV3 {
private:
@ -196,14 +274,11 @@ namespace geode {
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
};
class GEODE_DLL BoolSettingV3 final : public detail::GeodeSettingBaseValueV3<bool> {
class GEODE_DLL BoolSettingV3 final : public SettingBaseValueV3<bool> {
private:
class Impl;
std::shared_ptr<Impl> m_impl;
protected:
bool& getValueMut() const override;
private:
class PrivateMarker {};
friend class SettingV3;
@ -212,25 +287,19 @@ namespace geode {
BoolSettingV3(PrivateMarker);
static Result<std::shared_ptr<BoolSettingV3>> parse(std::string const& key, std::string const& modID, matjson::Value const& json);
bool getDefaultValue() const override;
Result<> isValid(bool value) const override;
bool load(matjson::Value const& json) override;
bool save(matjson::Value& json) const 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 detail::GeodeSettingBaseValueV3<int64_t> {
class GEODE_DLL IntSettingV3 final : public SettingBaseValueV3<int64_t> {
private:
class Impl;
std::shared_ptr<Impl> m_impl;
protected:
int64_t& getValueMut() const override;
private:
class PrivateMarker {};
friend class SettingV3;
@ -239,7 +308,6 @@ namespace geode {
IntSettingV3(PrivateMarker);
static Result<std::shared_ptr<IntSettingV3>> parse(std::string const& key, std::string const& modID, matjson::Value const& json);
int64_t getDefaultValue() const override;
Result<> isValid(int64_t value) const override;
std::optional<int64_t> getMinValue() const;
@ -253,22 +321,17 @@ namespace geode {
std::optional<int64_t> getSliderSnap() const;
bool isInputEnabled() const;
bool load(matjson::Value const& json) override;
bool save(matjson::Value& json) const 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 detail::GeodeSettingBaseValueV3<double> {
class GEODE_DLL FloatSettingV3 final : public SettingBaseValueV3<double> {
private:
class Impl;
std::shared_ptr<Impl> m_impl;
protected:
double& getValueMut() const override;
private:
class PrivateMarker {};
friend class SettingV3;
@ -277,7 +340,6 @@ namespace geode {
FloatSettingV3(PrivateMarker);
static Result<std::shared_ptr<FloatSettingV3>> parse(std::string const& key, std::string const& modID, matjson::Value const& json);
double getDefaultValue() const override;
Result<> isValid(double value) const override;
std::optional<double> getMinValue() const;
@ -291,22 +353,17 @@ namespace geode {
std::optional<double> getSliderSnap() const;
bool isInputEnabled() const;
bool load(matjson::Value const& json) override;
bool save(matjson::Value& json) const 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 detail::GeodeSettingBaseValueV3<std::string, std::string_view> {
class GEODE_DLL StringSettingV3 final : public SettingBaseValueV3<std::string, std::string_view> {
private:
class Impl;
std::shared_ptr<Impl> m_impl;
protected:
std::string& getValueMut() const override;
private:
class PrivateMarker {};
friend class SettingV3;
@ -315,29 +372,23 @@ namespace geode {
StringSettingV3(PrivateMarker);
static Result<std::shared_ptr<StringSettingV3>> parse(std::string const& key, std::string const& modID, matjson::Value const& json);
std::string getDefaultValue() const override;
Result<> isValid(std::string_view value) const override;
std::optional<std::string> getRegexValidator() const;
std::optional<std::string> getAllowedCharacters() const;
std::optional<std::vector<std::string>> getEnumOptions() const;
bool load(matjson::Value const& json) override;
bool save(matjson::Value& json) const 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 detail::GeodeSettingBaseValueV3<std::filesystem::path, std::filesystem::path const&> {
class GEODE_DLL FileSettingV3 final : public SettingBaseValueV3<std::filesystem::path, std::filesystem::path const&> {
private:
class Impl;
std::shared_ptr<Impl> m_impl;
protected:
std::filesystem::path& getValueMut() const override;
private:
class PrivateMarker {};
friend class SettingV3;
@ -346,7 +397,6 @@ namespace geode {
FileSettingV3(PrivateMarker);
static Result<std::shared_ptr<FileSettingV3>> parse(std::string const& key, std::string const& modID, matjson::Value const& json);
std::filesystem::path getDefaultValue() const override;
Result<> isValid(std::filesystem::path const& value) const override;
bool isFolder() const;
@ -354,22 +404,17 @@ namespace geode {
std::optional<std::vector<utils::file::FilePickOptions::Filter>> getFilters() const;
bool load(matjson::Value const& json) override;
bool save(matjson::Value& json) const 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 detail::GeodeSettingBaseValueV3<cocos2d::ccColor3B> {
class GEODE_DLL Color3BSettingV3 final : public SettingBaseValueV3<cocos2d::ccColor3B> {
private:
class Impl;
std::shared_ptr<Impl> m_impl;
protected:
cocos2d::ccColor3B& getValueMut() const override;
private:
class PrivateMarker {};
friend class SettingV3;
@ -378,25 +423,19 @@ namespace geode {
Color3BSettingV3(PrivateMarker);
static Result<std::shared_ptr<Color3BSettingV3>> parse(std::string const& key, std::string const& modID, matjson::Value const& json);
cocos2d::ccColor3B getDefaultValue() const override;
Result<> isValid(cocos2d::ccColor3B value) const override;
bool load(matjson::Value const& json) override;
bool save(matjson::Value& json) const 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 detail::GeodeSettingBaseValueV3<cocos2d::ccColor4B> {
class GEODE_DLL Color4BSettingV3 final : public SettingBaseValueV3<cocos2d::ccColor4B> {
private:
class Impl;
std::shared_ptr<Impl> m_impl;
protected:
cocos2d::ccColor4B& getValueMut() const override;
private:
class PrivateMarker {};
friend class SettingV3;
@ -405,11 +444,8 @@ namespace geode {
Color4BSettingV3(PrivateMarker);
static Result<std::shared_ptr<Color4BSettingV3>> parse(std::string const& key, std::string const& modID, matjson::Value const& json);
cocos2d::ccColor4B getDefaultValue() const override;
Result<> isValid(cocos2d::ccColor4B value) const override;
bool load(matjson::Value const& json) override;
bool save(matjson::Value& json) const override;
SettingNodeV3* createNode(float width) override;
std::optional<Setting> convertToLegacy() const override;
@ -426,13 +462,28 @@ namespace geode {
protected:
bool init(std::shared_ptr<SettingV3> setting, float width);
virtual void updateState();
/**
* Update the state of this setting node, bringing all inputs
* up-to-date with the current value. Derivatives of `SettingNodeV3`
* should set update the state (such as visibility, value, etc.) of all
* its controls, except for the one that's passed as the `invoker`
* argument. Derivatives should remember to **always call the base
* class's `updateState` function**, as it updates the built-in title
* label as well as the description and reset buttons!
* @param invoker The button or other interactive element that caused
* this state update. If that element is for example a text input, it
* may wish to ignore the state update, as it itself is the source of
* truth for the node's value at that moment. May be nullptr to mark
* that no specific node requested this state update
*/
virtual void updateState(cocos2d::CCNode* invoker);
/**
* Mark this setting as changed. This updates the UI for committing
* the value
* the value, as well as posts a `SettingNodeValueChangeEventV3`
* @param invoker The node to be passed onto `updateState`
*/
void markChanged();
void markChanged(cocos2d::CCNode* invoker);
/**
* When the setting value is committed (aka can't be undone), this
@ -453,17 +504,68 @@ namespace geode {
// Can be overridden by the setting itself
// Can / should be used to do alternating BG
void setBGColor(cocos2d::ccColor4B const& color);
void setDefaultBGColor(cocos2d::ccColor4B color);
cocos2d::CCLabelBMFont* getNameLabel() const;
cocos2d::CCMenu* getNameMenu() const;
cocos2d::CCMenu* getButtonMenu() const;
cocos2d::CCLayerColor* getBG() const;
void setContentSize(cocos2d::CCSize const& size) override;
std::shared_ptr<SettingV3> getSetting() const;
};
/**
* Helper class for creating `SettingNode`s for simple settings that
* implement `SettingBaseValueV3`
*/
template <class S>
class SettingValueNodeV3 : public SettingNodeV3 {
protected:
bool init(std::shared_ptr<S> setting, float width) {
if (!SettingNodeV3::init(setting, width))
return false;
return true;
}
void onCommit() override {
this->getSetting()->setValue(this->getValue());
}
bool hasUncommittedChanges() const override {
return this->getValue() != this->getSetting()->getValue();
}
bool hasNonDefaultValue() const override {
return this->getValue() != this->getSetting()->getDefaultValue();
}
void onResetToDefault() override {
this->setValue(this->getSetting()->getDefaultValue(), nullptr);
}
virtual void onSetValue(typename S::ValueAssignType value) = 0;
public:
/**
* Get the **uncommitted** value for this node
*/
virtual typename S::ValueType getValue() const = 0;
/**
* Set the **uncommitted** value for this node
* @param value The value to set
* @param invoker The node that invoked this value change; see the docs
* for `SettingNodeV3::updateState` to know more
*/
void setValue(typename S::ValueAssignType value, cocos2d::CCNode* invoker) {
this->onSetValue(value);
this->markChanged(invoker);
}
std::shared_ptr<S> getSetting() const {
return std::static_pointer_cast<S>(SettingNodeV3::getSetting());
}
};
class GEODE_DLL SettingChangedEventV3 final : public Event {
private:
class Impl;

View file

@ -92,7 +92,7 @@
"name": "Show Platform Console",
"description": "Show the native console (if one exists). <cr>This setting is meant for developers</c>",
"platforms": ["win", "mac"],
"restart-required": true
"requires-restart": true
},
"server-cache-size-limit": {
"type": "int",

View file

@ -52,17 +52,25 @@ public:
return Ok();
}
std::optional<SettingGenerator> find(std::string_view modID, std::string_view fullType) {
auto full = std::string(
fullType.starts_with("custom:") ?
fullType.substr(fullType.find(':') + 1) :
fullType
);
if (!full.find('/')) {
full = fmt::format("{}/{}", modID, full);
// Find custom settings via namespaced lookup
if (fullType.starts_with("custom:")) {
auto full = std::string(fullType.substr(fullType.find(':') + 1));
// If there's no mod ID in the type name, use the current mod's ID
if (full.find('/') == std::string_view::npos) {
full = fmt::format("{}/{}", modID, full);
}
if (m_types.contains(full)) {
return m_types.at(full);
}
}
if (m_types.contains(full)) {
return m_types.at(full);
// Otherwise find a built-in setting
else {
auto full = std::string(fullType);
if (m_types.contains(full)) {
return m_types.at(full);
}
}
// Return null if nothing was found
return std::nullopt;
}
};
@ -171,12 +179,15 @@ Result<> ModSettingsManager::load(matjson::Value const& json) {
auto root = checkJson(json, "Settings");
for (auto const& [key, value] : root.properties()) {
if (m_impl->settings.contains(key)) {
auto& sett = m_impl->settings.at(key);
if (!sett.v3) continue;
try {
if (!m_impl->settings.at(key).v3->load(value.json())) {
if (!sett.v3->load(value.json())) {
log::error("Unable to load setting '{}' for mod {}", key, m_impl->modID);
}
}
catch(matjson::JsonException const& e) {
// matjson::JsonException doesn't catch all possible json errors
catch(std::exception const& e) {
log::error("Unable to load setting '{}' for mod {} (JSON exception): {}", key, m_impl->modID, e.what());
}
}

View file

@ -56,6 +56,8 @@ public:
bool SettingNodeV3::init(std::shared_ptr<SettingV3> setting, float width) {
if (!CCNode::init())
return false;
// note: setting may be null due to UnresolvedCustomSettingNodeV3
m_impl = std::make_shared<Impl>();
m_impl->setting = setting;
@ -69,7 +71,7 @@ bool SettingNodeV3::init(std::shared_ptr<SettingV3> setting, float width) {
m_impl->nameMenu = CCMenu::create();
m_impl->nameMenu->setContentWidth(width / 2 + 25);
m_impl->nameLabel = CCLabelBMFont::create(setting->getDisplayName().c_str(), "bigFont.fnt");
m_impl->nameLabel = CCLabelBMFont::create(setting ? setting->getDisplayName().c_str() : "", "bigFont.fnt");
m_impl->nameLabel->setLayoutOptions(AxisLayoutOptions::create()->setScaleLimits(.1f, .4f)->setScalePriority(1));
m_impl->nameMenu->addChild(m_impl->nameLabel);
@ -77,7 +79,7 @@ bool SettingNodeV3::init(std::shared_ptr<SettingV3> setting, float width) {
m_impl->errorLabel->setScale(.25f);
this->addChildAtPosition(m_impl->errorLabel, Anchor::Left, ccp(10, -10), ccp(0, .5f));
if (setting->getDescription()) {
if (setting && setting->getDescription()) {
auto descSpr = CCSprite::createWithSpriteFrameName("GJ_infoIcon_001.png");
descSpr->setScale(.5f);
auto descBtn = CCMenuItemSpriteExtra::create(
@ -108,7 +110,7 @@ bool SettingNodeV3::init(std::shared_ptr<SettingV3> setting, float width) {
return true;
}
void SettingNodeV3::updateState() {
void SettingNodeV3::updateState(CCNode* invoker) {
m_impl->errorLabel->setVisible(false);
m_impl->nameLabel->setColor(this->hasUncommittedChanges() ? ccc3(17, 221, 0) : ccWHITE);
@ -117,7 +119,7 @@ void SettingNodeV3::updateState() {
m_impl->bg->setColor(to3B(m_impl->bgColor));
m_impl->bg->setOpacity(m_impl->bgColor.a);
if (!m_impl->setting->shouldEnable()) {
if (m_impl->setting && !m_impl->setting->shouldEnable()) {
if (auto desc = m_impl->setting->getEnableIfDescription()) {
m_impl->nameLabel->setColor(ccGRAY);
m_impl->errorLabel->setVisible(true);
@ -125,7 +127,7 @@ void SettingNodeV3::updateState() {
m_impl->errorLabel->setString(desc->c_str());
}
}
if (m_impl->setting->requiresRestart() && m_impl->committed) {
if (m_impl->setting && m_impl->setting->requiresRestart() && m_impl->committed) {
m_impl->errorLabel->setVisible(true);
m_impl->errorLabel->setColor("mod-list-restart-required-label"_cc3b);
m_impl->errorLabel->setString("Restart Required");
@ -133,6 +135,7 @@ void SettingNodeV3::updateState() {
m_impl->bg->setOpacity(75);
}
m_impl->nameMenu->setContentWidth(this->getContentWidth() - m_impl->buttonMenu->getContentWidth() - 20);
m_impl->nameMenu->updateLayout();
}
@ -162,26 +165,27 @@ void SettingNodeV3::onReset(CCObject*) {
);
}
void SettingNodeV3::setBGColor(ccColor4B const& color) {
void SettingNodeV3::setDefaultBGColor(ccColor4B color) {
m_impl->bgColor = color;
this->updateState();
this->updateState(nullptr);
}
void SettingNodeV3::markChanged() {
this->updateState();
void SettingNodeV3::markChanged(CCNode* invoker) {
this->updateState(invoker);
SettingNodeValueChangeEventV3(this, false).post();
}
void SettingNodeV3::commit() {
this->onCommit();
m_impl->committed = true;
this->updateState();
this->updateState(nullptr);
SettingNodeValueChangeEventV3(this, true).post();
}
void SettingNodeV3::resetToDefault() {
if (!m_impl->setting) return;
m_impl->setting->reset();
m_impl->committed = true;
this->onResetToDefault();
this->updateState();
this->updateState(nullptr);
SettingNodeValueChangeEventV3(this, false).post();
}
@ -201,6 +205,9 @@ CCMenu* SettingNodeV3::getNameMenu() const {
CCMenu* SettingNodeV3::getButtonMenu() const {
return m_impl->buttonMenu;
}
CCLayerColor* SettingNodeV3::getBG() const {
return m_impl->bg;
}
std::shared_ptr<SettingV3> SettingNodeV3::getSetting() const {
return m_impl->setting;
@ -215,7 +222,7 @@ bool TitleSettingNodeV3::init(std::shared_ptr<TitleSettingV3> setting, float wid
this->getNameLabel()->setFntFile("goldFont.fnt");
this->getNameMenu()->updateLayout();
this->setContentHeight(20);
this->updateState();
this->updateState(nullptr);
return true;
}
@ -247,12 +254,10 @@ TitleSettingNodeV3* TitleSettingNodeV3::create(std::shared_ptr<TitleSettingV3> s
// BoolSettingNodeV3
bool BoolSettingNodeV3::init(std::shared_ptr<BoolSettingV3> setting, float width) {
if (!SettingNodeV3::init(setting, width))
if (!SettingValueNodeV3::init(setting, width))
return false;
this->getButtonMenu()->setContentWidth(20);
this->getNameMenu()->setContentWidth(width - 50);
this->getNameMenu()->updateLayout();
m_toggle = CCMenuItemToggler::createWithStandardSprites(
this, menu_selector(BoolSettingNodeV3::onToggle), .55f
@ -265,13 +270,13 @@ bool BoolSettingNodeV3::init(std::shared_ptr<BoolSettingV3> setting, float width
m_toggle->toggle(setting->getValue());
this->getButtonMenu()->addChildAtPosition(m_toggle, Anchor::Right, ccp(-10, 0));
this->updateState();
this->updateState(nullptr);
return true;
}
void BoolSettingNodeV3::updateState() {
SettingNodeV3::updateState();
void BoolSettingNodeV3::updateState(CCNode* invoker) {
SettingNodeV3::updateState(invoker);
auto enable = this->getSetting()->shouldEnable();
m_toggle->setCascadeColorEnabled(true);
m_toggle->setCascadeOpacityEnabled(true);
@ -280,26 +285,16 @@ void BoolSettingNodeV3::updateState() {
m_toggle->setOpacity(enable ? 255 : 155);
}
void BoolSettingNodeV3::onCommit() {
this->getSetting()->setValue(m_toggle->isToggled());
}
void BoolSettingNodeV3::onToggle(CCObject*) {
m_toggle->toggle(!m_toggle->isToggled());
this->markChanged();
this->markChanged(m_toggle);
}
bool BoolSettingNodeV3::hasUncommittedChanges() const {
return m_toggle->isToggled() != this->getSetting()->getValue();
bool BoolSettingNodeV3::getValue() const {
return m_toggle->isToggled();
}
bool BoolSettingNodeV3::hasNonDefaultValue() const {
return m_toggle->isToggled() != this->getSetting()->getDefaultValue();
}
void BoolSettingNodeV3::onResetToDefault() {
m_toggle->toggle(this->getSetting()->getDefaultValue());
}
std::shared_ptr<BoolSettingV3> BoolSettingNodeV3::getSetting() const {
return std::static_pointer_cast<BoolSettingV3>(SettingNodeV3::getSetting());
void BoolSettingNodeV3::onSetValue(bool value) {
m_toggle->toggle(value);
}
BoolSettingNodeV3* BoolSettingNodeV3::create(std::shared_ptr<BoolSettingV3> setting, float width) {
@ -315,12 +310,12 @@ BoolSettingNodeV3* BoolSettingNodeV3::create(std::shared_ptr<BoolSettingV3> sett
// StringSettingNodeV3
bool StringSettingNodeV3::init(std::shared_ptr<StringSettingV3> setting, float width) {
if (!SettingNodeV3::init(setting, width))
if (!SettingValueNodeV3::init(setting, width))
return false;
m_input = TextInput::create(setting->getEnumOptions() ? width / 2 - 50 : width / 2, "Text");
m_input->setCallback([this](auto const&) {
this->markChanged();
this->markChanged(m_input);
});
m_input->setScale(.7f);
m_input->setString(this->getSetting()->getValue());
@ -350,13 +345,13 @@ bool StringSettingNodeV3::init(std::shared_ptr<StringSettingV3> setting, float w
this->getButtonMenu()->addChildAtPosition(arrowRightBtn, Anchor::Right, ccp(-5, 0));
}
this->updateState();
this->updateState(nullptr);
return true;
}
void StringSettingNodeV3::updateState() {
SettingNodeV3::updateState();
void StringSettingNodeV3::updateState(CCNode* invoker) {
SettingNodeV3::updateState(invoker);
auto enable = this->getSetting()->shouldEnable();
if (!this->getSetting()->getEnumOptions()) {
m_input->setEnabled(enable);
@ -379,24 +374,14 @@ void StringSettingNodeV3::onArrow(CCObject* sender) {
index = index > 0 ? index - 1 : options.size() - 1;
}
m_input->setString(options.at(index));
this->updateState();
this->updateState(static_cast<CCNode*>(sender));
}
void StringSettingNodeV3::onCommit() {
this->getSetting()->setValue(m_input->getString());
std::string StringSettingNodeV3::getValue() const {
return m_input->getString();
}
bool StringSettingNodeV3::hasUncommittedChanges() const {
return m_input->getString() != this->getSetting()->getValue();
}
bool StringSettingNodeV3::hasNonDefaultValue() const {
return m_input->getString() != this->getSetting()->getDefaultValue();
}
void StringSettingNodeV3::onResetToDefault() {
m_input->setString(this->getSetting()->getDefaultValue());
}
std::shared_ptr<StringSettingV3> StringSettingNodeV3::getSetting() const {
return std::static_pointer_cast<StringSettingV3>(SettingNodeV3::getSetting());
void StringSettingNodeV3::onSetValue(std::string_view value) {
m_input->setString(std::string(value));
}
StringSettingNodeV3* StringSettingNodeV3::create(std::shared_ptr<StringSettingV3> setting, float width) {
@ -412,7 +397,7 @@ StringSettingNodeV3* StringSettingNodeV3::create(std::shared_ptr<StringSettingV3
// FileSettingNodeV3
bool FileSettingNodeV3::init(std::shared_ptr<FileSettingV3> setting, float width) {
if (!SettingNodeV3::init(setting, width))
if (!SettingValueNodeV3::init(setting, width))
return false;
m_path = setting->getValue();
@ -437,13 +422,13 @@ bool FileSettingNodeV3::init(std::shared_ptr<FileSettingV3> setting, float width
);
this->getButtonMenu()->addChildAtPosition(m_selectBtn, Anchor::Right, ccp(-5, 0));
this->updateState();
this->updateState(nullptr);
return true;
}
void FileSettingNodeV3::updateState() {
SettingNodeV3::updateState();
void FileSettingNodeV3::updateState(CCNode* invoker) {
SettingNodeV3::updateState(invoker);
m_fileIcon->setDisplayFrame(CCSpriteFrameCache::get()->spriteFrameByName(
this->getSetting()->isFolder() ? "folderIcon_001.png" : "file.png"_spr
));
@ -474,7 +459,7 @@ void FileSettingNodeV3::onPickFile(CCObject*) {
}
if (value->isOk()) {
m_path = value->unwrap().string();
this->markChanged();
this->markChanged(nullptr);
}
else {
FLAlertLayer::create(
@ -497,21 +482,11 @@ void FileSettingNodeV3::onPickFile(CCObject*) {
));
}
void FileSettingNodeV3::onCommit() {
this->getSetting()->setValue(m_path);
std::filesystem::path FileSettingNodeV3::getValue() const {
return m_path;
}
bool FileSettingNodeV3::hasUncommittedChanges() const {
return m_path != this->getSetting()->getValue();
}
bool FileSettingNodeV3::hasNonDefaultValue() const {
return m_path != this->getSetting()->getDefaultValue();
}
void FileSettingNodeV3::onResetToDefault() {
m_path = this->getSetting()->getDefaultValue();
}
std::shared_ptr<FileSettingV3> FileSettingNodeV3::getSetting() const {
return std::static_pointer_cast<FileSettingV3>(SettingNodeV3::getSetting());
void FileSettingNodeV3::onSetValue(std::filesystem::path const& value) {
m_path = value;
}
FileSettingNodeV3* FileSettingNodeV3::create(std::shared_ptr<FileSettingV3> setting, float width) {
@ -527,7 +502,7 @@ FileSettingNodeV3* FileSettingNodeV3::create(std::shared_ptr<FileSettingV3> sett
// Color3BSettingNodeV3
bool Color3BSettingNodeV3::init(std::shared_ptr<Color3BSettingV3> setting, float width) {
if (!SettingNodeV3::init(setting, width))
if (!SettingValueNodeV3::init(setting, width))
return false;
m_value = setting->getValue();
@ -540,13 +515,13 @@ bool Color3BSettingNodeV3::init(std::shared_ptr<Color3BSettingV3> setting, float
);
this->getButtonMenu()->addChildAtPosition(m_colorBtn, Anchor::Right, ccp(-10, 0));
this->updateState();
this->updateState(nullptr);
return true;
}
void Color3BSettingNodeV3::updateState() {
SettingNodeV3::updateState();
void Color3BSettingNodeV3::updateState(CCNode* invoker) {
SettingNodeV3::updateState(invoker);
m_colorSprite->setColor(m_value);
auto enable = this->getSetting()->shouldEnable();
@ -561,24 +536,14 @@ void Color3BSettingNodeV3::onSelectColor(CCObject*) {
}
void Color3BSettingNodeV3::updateColor(ccColor4B const& color) {
m_value = to3B(color);
this->markChanged();
this->markChanged(nullptr);
}
void Color3BSettingNodeV3::onCommit() {
this->getSetting()->setValue(m_value);
ccColor3B Color3BSettingNodeV3::getValue() const {
return m_value;
}
bool Color3BSettingNodeV3::hasUncommittedChanges() const {
return m_value != this->getSetting()->getValue();
}
bool Color3BSettingNodeV3::hasNonDefaultValue() const {
return m_value != this->getSetting()->getDefaultValue();
}
void Color3BSettingNodeV3::onResetToDefault() {
m_value = this->getSetting()->getDefaultValue();
}
std::shared_ptr<Color3BSettingV3> Color3BSettingNodeV3::getSetting() const {
return std::static_pointer_cast<Color3BSettingV3>(SettingNodeV3::getSetting());
void Color3BSettingNodeV3::onSetValue(ccColor3B value) {
m_value = value;
}
Color3BSettingNodeV3* Color3BSettingNodeV3::create(std::shared_ptr<Color3BSettingV3> setting, float width) {
@ -594,7 +559,7 @@ Color3BSettingNodeV3* Color3BSettingNodeV3::create(std::shared_ptr<Color3BSettin
// Color4BSettingNodeV3
bool Color4BSettingNodeV3::init(std::shared_ptr<Color4BSettingV3> setting, float width) {
if (!SettingNodeV3::init(setting, width))
if (!SettingValueNodeV3::init(setting, width))
return false;
m_value = setting->getValue();
@ -607,13 +572,13 @@ bool Color4BSettingNodeV3::init(std::shared_ptr<Color4BSettingV3> setting, float
);
this->getButtonMenu()->addChildAtPosition(m_colorBtn, Anchor::Right, ccp(-10, 0));
this->updateState();
this->updateState(nullptr);
return true;
}
void Color4BSettingNodeV3::updateState() {
SettingNodeV3::updateState();
void Color4BSettingNodeV3::updateState(CCNode* invoker) {
SettingNodeV3::updateState(invoker);
m_colorSprite->setColor(to3B(m_value));
m_colorSprite->updateOpacity(m_value.a / 255.f);
@ -629,24 +594,14 @@ void Color4BSettingNodeV3::onSelectColor(CCObject*) {
}
void Color4BSettingNodeV3::updateColor(ccColor4B const& color) {
m_value = color;
this->markChanged();
this->markChanged(nullptr);
}
void Color4BSettingNodeV3::onCommit() {
this->getSetting()->setValue(m_value);
ccColor4B Color4BSettingNodeV3::getValue() const {
return m_value;
}
bool Color4BSettingNodeV3::hasUncommittedChanges() const {
return m_value != this->getSetting()->getValue();
}
bool Color4BSettingNodeV3::hasNonDefaultValue() const {
return m_value != this->getSetting()->getDefaultValue();
}
void Color4BSettingNodeV3::onResetToDefault() {
m_value = this->getSetting()->getDefaultValue();
}
std::shared_ptr<Color4BSettingV3> Color4BSettingNodeV3::getSetting() const {
return std::static_pointer_cast<Color4BSettingV3>(SettingNodeV3::getSetting());
void Color4BSettingNodeV3::onSetValue(ccColor4B value) {
m_value = value;
}
Color4BSettingNodeV3* Color4BSettingNodeV3::create(std::shared_ptr<Color4BSettingV3> setting, float width) {
@ -661,22 +616,29 @@ Color4BSettingNodeV3* Color4BSettingNodeV3::create(std::shared_ptr<Color4BSettin
// UnresolvedCustomSettingNodeV3
bool UnresolvedCustomSettingNodeV3::init(std::shared_ptr<LegacyCustomSettingV3> setting, float width) {
if (!SettingNodeV3::init(setting, width))
bool UnresolvedCustomSettingNodeV3::init(std::string_view key, float width) {
if (!SettingNodeV3::init(nullptr, width))
return false;
this->setContentHeight(30);
auto label = CCLabelBMFont::create(
fmt::format("Missing setting '{}'", setting->getKey()).c_str(),
fmt::format("Missing setting '{}'", key).c_str(),
"bigFont.fnt"
);
label->limitLabelWidth(width - m_obContentSize.height, .5f, .1f);
this->addChildAtPosition(label, Anchor::Left, ccp(m_obContentSize.height / 2, 0));
label->setColor("mod-list-errors-found-2"_cc3b);
label->limitLabelWidth(width - m_obContentSize.height, .3f, .1f);
this->addChildAtPosition(label, Anchor::Left, ccp(m_obContentSize.height / 2, 0), ccp(0, .5f));
return true;
}
void UnresolvedCustomSettingNodeV3::updateState(CCNode* invoker) {
SettingNodeV3::updateState(invoker);
this->getBG()->setColor("mod-list-errors-found"_cc3b);
this->getBG()->setOpacity(75);
}
void UnresolvedCustomSettingNodeV3::onCommit() {}
bool UnresolvedCustomSettingNodeV3::hasUncommittedChanges() const {
@ -687,13 +649,9 @@ bool UnresolvedCustomSettingNodeV3::hasNonDefaultValue() const {
}
void UnresolvedCustomSettingNodeV3::onResetToDefault() {}
std::shared_ptr<LegacyCustomSettingV3> UnresolvedCustomSettingNodeV3::getSetting() const {
return std::static_pointer_cast<LegacyCustomSettingV3>(SettingNodeV3::getSetting());
}
UnresolvedCustomSettingNodeV3* UnresolvedCustomSettingNodeV3::create(std::shared_ptr<LegacyCustomSettingV3> setting, float width) {
UnresolvedCustomSettingNodeV3* UnresolvedCustomSettingNodeV3::create(std::string_view key, float width) {
auto ret = new UnresolvedCustomSettingNodeV3();
if (ret && ret->init(setting, width)) {
if (ret && ret->init(key, width)) {
ret->autorelease();
return ret;
}

View file

@ -27,31 +27,26 @@ public:
std::shared_ptr<TitleSettingV3> getSetting() const;
};
class BoolSettingNodeV3 : public SettingNodeV3 {
class BoolSettingNodeV3 : public SettingValueNodeV3<BoolSettingV3> {
protected:
CCMenuItemToggler* m_toggle;
bool init(std::shared_ptr<BoolSettingV3> setting, float width);
void updateState() override;
void onCommit() override;
void updateState(CCNode* invoker) override;
void onToggle(CCObject*);
public:
static BoolSettingNodeV3* create(std::shared_ptr<BoolSettingV3> setting, float width);
bool hasUncommittedChanges() const override;
bool hasNonDefaultValue() const override;
void onResetToDefault() override;
bool getValue() const override;
void onSetValue(bool value) override;
std::shared_ptr<BoolSettingV3> getSetting() const;
static BoolSettingNodeV3* create(std::shared_ptr<BoolSettingV3> setting, float width);
};
template <class S>
class NumberSettingNodeV3 : public SettingNodeV3 {
class NumberSettingNodeV3 : public SettingValueNodeV3<S> {
protected:
using ValueType = typename S::ValueType;
using ValueAssignType = typename S::ValueAssignType;
TextInput* m_input;
Slider* m_slider;
@ -82,7 +77,7 @@ protected:
}
bool init(std::shared_ptr<S> setting, float width) {
if (!SettingNodeV3::init(setting, width))
if (!SettingValueNodeV3<S>::init(setting, width))
return false;
m_bigArrowLeftBtnSpr = CCSprite::create();
@ -115,7 +110,7 @@ protected:
m_input = TextInput::create(this->getButtonMenu()->getContentWidth() - 40, "Num");
m_input->setScale(.7f);
m_input->setCallback([this](auto const&) {
this->markChanged();
this->markChanged(m_input);
});
if (!setting->isInputEnabled()) {
m_input->getBGSprite()->setVisible(false);
@ -164,21 +159,21 @@ protected:
this->getButtonMenu()->addChildAtPosition(m_slider, Anchor::Center, ccp(0, -20), ccp(0, 0));
}
this->setCurrentValue(setting->getValue());
this->updateState();
this->setValue(setting->getValue(), nullptr);
this->updateState(nullptr);
return true;
}
void updateState() override {
SettingNodeV3::updateState();
void updateState(CCNode* invoker) override {
SettingNodeV3::updateState(invoker);
auto enable = this->getSetting()->shouldEnable();
if (this->getSetting()->isInputEnabled()) {
m_input->setEnabled(enable);
}
auto min = this->getSetting()->getMinValue();
auto enableLeft = enable && (!min || this->getCurrentValue() > *min);
auto enableLeft = enable && (!min || this->getValue() > *min);
m_arrowLeftBtn->setEnabled(enableLeft);
m_bigArrowLeftBtn->setEnabled(enableLeft);
m_arrowLeftBtnSpr->setOpacity(enableLeft ? 255 : 155);
@ -187,7 +182,7 @@ protected:
m_bigArrowLeftBtnSpr->setColor(enableLeft ? ccWHITE : ccGRAY);
auto max = this->getSetting()->getMaxValue();
auto enableRight = enable && (!max || this->getCurrentValue() < *max);
auto enableRight = enable && (!max || this->getValue() < *max);
m_arrowRightBtn->setEnabled(enableRight);
m_bigArrowRightBtn->setEnabled(enableRight);
m_arrowRightBtnSpr->setOpacity(enableRight ? 255 : 155);
@ -196,7 +191,7 @@ protected:
m_bigArrowRightBtnSpr->setColor(enableRight ? ccWHITE : ccGRAY);
if (m_slider) {
m_slider->m_touchLogic->m_thumb->setValue(this->valueToSlider(this->getCurrentValue()));
m_slider->m_touchLogic->m_thumb->setValue(this->valueToSlider(this->getValue()));
m_slider->updateBar();
m_slider->m_sliderBar->setColor(enable ? ccWHITE : ccGRAY);
m_slider->m_touchLogic->m_thumb->setColor(enable ? ccWHITE : ccGRAY);
@ -204,11 +199,8 @@ protected:
}
}
void onCommit() override {
this->getSetting()->setValue(this->getCurrentValue());
}
void onArrow(CCObject* sender) {
auto value = this->getCurrentValue() + static_cast<ObjWrapper<ValueType>*>(
auto value = this->getValue() + static_cast<ObjWrapper<ValueType>*>(
static_cast<CCNode*>(sender)->getUserObject()
)->getValue();
if (auto min = this->getSetting()->getMinValue()) {
@ -217,19 +209,18 @@ protected:
if (auto max = this->getSetting()->getMaxValue()) {
value = std::min(*max, value);
}
this->setCurrentValue(value);
this->setValue(value, static_cast<CCNode*>(sender));
}
void onSlider(CCObject*) {
this->setCurrentValue(this->valueFromSlider(m_slider->m_touchLogic->m_thumb->getValue()));
this->setValue(this->valueFromSlider(m_slider->m_touchLogic->m_thumb->getValue()), m_slider);
}
ValueType getCurrentValue() const {
ValueType getValue() const override {
return numFromString<ValueType>(m_input->getString())
.value_or(this->getSetting()->getDefaultValue());
}
void setCurrentValue(ValueType value) {
void onSetValue(ValueAssignType value) override {
m_input->setString(numToString(value));
this->markChanged();
}
public:
@ -242,50 +233,29 @@ public:
CC_SAFE_DELETE(ret);
return nullptr;
}
bool hasUncommittedChanges() const override {
return this->getSetting()->getValue() != this->getCurrentValue();
}
bool hasNonDefaultValue() const override {
return this->getSetting()->getDefaultValue() != this->getCurrentValue();
}
void onResetToDefault() override {
this->setCurrentValue(this->getSetting()->getDefaultValue());
}
std::shared_ptr<S> getSetting() const {
return std::static_pointer_cast<S>(SettingNodeV3::getSetting());
}
};
using IntSettingNodeV3 = NumberSettingNodeV3<IntSettingV3>;
using FloatSettingNodeV3 = NumberSettingNodeV3<FloatSettingV3>;
class StringSettingNodeV3 : public SettingNodeV3 {
class StringSettingNodeV3 : public SettingValueNodeV3<StringSettingV3> {
protected:
TextInput* m_input;
CCSprite* m_arrowLeftSpr = nullptr;
CCSprite* m_arrowRightSpr = nullptr;
bool init(std::shared_ptr<StringSettingV3> setting, float width);
void updateState() override;
void updateState(CCNode* invoker) override;
void onArrow(CCObject* sender);
void onCommit() override;
public:
static StringSettingNodeV3* create(std::shared_ptr<StringSettingV3> setting, float width);
bool hasUncommittedChanges() const override;
bool hasNonDefaultValue() const override;
void onResetToDefault() override;
std::shared_ptr<StringSettingV3> getSetting() const;
std::string getValue() const override;
void onSetValue(std::string_view value) override;
};
class FileSettingNodeV3 : public SettingNodeV3 {
class FileSettingNodeV3 : public SettingValueNodeV3<FileSettingV3> {
protected:
CCSprite* m_fileIcon;
std::filesystem::path m_path;
@ -295,84 +265,66 @@ protected:
CCSprite* m_selectBtnSpr;
bool init(std::shared_ptr<FileSettingV3> setting, float width);
void updateState() override;
void onCommit() override;
void updateState(CCNode* invoker) override;
void onPickFile(CCObject*);
public:
static FileSettingNodeV3* create(std::shared_ptr<FileSettingV3> setting, float width);
bool hasUncommittedChanges() const override;
bool hasNonDefaultValue() const override;
void onResetToDefault() override;
std::shared_ptr<FileSettingV3> getSetting() const;
std::filesystem::path getValue() const override;
void onSetValue(std::filesystem::path const& value) override;
};
class Color3BSettingNodeV3 : public SettingNodeV3, public ColorPickPopupDelegate {
class Color3BSettingNodeV3 : public SettingValueNodeV3<Color3BSettingV3>, public ColorPickPopupDelegate {
protected:
ccColor3B m_value;
CCMenuItemSpriteExtra* m_colorBtn;
ColorChannelSprite* m_colorSprite;
bool init(std::shared_ptr<Color3BSettingV3> setting, float width);
void updateState() override;
void onCommit() override;
void updateState(CCNode* invoker) override;
void onSelectColor(CCObject*);
void updateColor(ccColor4B const& color) override;
public:
static Color3BSettingNodeV3* create(std::shared_ptr<Color3BSettingV3> setting, float width);
bool hasUncommittedChanges() const override;
bool hasNonDefaultValue() const override;
void onResetToDefault() override;
std::shared_ptr<Color3BSettingV3> getSetting() const;
ccColor3B getValue() const override;
void onSetValue(ccColor3B value) override;
};
class Color4BSettingNodeV3 : public SettingNodeV3, public ColorPickPopupDelegate {
class Color4BSettingNodeV3 : public SettingValueNodeV3<Color4BSettingV3>, public ColorPickPopupDelegate {
protected:
ccColor4B m_value;
CCMenuItemSpriteExtra* m_colorBtn;
ColorChannelSprite* m_colorSprite;
bool init(std::shared_ptr<Color4BSettingV3> setting, float width);
void updateState() override;
void onCommit() override;
void updateState(CCNode* invoker) override;
void onSelectColor(CCObject*);
void updateColor(ccColor4B const& color) override;
public:
static Color4BSettingNodeV3* create(std::shared_ptr<Color4BSettingV3> setting, float width);
bool hasUncommittedChanges() const override;
bool hasNonDefaultValue() const override;
void onResetToDefault() override;
std::shared_ptr<Color4BSettingV3> getSetting() const;
ccColor4B getValue() const override;
void onSetValue(ccColor4B value) override;
};
class UnresolvedCustomSettingNodeV3 : public SettingNodeV3 {
protected:
bool init(std::shared_ptr<LegacyCustomSettingV3> setting, float width);
bool init(std::string_view key, float width);
void updateState(CCNode* invoker) override;
void onCommit() override;
public:
static UnresolvedCustomSettingNodeV3* create(std::shared_ptr<LegacyCustomSettingV3> setting, float width);
static UnresolvedCustomSettingNodeV3* create(std::string_view key, float width);
bool hasUncommittedChanges() const override;
bool hasNonDefaultValue() const override;
void onResetToDefault() override;
std::shared_ptr<LegacyCustomSettingV3> getSetting() const;
};
// If these classes do get exposed in headers,

View file

@ -471,12 +471,12 @@ public:
SettingV3::SettingV3() : m_impl(std::make_shared<GeodeImpl>()) {}
SettingV3::~SettingV3() = default;
Result<> SettingV3::parseSharedProperties(std::string const& key, std::string const& modID, matjson::Value const& value, bool onlyNameAndDesc) {
Result<> SettingV3::parseBaseProperties(std::string const& key, std::string const& modID, matjson::Value const& value, bool onlyNameAndDesc) {
auto json = checkJson(value, "SettingV3");
this->parseSharedProperties(key, modID, json, onlyNameAndDesc);
this->parseBaseProperties(key, modID, json, onlyNameAndDesc);
return json.ok();
}
void SettingV3::parseSharedProperties(std::string const& key, std::string const& modID, JsonExpectedValue& value, bool onlyNameAndDesc) {
void SettingV3::parseBaseProperties(std::string const& key, std::string const& modID, JsonExpectedValue& value, bool onlyNameAndDesc) {
this->init(key, modID);
value.needs("type");
value.has("platforms");
@ -573,7 +573,7 @@ TitleSettingV3::TitleSettingV3(PrivateMarker) : m_impl(std::make_shared<Impl>())
Result<std::shared_ptr<TitleSettingV3>> TitleSettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) {
auto ret = std::make_shared<TitleSettingV3>(PrivateMarker());
auto root = checkJson(json, "TitleSettingV3");
ret->parseSharedProperties(key, modID, root, true);
ret->parseBaseProperties(key, modID, root, true);
root.checkUnknownKeys();
return root.ok(ret);
}
@ -628,9 +628,7 @@ SettingNodeV3* LegacyCustomSettingV3::createNode(float width) {
std::static_pointer_cast<LegacyCustomSettingV3>(shared_from_this()), width
);
}
return UnresolvedCustomSettingNodeV3::create(
std::static_pointer_cast<LegacyCustomSettingV3>(shared_from_this()), width
);
return UnresolvedCustomSettingNodeV3::create(this->getKey(), width);
}
bool LegacyCustomSettingV3::isDefaultValue() const {
@ -649,45 +647,22 @@ std::optional<std::shared_ptr<SettingValue>> LegacyCustomSettingV3::convertToLeg
class BoolSettingV3::Impl final {
public:
bool value;
bool defaultValue;
};
BoolSettingV3::BoolSettingV3(PrivateMarker) : m_impl(std::make_shared<Impl>()) {}
Result<std::shared_ptr<BoolSettingV3>> BoolSettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) {
auto ret = std::make_shared<BoolSettingV3>(PrivateMarker());
auto root = checkJson(json, "BoolSettingV3");
ret->parseSharedProperties(key, modID, root);
ret->parseDefaultValue(root, ret->m_impl->defaultValue);
ret->m_impl->value = ret->m_impl->defaultValue;
ret->parseBaseProperties(key, modID, root);
root.checkUnknownKeys();
return root.ok(ret);
}
bool& BoolSettingV3::getValueMut() const {
return m_impl->value;
}
bool BoolSettingV3::getDefaultValue() const {
return m_impl->defaultValue;
}
Result<> BoolSettingV3::isValid(bool value) const {
return Ok();
}
bool BoolSettingV3::load(matjson::Value const& json) {
if (json.is_bool()) {
m_impl->value = json.as_bool();
return true;
}
return false;
}
bool BoolSettingV3::save(matjson::Value& json) const {
json = m_impl->value;
return true;
}
SettingNodeV3* BoolSettingV3::createNode(float width) {
return BoolSettingNodeV3::create(
std::static_pointer_cast<BoolSettingV3>(shared_from_this()), width
@ -707,8 +682,6 @@ std::optional<std::shared_ptr<SettingValue>> BoolSettingV3::convertToLegacyValue
class IntSettingV3::Impl final {
public:
int64_t value;
int64_t defaultValue;
std::optional<int64_t> minValue;
std::optional<int64_t> maxValue;
@ -726,9 +699,7 @@ Result<std::shared_ptr<IntSettingV3>> IntSettingV3::parse(std::string const& key
auto ret = std::make_shared<IntSettingV3>(PrivateMarker());
auto root = checkJson(json, "IntSettingV3");
ret->parseSharedProperties(key, modID, root);
ret->parseDefaultValue(root, ret->m_impl->defaultValue);
ret->m_impl->value = ret->m_impl->defaultValue;
ret->parseBaseProperties(key, modID, root);
root.has("min").into(ret->m_impl->minValue);
root.has("max").into(ret->m_impl->maxValue);
@ -773,12 +744,6 @@ Result<std::shared_ptr<IntSettingV3>> IntSettingV3::parse(std::string const& key
IntSettingV3::IntSettingV3(PrivateMarker) : m_impl(std::make_shared<Impl>()) {}
int64_t& IntSettingV3::getValueMut() const {
return m_impl->value;
}
int64_t IntSettingV3::getDefaultValue() const {
return m_impl->defaultValue;
}
Result<> IntSettingV3::isValid(int64_t value) const {
if (m_impl->minValue && value < *m_impl->minValue) {
return Err("Value must be at least {}", *m_impl->minValue);
@ -818,17 +783,6 @@ bool IntSettingV3::isInputEnabled() const {
return m_impl->controls.textInputEnabled;
}
bool IntSettingV3::load(matjson::Value const& json) {
if (json.is_number()) {
m_impl->value = json.as_int();
return true;
}
return false;
}
bool IntSettingV3::save(matjson::Value& json) const {
json = m_impl->value;
return true;
}
SettingNodeV3* IntSettingV3::createNode(float width) {
return IntSettingNodeV3::create(
std::static_pointer_cast<IntSettingV3>(shared_from_this()), width
@ -859,8 +813,6 @@ std::optional<std::shared_ptr<SettingValue>> IntSettingV3::convertToLegacyValue(
class FloatSettingV3::Impl final {
public:
double value;
double defaultValue;
std::optional<double> minValue;
std::optional<double> maxValue;
@ -880,9 +832,7 @@ Result<std::shared_ptr<FloatSettingV3>> FloatSettingV3::parse(std::string const&
auto ret = std::make_shared<FloatSettingV3>(PrivateMarker());
auto root = checkJson(json, "FloatSettingV3");
ret->parseSharedProperties(key, modID, root);
ret->parseDefaultValue(root, ret->m_impl->defaultValue);
ret->m_impl->value = ret->m_impl->defaultValue;
ret->parseBaseProperties(key, modID, root);
root.has("min").into(ret->m_impl->minValue);
root.has("max").into(ret->m_impl->maxValue);
@ -923,12 +873,6 @@ Result<std::shared_ptr<FloatSettingV3>> FloatSettingV3::parse(std::string const&
return root.ok(ret);
}
double& FloatSettingV3::getValueMut() const {
return m_impl->value;
}
double FloatSettingV3::getDefaultValue() const {
return m_impl->defaultValue;
}
Result<> FloatSettingV3::isValid(double value) const {
if (m_impl->minValue && value < *m_impl->minValue) {
return Err("Value must be at least {}", *m_impl->minValue);
@ -968,17 +912,6 @@ bool FloatSettingV3::isInputEnabled() const {
return m_impl->controls.textInputEnabled;
}
bool FloatSettingV3::load(matjson::Value const& json) {
if (json.is_number()) {
m_impl->value = json.as_double();
return true;
}
return false;
}
bool FloatSettingV3::save(matjson::Value& json) const {
json = m_impl->value;
return true;
}
SettingNodeV3* FloatSettingV3::createNode(float width) {
return FloatSettingNodeV3::create(
std::static_pointer_cast<FloatSettingV3>(shared_from_this()), width
@ -1009,8 +942,6 @@ std::optional<std::shared_ptr<SettingValue>> FloatSettingV3::convertToLegacyValu
class StringSettingV3::Impl final {
public:
std::string value;
std::string defaultValue;
std::optional<std::string> match;
std::optional<std::string> filter;
std::optional<std::vector<std::string>> oneOf;
@ -1022,9 +953,7 @@ Result<std::shared_ptr<StringSettingV3>> StringSettingV3::parse(std::string cons
auto ret = std::make_shared<StringSettingV3>(PrivateMarker());
auto root = checkJson(json, "StringSettingV3");
ret->parseSharedProperties(key, modID, root);
ret->parseDefaultValue(root, ret->m_impl->defaultValue);
ret->m_impl->value = ret->m_impl->defaultValue;
ret->parseBaseProperties(key, modID, root);
root.has("match").into(ret->m_impl->match);
root.has("filter").into(ret->m_impl->filter);
@ -1037,12 +966,6 @@ Result<std::shared_ptr<StringSettingV3>> StringSettingV3::parse(std::string cons
return root.ok(ret);
}
std::string& StringSettingV3::getValueMut() const {
return m_impl->value;
}
std::string StringSettingV3::getDefaultValue() const {
return m_impl->defaultValue;
}
Result<> StringSettingV3::isValid(std::string_view value) const {
if (m_impl->match) {
if (!std::regex_match(std::string(value), std::regex(*m_impl->match))) {
@ -1067,17 +990,6 @@ std::optional<std::vector<std::string>> StringSettingV3::getEnumOptions() const
return m_impl->oneOf;
}
bool StringSettingV3::load(matjson::Value const& json) {
if (json.is_string()) {
m_impl->value = json.as_string();
return true;
}
return false;
}
bool StringSettingV3::save(matjson::Value& json) const {
json = m_impl->value;
return true;
}
SettingNodeV3* StringSettingV3::createNode(float width) {
return StringSettingNodeV3::create(
std::static_pointer_cast<StringSettingV3>(shared_from_this()), width
@ -1100,8 +1012,6 @@ std::optional<std::shared_ptr<SettingValue>> StringSettingV3::convertToLegacyVal
class FileSettingV3::Impl final {
public:
std::filesystem::path value;
std::filesystem::path defaultValue;
bool folder = false;
bool useSaveDialog = false; // this option makes no sense if folder = true
std::optional<std::vector<utils::file::FilePickOptions::Filter>> filters;
@ -1113,25 +1023,23 @@ Result<std::shared_ptr<FileSettingV3>> FileSettingV3::parse(std::string const& k
auto ret = std::make_shared<FileSettingV3>(PrivateMarker());
auto root = checkJson(json, "FileSettingV3");
ret->parseSharedProperties(key, modID, root);
ret->parseDefaultValue(root, ret->m_impl->defaultValue);
ret->m_impl->value = ret->m_impl->defaultValue;
ret->parseBaseProperties(key, modID, root);
// Replace known paths like `{gd-save-dir}/`
try {
ret->m_impl->defaultValue = fmt::format(
fmt::runtime(ret->m_impl->defaultValue.string()),
ret->setDefaultValue(fmt::format(
fmt::runtime(ret->getDefaultValue().string()),
fmt::arg("gd_dir", dirs::getGameDir()),
fmt::arg("gd_save_dir", dirs::getSaveDir()),
fmt::arg("mod_config_dir", dirs::getModConfigDir() / modID),
fmt::arg("mod_save_dir", dirs::getModsSaveDir() / modID),
fmt::arg("temp_dir", dirs::getTempDir())
);
));
}
catch(fmt::format_error const& e) {
return Err("Invalid format string for file setting path: {}", e.what());
}
ret->m_impl->value = ret->m_impl->defaultValue;
ret->setValue(ret->getDefaultValue());
std::string type;
root.needs("type").into(type);
@ -1175,12 +1083,6 @@ Result<std::shared_ptr<FileSettingV3>> FileSettingV3::parse(std::string const& k
return root.ok(ret);
}
std::filesystem::path& FileSettingV3::getValueMut() const {
return m_impl->value;
}
std::filesystem::path FileSettingV3::getDefaultValue() const {
return m_impl->defaultValue;
}
Result<> FileSettingV3::isValid(std::filesystem::path const& value) const {
std::error_code ec;
if (m_impl->folder) {
@ -1207,17 +1109,6 @@ std::optional<std::vector<utils::file::FilePickOptions::Filter>> FileSettingV3::
return m_impl->filters;
}
bool FileSettingV3::load(matjson::Value const& json) {
if (json.is_string()) {
m_impl->value = json.as_string();
return true;
}
return false;
}
bool FileSettingV3::save(matjson::Value& json) const {
json = m_impl->value;
return true;
}
SettingNodeV3* FileSettingV3::createNode(float width) {
return FileSettingNodeV3::create(
std::static_pointer_cast<FileSettingV3>(shared_from_this()), width
@ -1238,45 +1129,22 @@ std::optional<std::shared_ptr<SettingValue>> FileSettingV3::convertToLegacyValue
class Color3BSettingV3::Impl final {
public:
ccColor3B value;
ccColor3B defaultValue;
};
Color3BSettingV3::Color3BSettingV3(PrivateMarker) : m_impl(std::make_shared<Impl>()) {}
Result<std::shared_ptr<Color3BSettingV3>> Color3BSettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) {
auto ret = std::make_shared<Color3BSettingV3>(PrivateMarker());
auto root = checkJson(json, "Color3BSettingV3");
ret->parseSharedProperties(key, modID, root);
ret->parseDefaultValue(root, ret->m_impl->defaultValue);
ret->m_impl->value = ret->m_impl->defaultValue;
ret->parseBaseProperties(key, modID, root);
root.checkUnknownKeys();
return root.ok(ret);
}
ccColor3B& Color3BSettingV3::getValueMut() const {
return m_impl->value;
}
ccColor3B Color3BSettingV3::getDefaultValue() const {
return m_impl->defaultValue;
}
Result<> Color3BSettingV3::isValid(ccColor3B value) const {
return Ok();
}
bool Color3BSettingV3::load(matjson::Value const& json) {
if (json.template is<ccColor3B>()) {
m_impl->value = json.template as<ccColor3B>();
return true;
}
return false;
}
bool Color3BSettingV3::save(matjson::Value& json) const {
json = m_impl->value;
return true;
}
SettingNodeV3* Color3BSettingV3::createNode(float width) {
return Color3BSettingNodeV3::create(
std::static_pointer_cast<Color3BSettingV3>(shared_from_this()), width
@ -1296,45 +1164,22 @@ std::optional<std::shared_ptr<SettingValue>> Color3BSettingV3::convertToLegacyVa
class Color4BSettingV3::Impl final {
public:
ccColor4B value;
ccColor4B defaultValue;
};
Color4BSettingV3::Color4BSettingV3(PrivateMarker) : m_impl(std::make_shared<Impl>()) {}
Result<std::shared_ptr<Color4BSettingV3>> Color4BSettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) {
auto ret = std::make_shared<Color4BSettingV3>(PrivateMarker());
auto root = checkJson(json, "Color4BSettingV3");
ret->parseSharedProperties(key, modID, root);
ret->parseDefaultValue(root, ret->m_impl->defaultValue);
ret->m_impl->value = ret->m_impl->defaultValue;
ret->parseBaseProperties(key, modID, root);
root.checkUnknownKeys();
return root.ok(ret);
}
ccColor4B& Color4BSettingV3::getValueMut() const {
return m_impl->value;
}
ccColor4B Color4BSettingV3::getDefaultValue() const {
return m_impl->defaultValue;
}
Result<> Color4BSettingV3::isValid(ccColor4B value) const {
return Ok();
}
bool Color4BSettingV3::load(matjson::Value const& json) {
if (json.template is<ccColor4B>()) {
m_impl->value = json.template as<ccColor4B>();
return true;
}
return false;
}
bool Color4BSettingV3::save(matjson::Value& json) const {
json = m_impl->value;
return true;
}
SettingNodeV3* Color4BSettingV3::createNode(float width) {
return Color4BSettingNodeV3::create(
std::static_pointer_cast<Color4BSettingV3>(shared_from_this()), width

View file

@ -6,6 +6,7 @@
#include <Geode/ui/ScrollLayer.hpp>
#include <Geode/utils/cocos.hpp>
#include <Geode/ui/General.hpp>
#include <loader/SettingNodeV3.hpp>
bool ModSettingsPopup::setup(Mod* mod) {
m_noElasticity = true;
@ -33,10 +34,9 @@ bool ModSettingsPopup::setup(Mod* mod) {
node = sett->createNode(layerSize.width);
}
else {
// todo: placeholder node
continue;
node = UnresolvedCustomSettingNodeV3::create(key, layerSize.width);
}
node->setBGColor(ccc4(0, 0, 0, bg ? 60 : 20));
node->setDefaultBGColor(ccc4(0, 0, 0, bg ? 60 : 20));
// auto separator = CCLayerColor::create({ 0, 0, 0, 50 }, layerSize.width, 1.f);
// separator->setOpacity(bg ? 100 : 50);
@ -191,8 +191,8 @@ void ModSettingsPopup::updateState(SettingNodeV3* invoker) {
if (sett == invoker) {
continue;
}
if (sett->getSetting()->getEnableIf()) {
sett->updateState();
if (sett->getSetting() && sett->getSetting()->getEnableIf()) {
sett->updateState(nullptr);
}
}