diff --git a/loader/include/Geode/loader/SettingV3.hpp b/loader/include/Geode/loader/SettingV3.hpp index 83ff851f..dd784837 100644 --- a/loader/include/Geode/loader/SettingV3.hpp +++ b/loader/include/Geode/loader/SettingV3.hpp @@ -23,8 +23,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); - void parseSharedProperties(std::string const& key, std::string const& modID, JsonExpectedValue& value); + 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); public: SettingV3(); @@ -46,7 +46,7 @@ namespace geode { /** * Get the name of this setting */ - std::string getName() const; + std::optional getName() const; /** * Get the description of this setting */ @@ -135,8 +135,6 @@ namespace geode { TitleSettingV3(PrivateMarker); static Result> parse(std::string const& key, std::string const& modID, matjson::Value const& json); - std::string getTitle() const; - bool load(matjson::Value const& json) override; bool save(matjson::Value& json) const override; SettingNodeV3* createNode(float width) override; @@ -401,6 +399,8 @@ namespace geode { protected: bool init(std::shared_ptr setting, float width); + virtual void updateState(); + /** * Mark this setting as changed. This updates the UI for committing * the value @@ -414,12 +414,19 @@ namespace geode { */ virtual void onCommit() = 0; + void onDescription(CCObject*); + void onReset(CCObject*); + public: void commit(); virtual bool hasUncommittedChanges() const = 0; virtual bool hasNonDefaultValue() const = 0; virtual void resetToDefault() = 0; + cocos2d::CCLabelBMFont* getNameLabel() const; + cocos2d::CCMenu* getNameMenu() const; + cocos2d::CCMenu* getButtonMenu() const; + void setContentSize(cocos2d::CCSize const& size) override; std::shared_ptr getSetting() const; diff --git a/loader/resources/mod.json.in b/loader/resources/mod.json.in index dcbe69de..89e17202 100644 --- a/loader/resources/mod.json.in +++ b/loader/resources/mod.json.in @@ -64,13 +64,6 @@ } }, "settings": { - "show-platform-console": { - "type": "bool", - "default": false, - "name": "Show Platform Console", - "description": "Show the native console (if one exists). This setting is meant for developers", - "platforms": ["win", "mac"] - }, "auto-check-updates": { "type": "bool", "default": true, @@ -83,6 +76,24 @@ "name": "Disable Crash Popup", "description": "Disables the popup at startup asking if you'd like to send a bug report; intended for developers" }, + "enable-geode-theme": { + "type": "bool", + "default": true, + "name": "Enable Geode-Themed Colors", + "description": "When enabled, the Geode menu has a Geode-themed color scheme. This does not affect any other menus!" + }, + "developer-title": { + "type": "title", + "name": "Developer Settings" + }, + "show-platform-console": { + "type": "bool", + "default": false, + "name": "Show Platform Console", + "description": "Show the native console (if one exists). This setting is meant for developers", + "platforms": ["win", "mac"], + "restart-required": true + }, "server-cache-size-limit": { "type": "int", "default": 20, @@ -90,12 +101,6 @@ "max": 100, "name": "Server Cache Size Limit", "description": "Limits the size of the cache used for loading mods. Higher values result in higher memory usage." - }, - "enable-geode-theme": { - "type": "bool", - "default": true, - "name": "Enable Geode-Themed Colors", - "description": "When enabled, the Geode menu has a Geode-themed color scheme. This does not affect any other menus!" } }, "issues": { diff --git a/loader/src/loader/SettingNodeV3.cpp b/loader/src/loader/SettingNodeV3.cpp index 339eb74d..21260852 100644 --- a/loader/src/loader/SettingNodeV3.cpp +++ b/loader/src/loader/SettingNodeV3.cpp @@ -36,6 +36,10 @@ bool SettingNodeValueChangeEventV3::isCommit() const { class SettingNodeV3::Impl final { public: std::shared_ptr setting; + CCLabelBMFont* nameLabel; + CCMenu* nameMenu; + CCMenu* buttonMenu; + CCMenuItemSpriteExtra* resetButton; }; bool SettingNodeV3::init(std::shared_ptr setting, float width) { @@ -45,23 +49,93 @@ bool SettingNodeV3::init(std::shared_ptr setting, float width) { m_impl = std::make_shared(); m_impl->setting = setting; + m_impl->nameMenu = CCMenu::create(); + m_impl->nameMenu->setContentWidth(width / 2 - 20); + + m_impl->nameLabel = CCLabelBMFont::create( + setting->getName().value_or(setting->getKey()).c_str(), + "bigFont.fnt" + ); + m_impl->nameLabel->setLayoutOptions(AxisLayoutOptions::create()->setScaleLimits(.1f, .4f)->setScalePriority(1)); + m_impl->nameMenu->addChild(m_impl->nameLabel); + + if (setting->getDescription()) { + auto descSpr = CCSprite::createWithSpriteFrameName("GJ_infoIcon_001.png"); + descSpr->setScale(.5f); + auto descBtn = CCMenuItemSpriteExtra::create( + descSpr, this, menu_selector(SettingNodeV3::onDescription) + ); + m_impl->nameMenu->addChild(descBtn); + } + + auto resetSpr = CCSprite::createWithSpriteFrameName("reset-gold.png"_spr); + resetSpr->setScale(.5f); + m_impl->resetButton = CCMenuItemSpriteExtra::create( + resetSpr, this, menu_selector(SettingNodeV3::onReset) + ); + m_impl->nameMenu->addChild(m_impl->resetButton); + + m_impl->nameMenu->setLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Start)); + this->addChildAtPosition(m_impl->nameMenu, Anchor::Left, ccp(10, 0), ccp(0, .5f)); + + m_impl->buttonMenu = CCMenu::create(); + m_impl->buttonMenu->setContentWidth(width / 2 - 20); + m_impl->buttonMenu->setLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::End)); + this->addChildAtPosition(m_impl->buttonMenu, Anchor::Right, ccp(-10, 0), ccp(1, .5f)); + + this->setAnchorPoint({ .5f, .5f }); + this->setContentSize({ width, 30 }); + return true; } -void SettingNodeV3::markChanged() { - SettingNodeValueChangeEventV3(false).post(); +void SettingNodeV3::updateState() { + this->getNameLabel()->setColor(this->hasUncommittedChanges() ? ccc3(17, 221, 0) : ccWHITE); + m_impl->resetButton->setVisible(this->hasNonDefaultValue()); + m_impl->nameMenu->updateLayout(); } +void SettingNodeV3::onDescription(CCObject*) { + auto title = m_impl->setting->getName().value_or(m_impl->setting->getKey()); + FLAlertLayer::create( + nullptr, + title.c_str(), + m_impl->setting->getDescription().value_or("No description provided"), + "OK", nullptr, + clamp(title.size() * 16, 240, 400) + )->show(); +} +void SettingNodeV3::onReset(CCObject*) { + this->resetToDefault(); + this->updateState(); +} + +void SettingNodeV3::markChanged() { + this->updateState(); + SettingNodeValueChangeEventV3(false).post(); +} void SettingNodeV3::commit() { this->onCommit(); + this->updateState(); SettingNodeValueChangeEventV3(true).post(); } void SettingNodeV3::setContentSize(CCSize const& size) { CCNode::setContentSize(size); + this->updateLayout(); SettingNodeSizeChangeEventV3(this).post(); } +CCLabelBMFont* SettingNodeV3::getNameLabel() const { + return m_impl->nameLabel; +} +CCMenu* SettingNodeV3::getNameMenu() const { + return m_impl->nameMenu; +} +CCMenu* SettingNodeV3::getButtonMenu() const { + return m_impl->buttonMenu; +} + std::shared_ptr SettingNodeV3::getSetting() const { return m_impl->setting; } @@ -72,11 +146,10 @@ bool TitleSettingNodeV3::init(std::shared_ptr setting, float wid if (!SettingNodeV3::init(setting, width)) return false; + this->getNameLabel()->setFntFile("goldFont.fnt"); + this->getNameMenu()->updateLayout(); this->setContentHeight(20); - - auto label = CCLabelBMFont::create(setting->getTitle().c_str(), "goldFont.fnt"); - label->limitLabelWidth(width - m_obContentSize.height, .7f, .1f); - this->addChildAtPosition(label, Anchor::Left, ccp(m_obContentSize.height / 2, 0)); + this->updateState(); return true; } @@ -111,16 +184,19 @@ bool BoolSettingNodeV3::init(std::shared_ptr setting, float width if (!SettingNodeV3::init(setting, width)) return false; - this->setContentHeight(30); - - auto label = CCLabelBMFont::create(setting->getName().c_str(), "bigFont.fnt"); - label->limitLabelWidth(width - m_obContentSize.height * 1.5f, .5f, .1f); - this->addChildAtPosition(label, Anchor::Left, ccp(m_obContentSize.height / 2, 0)); - m_toggle = CCMenuItemToggler::createWithStandardSprites( - this, nullptr, .8f + this, menu_selector(BoolSettingNodeV3::onToggle), .55f ); - this->addChildAtPosition(m_toggle, Anchor::Right, ccp(-m_obContentSize.height / 2, 0)); + m_toggle->m_onButton->setContentSize({ 25, 25 }); + m_toggle->m_onButton->getNormalImage()->setPosition(ccp(25, 25) / 2); + m_toggle->m_offButton->setContentSize({ 25, 25 }); + m_toggle->m_offButton->getNormalImage()->setPosition(ccp(25, 25) / 2); + m_toggle->m_notClickable = true; + m_toggle->toggle(setting->getValue()); + this->getButtonMenu()->addChild(m_toggle); + this->getButtonMenu()->updateLayout(); + + this->updateState(); return true; } @@ -128,6 +204,10 @@ bool BoolSettingNodeV3::init(std::shared_ptr setting, float width void BoolSettingNodeV3::onCommit() { this->getSetting()->setValue(m_toggle->isToggled()); } +void BoolSettingNodeV3::onToggle(CCObject*) { + m_toggle->toggle(!m_toggle->isToggled()); + this->markChanged(); +} BoolSettingNodeV3* BoolSettingNodeV3::create(std::shared_ptr setting, float width) { auto ret = new BoolSettingNodeV3(); diff --git a/loader/src/loader/SettingNodeV3.hpp b/loader/src/loader/SettingNodeV3.hpp index f1faa862..ca1753e1 100644 --- a/loader/src/loader/SettingNodeV3.hpp +++ b/loader/src/loader/SettingNodeV3.hpp @@ -33,6 +33,8 @@ protected: void onCommit() override; + void onToggle(CCObject*); + public: static BoolSettingNodeV3* create(std::shared_ptr setting, float width); diff --git a/loader/src/loader/SettingV3.cpp b/loader/src/loader/SettingV3.cpp index e7e8039a..119821d8 100644 --- a/loader/src/loader/SettingV3.cpp +++ b/loader/src/loader/SettingV3.cpp @@ -18,18 +18,20 @@ public: SettingV3::SettingV3() : m_impl(std::make_shared()) {} SettingV3::~SettingV3() = default; -Result<> SettingV3::parseSharedProperties(std::string const& key, std::string const& modID, matjson::Value const& value) { +Result<> SettingV3::parseSharedProperties(std::string const& key, std::string const& modID, matjson::Value const& value, bool onlyNameAndDesc) { auto json = checkJson(value, "SettingV3"); - this->parseSharedProperties(key, modID, json); + this->parseSharedProperties(key, modID, json, onlyNameAndDesc); return json.ok(); } -void SettingV3::parseSharedProperties(std::string const& key, std::string const& modID, JsonExpectedValue& value) { +void SettingV3::parseSharedProperties(std::string const& key, std::string const& modID, JsonExpectedValue& value, bool onlyNameAndDesc) { this->init(key, modID); value.needs("type"); value.has("name").into(m_impl->name); value.has("description").into(m_impl->description); - value.has("enable-if").into(m_impl->enableIf); - value.has("requires-restart").into(m_impl->requiresRestart); + if (!onlyNameAndDesc) { + value.has("enable-if").into(m_impl->enableIf); + value.has("requires-restart").into(m_impl->requiresRestart); + } } void SettingV3::init(std::string const& key, std::string const& modID) { m_impl->key = key; @@ -42,8 +44,8 @@ std::string SettingV3::getKey() const { std::string SettingV3::getModID() const { return m_impl->modID; } -std::string SettingV3::getName() const { - return m_impl->name.value_or(m_impl->key); +std::optional SettingV3::getName() const { + return m_impl->name; } std::optional SettingV3::getDescription() const { return m_impl->description; @@ -67,7 +69,6 @@ std::optional> SettingV3::convertToLegacyValue() c class TitleSettingV3::Impl final { public: - std::string title; }; TitleSettingV3::TitleSettingV3(PrivateMarker) : m_impl(std::make_shared()) {} @@ -75,16 +76,11 @@ TitleSettingV3::TitleSettingV3(PrivateMarker) : m_impl(std::make_shared()) Result> TitleSettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) { auto ret = std::make_shared(PrivateMarker()); auto root = checkJson(json, "TitleSettingV3"); - ret->init(key, modID); - root.needs("title").into(ret->m_impl->title); + ret->parseSharedProperties(key, modID, root, true); root.checkUnknownKeys(); return root.ok(ret); } -std::string TitleSettingV3::getTitle() const { - return m_impl->title; -} - bool TitleSettingV3::load(matjson::Value const& json) { return true; } diff --git a/loader/src/ui/mods/settings/ModSettingsPopup.cpp b/loader/src/ui/mods/settings/ModSettingsPopup.cpp index e80f72b2..020ca261 100644 --- a/loader/src/ui/mods/settings/ModSettingsPopup.cpp +++ b/loader/src/ui/mods/settings/ModSettingsPopup.cpp @@ -28,7 +28,7 @@ bool ModSettingsPopup::setup(Mod* mod) { hasBG = !hasBG; auto bg = CCLayerColor::create({ 0, 0, 0, 50 }); - bg->setOpacity(hasBG ? 50 : 0); + bg->setOpacity(hasBG ? 60 : 20); SettingNodeV3* node; if (auto sett = mod->getSettingV3(key)) { @@ -40,11 +40,12 @@ bool ModSettingsPopup::setup(Mod* mod) { } bg->setContentSize(node->getScaledContentSize()); - bg->addChildAtPosition(node, Anchor::Center); + bg->addChildAtPosition(node, Anchor::Center, ccp(0, 0), ccp(.5f, .5f)); - auto separator = CCLayerColor::create({ 0, 0, 0, 50 }, layerSize.width, 1.f); - separator->setOpacity(hasBG ? 100 : 50); - bg->addChildAtPosition(separator, Anchor::Bottom); + // auto separator = CCLayerColor::create({ 0, 0, 0, 50 }, layerSize.width, 1.f); + // separator->setOpacity(hasBG ? 100 : 50); + // separator->ignoreAnchorPointForPosition(false); + // bg->addChildAtPosition(separator, Anchor::Bottom, ccp(0, 0), ccp(.5f, .5f)); m_settings.push_back(node); @@ -132,11 +133,13 @@ void ModSettingsPopup::onResetAll(CCObject*) { void ModSettingsPopup::updateState() { if (this->hasUncommitted()) { - m_applyBtnSpr->setColor({0xff, 0xff, 0xff}); + m_applyBtnSpr->setColor(ccWHITE); + m_applyBtnSpr->setOpacity(255); m_applyBtn->setEnabled(true); } else { - m_applyBtnSpr->setColor({0x44, 0x44, 0x44}); + m_applyBtnSpr->setColor(ccGRAY); + m_applyBtnSpr->setOpacity(155); m_applyBtn->setEnabled(false); } } @@ -172,7 +175,7 @@ void ModSettingsPopup::onOpenSaveDirectory(CCObject*) { ModSettingsPopup* ModSettingsPopup::create(Mod* mod) { auto ret = new ModSettingsPopup(); - if (ret->init(440.f, 280.f, mod)) { + if (ret->init(440, 280, mod)) { ret->autorelease(); return ret; }