mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-14 19:15:05 -05:00
path settings done
This commit is contained in:
parent
3f3b52104f
commit
766b71dfbd
4 changed files with 252 additions and 84 deletions
|
@ -267,8 +267,8 @@ namespace geode {
|
|||
|
||||
bool isArrowsEnabled() const;
|
||||
bool isBigArrowsEnabled() const;
|
||||
size_t getArrowStepSize() const;
|
||||
size_t getBigArrowStepSize() const;
|
||||
double getArrowStepSize() const;
|
||||
double getBigArrowStepSize() const;
|
||||
bool isSliderEnabled() const;
|
||||
std::optional<double> getSliderSnap() const;
|
||||
bool isInputEnabled() const;
|
||||
|
@ -328,9 +328,17 @@ namespace geode {
|
|||
FileSettingV3(PrivateMarker);
|
||||
static Result<std::shared_ptr<FileSettingV3>> parse(std::string const& key, std::string const& modID, matjson::Value const& json);
|
||||
|
||||
enum class FileType {
|
||||
Any = 0,
|
||||
File = 1,
|
||||
Folder = 2,
|
||||
};
|
||||
|
||||
std::filesystem::path getDefaultValue() const override;
|
||||
Result<> isValid(std::filesystem::path const& value) const override;
|
||||
|
||||
FileType getFileType() const;
|
||||
|
||||
std::optional<std::vector<utils::file::FilePickOptions::Filter>> getFilters() const;
|
||||
|
||||
bool load(matjson::Value const& json) override;
|
||||
|
|
|
@ -73,6 +73,7 @@ bool SettingNodeV3::init(std::shared_ptr<SettingV3> setting, float width) {
|
|||
m_impl->nameMenu->addChild(m_impl->resetButton);
|
||||
|
||||
m_impl->nameMenu->setLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Start));
|
||||
m_impl->nameMenu->getLayout()->ignoreInvisibleChildren(true);
|
||||
this->addChildAtPosition(m_impl->nameMenu, Anchor::Left, ccp(10, 0), ccp(0, .5f));
|
||||
|
||||
m_impl->buttonMenu = CCMenu::create();
|
||||
|
@ -197,6 +198,10 @@ TitleSettingNodeV3* TitleSettingNodeV3::create(std::shared_ptr<TitleSettingV3> s
|
|||
bool BoolSettingNodeV3::init(std::shared_ptr<BoolSettingV3> setting, float width) {
|
||||
if (!SettingNodeV3::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
|
||||
|
@ -209,9 +214,6 @@ 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->getNameMenu()->setContentWidth(width - 50);
|
||||
this->getNameMenu()->updateLayout();
|
||||
|
||||
this->updateState();
|
||||
|
||||
return true;
|
||||
|
@ -255,7 +257,7 @@ bool StringSettingNodeV3::init(std::shared_ptr<StringSettingV3> setting, float w
|
|||
if (!SettingNodeV3::init(setting, width))
|
||||
return false;
|
||||
|
||||
m_input = TextInput::create(width / 2 - 50, "Num");
|
||||
m_input = TextInput::create(setting->getEnumOptions() ? width / 2 - 50 : width / 2, "Text");
|
||||
m_input->setCallback([this](auto const&) {
|
||||
this->markChanged();
|
||||
});
|
||||
|
@ -339,20 +341,91 @@ bool FileSettingNodeV3::init(std::shared_ptr<FileSettingV3> setting, float width
|
|||
if (!SettingNodeV3::init(setting, width))
|
||||
return false;
|
||||
|
||||
// todo
|
||||
m_path = setting->getValue();
|
||||
|
||||
auto labelBG = extension::CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 });
|
||||
labelBG->setScale(.25f);
|
||||
labelBG->setColor({ 0, 0, 0 });
|
||||
labelBG->setOpacity(90);
|
||||
labelBG->setContentSize({ 400, 80 });
|
||||
this->getButtonMenu()->addChildAtPosition(labelBG, Anchor::Center, ccp(-15, 0));
|
||||
|
||||
m_fileIcon = CCSprite::create();
|
||||
this->getButtonMenu()->addChildAtPosition(m_fileIcon, Anchor::Left, ccp(3, 0));
|
||||
|
||||
m_nameLabel = CCLabelBMFont::create("", "bigFont.fnt");
|
||||
this->getButtonMenu()->addChildAtPosition(m_nameLabel, Anchor::Left, ccp(11, 0), ccp(0, .5f));
|
||||
|
||||
auto selectSpr = CCSprite::createWithSpriteFrameName("GJ_plus2Btn_001.png");
|
||||
selectSpr->setScale(.75f);
|
||||
auto selectBtn = CCMenuItemSpriteExtra::create(
|
||||
selectSpr, this, menu_selector(FileSettingNodeV3::onPickFile)
|
||||
);
|
||||
this->getButtonMenu()->addChildAtPosition(selectBtn, Anchor::Right, ccp(-5, 0));
|
||||
|
||||
this->updateState();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileSettingNodeV3::onCommit() {}
|
||||
void FileSettingNodeV3::updateState() {
|
||||
SettingNodeV3::updateState();
|
||||
auto ty = this->getSetting()->getFileType();
|
||||
if (ty == FileSettingV3::FileType::Any) {
|
||||
ty = std::filesystem::is_directory(m_path) ?
|
||||
FileSettingV3::FileType::Folder :
|
||||
FileSettingV3::FileType::File;
|
||||
}
|
||||
m_fileIcon->setDisplayFrame(CCSpriteFrameCache::get()->spriteFrameByName(
|
||||
ty == FileSettingV3::FileType::File ? "file.png"_spr : "folderIcon_001.png"
|
||||
));
|
||||
limitNodeSize(m_fileIcon, ccp(10, 10), 1.f, .1f);
|
||||
m_nameLabel->setString(m_path.filename().string().c_str());
|
||||
m_nameLabel->limitLabelWidth(75, .4f, .1f);
|
||||
}
|
||||
|
||||
void FileSettingNodeV3::onCommit() {
|
||||
this->getSetting()->setValue(m_path);
|
||||
}
|
||||
|
||||
void FileSettingNodeV3::onPickFile(CCObject*) {
|
||||
m_pickListener.bind([this](auto* event) {
|
||||
auto value = event->getValue();
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
if (value->isOk()) {
|
||||
m_path = value->unwrap().string();
|
||||
this->markChanged();
|
||||
}
|
||||
else {
|
||||
FLAlertLayer::create(
|
||||
"Failed",
|
||||
fmt::format("Failed to pick file: {}", value->unwrapErr()),
|
||||
"Ok"
|
||||
)->show();
|
||||
}
|
||||
});
|
||||
m_pickListener.setFilter(file::pick(
|
||||
this->getSetting()->getFileType() == FileSettingV3::FileType::Folder ?
|
||||
file::PickMode::OpenFolder :
|
||||
file::PickMode::OpenFile,
|
||||
{
|
||||
dirs::getGameDir(),
|
||||
this->getSetting()->getFilters().value_or(std::vector<file::FilePickOptions::Filter>())
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
bool FileSettingNodeV3::hasUncommittedChanges() const {
|
||||
return false;
|
||||
return m_path != this->getSetting()->getValue();
|
||||
}
|
||||
bool FileSettingNodeV3::hasNonDefaultValue() const {
|
||||
return false;
|
||||
return m_path != this->getSetting()->getDefaultValue();
|
||||
}
|
||||
void FileSettingNodeV3::onResetToDefault() {
|
||||
m_path = this->getSetting()->getDefaultValue();
|
||||
}
|
||||
void FileSettingNodeV3::onResetToDefault() {}
|
||||
|
||||
std::shared_ptr<FileSettingV3> FileSettingNodeV3::getSetting() const {
|
||||
return std::static_pointer_cast<FileSettingV3>(SettingNodeV3::getSetting());
|
||||
|
|
|
@ -52,6 +52,10 @@ protected:
|
|||
|
||||
TextInput* m_input;
|
||||
Slider* m_slider;
|
||||
CCMenuItemSpriteExtra* m_arrowLeftBtn;
|
||||
CCMenuItemSpriteExtra* m_bigArrowLeftBtn;
|
||||
CCMenuItemSpriteExtra* m_arrowRightBtn;
|
||||
CCMenuItemSpriteExtra* m_bigArrowRightBtn;
|
||||
|
||||
float valueToSlider(ValueType value) {
|
||||
auto min = this->getSetting()->getMinValue().value_or(-100);
|
||||
|
@ -75,6 +79,8 @@ protected:
|
|||
return false;
|
||||
|
||||
auto bigArrowLeftSpr = CCSprite::create();
|
||||
bigArrowLeftSpr->setCascadeColorEnabled(true);
|
||||
bigArrowLeftSpr->setCascadeOpacityEnabled(true);
|
||||
auto bigArrowLeftSpr1 = CCSprite::createWithSpriteFrameName("GJ_arrow_03_001.png");
|
||||
auto bigArrowLeftSpr2 = CCSprite::createWithSpriteFrameName("GJ_arrow_03_001.png");
|
||||
|
||||
|
@ -83,21 +89,21 @@ protected:
|
|||
bigArrowLeftSpr->addChildAtPosition(bigArrowLeftSpr1, Anchor::Center, ccp(-10, 0));
|
||||
bigArrowLeftSpr->setScale(.3f);
|
||||
|
||||
auto bigArrowLeftBtn = CCMenuItemSpriteExtra::create(
|
||||
m_bigArrowLeftBtn = CCMenuItemSpriteExtra::create(
|
||||
bigArrowLeftSpr, this, menu_selector(NumberSettingNodeV3::onArrow)
|
||||
);
|
||||
bigArrowLeftBtn->setTag(-setting->getBigArrowStepSize());
|
||||
bigArrowLeftBtn->setVisible(setting->isBigArrowsEnabled());
|
||||
this->getButtonMenu()->addChildAtPosition(bigArrowLeftBtn, Anchor::Left, ccp(5, 0));
|
||||
m_bigArrowLeftBtn->setUserObject(ObjWrapper<ValueType>::create(-setting->getBigArrowStepSize()));
|
||||
m_bigArrowLeftBtn->setVisible(setting->isBigArrowsEnabled());
|
||||
this->getButtonMenu()->addChildAtPosition(m_bigArrowLeftBtn, Anchor::Left, ccp(5, 0));
|
||||
|
||||
auto arrowLeftSpr = CCSprite::createWithSpriteFrameName("GJ_arrow_01_001.png");
|
||||
arrowLeftSpr->setScale(.5f);
|
||||
auto arrowLeftBtn = CCMenuItemSpriteExtra::create(
|
||||
m_arrowLeftBtn = CCMenuItemSpriteExtra::create(
|
||||
arrowLeftSpr, this, menu_selector(NumberSettingNodeV3::onArrow)
|
||||
);
|
||||
arrowLeftBtn->setTag(-setting->getArrowStepSize());
|
||||
arrowLeftBtn->setVisible(setting->isArrowsEnabled());
|
||||
this->getButtonMenu()->addChildAtPosition(arrowLeftBtn, Anchor::Left, ccp(22, 0));
|
||||
m_arrowLeftBtn->setUserObject(ObjWrapper<ValueType>::create(-setting->getArrowStepSize()));
|
||||
m_arrowLeftBtn->setVisible(setting->isArrowsEnabled());
|
||||
this->getButtonMenu()->addChildAtPosition(m_arrowLeftBtn, Anchor::Left, ccp(22, 0));
|
||||
|
||||
m_input = TextInput::create(this->getButtonMenu()->getContentWidth() - 40, "Num");
|
||||
m_input->setScale(.7f);
|
||||
|
@ -115,14 +121,16 @@ protected:
|
|||
auto arrowRightSpr = CCSprite::createWithSpriteFrameName("GJ_arrow_01_001.png");
|
||||
arrowRightSpr->setFlipX(true);
|
||||
arrowRightSpr->setScale(.5f);
|
||||
auto arrowRightBtn = CCMenuItemSpriteExtra::create(
|
||||
m_arrowRightBtn = CCMenuItemSpriteExtra::create(
|
||||
arrowRightSpr, this, menu_selector(NumberSettingNodeV3::onArrow)
|
||||
);
|
||||
arrowRightBtn->setTag(setting->getArrowStepSize());
|
||||
arrowRightBtn->setVisible(setting->isArrowsEnabled());
|
||||
this->getButtonMenu()->addChildAtPosition(arrowRightBtn, Anchor::Right, ccp(-22, 0));
|
||||
m_arrowRightBtn->setUserObject(ObjWrapper<ValueType>::create(setting->getArrowStepSize()));
|
||||
m_arrowRightBtn->setVisible(setting->isArrowsEnabled());
|
||||
this->getButtonMenu()->addChildAtPosition(m_arrowRightBtn, Anchor::Right, ccp(-22, 0));
|
||||
|
||||
auto bigArrowRightSpr = CCSprite::create();
|
||||
bigArrowRightSpr->setCascadeColorEnabled(true);
|
||||
bigArrowRightSpr->setCascadeOpacityEnabled(true);
|
||||
auto bigArrowRightSpr1 = CCSprite::createWithSpriteFrameName("GJ_arrow_03_001.png");
|
||||
bigArrowRightSpr1->setFlipX(true);
|
||||
auto bigArrowRightSpr2 = CCSprite::createWithSpriteFrameName("GJ_arrow_03_001.png");
|
||||
|
@ -133,12 +141,12 @@ protected:
|
|||
bigArrowRightSpr->addChildAtPosition(bigArrowRightSpr2, Anchor::Center, ccp(10, 0));
|
||||
bigArrowRightSpr->setScale(.3f);
|
||||
|
||||
auto bigArrowRightBtn = CCMenuItemSpriteExtra::create(
|
||||
m_bigArrowRightBtn = CCMenuItemSpriteExtra::create(
|
||||
bigArrowRightSpr, this, menu_selector(NumberSettingNodeV3::onArrow)
|
||||
);
|
||||
bigArrowRightBtn->setTag(setting->getBigArrowStepSize());
|
||||
bigArrowRightBtn->setVisible(setting->isBigArrowsEnabled());
|
||||
this->getButtonMenu()->addChildAtPosition(bigArrowRightBtn, Anchor::Right, ccp(-5, 0));
|
||||
m_bigArrowRightBtn->setUserObject(ObjWrapper<ValueType>::create(setting->getBigArrowStepSize()));
|
||||
m_bigArrowRightBtn->setVisible(setting->isBigArrowsEnabled());
|
||||
this->getButtonMenu()->addChildAtPosition(m_bigArrowRightBtn, Anchor::Right, ccp(-5, 0));
|
||||
|
||||
if (setting->isSliderEnabled()) {
|
||||
this->setContentHeight(45);
|
||||
|
@ -161,13 +169,40 @@ protected:
|
|||
m_slider->m_touchLogic->m_thumb->setValue(this->valueToSlider(this->getCurrentValue()));
|
||||
m_slider->updateBar();
|
||||
}
|
||||
if (auto min = this->getSetting()->getMinValue()) {
|
||||
auto enable = this->getCurrentValue() > *min;
|
||||
m_arrowLeftBtn->setEnabled(enable);
|
||||
m_bigArrowLeftBtn->setEnabled(enable);
|
||||
static_cast<CCSprite*>(m_arrowLeftBtn->getNormalImage())->setOpacity(enable ? 255 : 155);
|
||||
static_cast<CCSprite*>(m_arrowLeftBtn->getNormalImage())->setColor(enable ? ccWHITE : ccGRAY);
|
||||
static_cast<CCSprite*>(m_bigArrowLeftBtn->getNormalImage())->setOpacity(enable ? 255 : 155);
|
||||
static_cast<CCSprite*>(m_bigArrowLeftBtn->getNormalImage())->setColor(enable ? ccWHITE : ccGRAY);
|
||||
}
|
||||
if (auto max = this->getSetting()->getMaxValue()) {
|
||||
auto enable = this->getCurrentValue() < *max;
|
||||
m_arrowRightBtn->setEnabled(enable);
|
||||
m_bigArrowRightBtn->setEnabled(enable);
|
||||
static_cast<CCSprite*>(m_arrowRightBtn->getNormalImage())->setOpacity(enable ? 255 : 155);
|
||||
static_cast<CCSprite*>(m_arrowRightBtn->getNormalImage())->setColor(enable ? ccWHITE : ccGRAY);
|
||||
static_cast<CCSprite*>(m_bigArrowRightBtn->getNormalImage())->setOpacity(enable ? 255 : 155);
|
||||
static_cast<CCSprite*>(m_bigArrowRightBtn->getNormalImage())->setColor(enable ? ccWHITE : ccGRAY);
|
||||
}
|
||||
}
|
||||
|
||||
void onCommit() override {
|
||||
this->getSetting()->setValue(this->getCurrentValue());
|
||||
}
|
||||
void onArrow(CCObject* sender) {
|
||||
this->setCurrentValue(this->getCurrentValue() + sender->getTag());
|
||||
auto value = this->getCurrentValue() + static_cast<ObjWrapper<ValueType>*>(
|
||||
static_cast<CCNode*>(sender)->getUserObject()
|
||||
)->getValue();
|
||||
if (auto min = this->getSetting()->getMinValue()) {
|
||||
value = std::max(*min, value);
|
||||
}
|
||||
if (auto max = this->getSetting()->getMaxValue()) {
|
||||
value = std::min(*max, value);
|
||||
}
|
||||
this->setCurrentValue(value);
|
||||
}
|
||||
void onSlider(CCObject*) {
|
||||
this->setCurrentValue(this->valueFromSlider(m_slider->m_touchLogic->m_thumb->getValue()));
|
||||
|
@ -233,9 +268,17 @@ public:
|
|||
|
||||
class FileSettingNodeV3 : public SettingNodeV3 {
|
||||
protected:
|
||||
CCSprite* m_fileIcon;
|
||||
std::filesystem::path m_path;
|
||||
CCLabelBMFont* m_nameLabel;
|
||||
EventListener<Task<Result<std::filesystem::path>>> m_pickListener;
|
||||
|
||||
bool init(std::shared_ptr<FileSettingV3> setting, float width);
|
||||
|
||||
void updateState() override;
|
||||
|
||||
void onCommit() override;
|
||||
void onPickFile(CCObject*);
|
||||
|
||||
public:
|
||||
static FileSettingNodeV3* create(std::shared_ptr<FileSettingV3> setting, float width);
|
||||
|
|
|
@ -26,6 +26,7 @@ Result<> SettingV3::parseSharedProperties(std::string const& key, std::string co
|
|||
void SettingV3::parseSharedProperties(std::string const& key, std::string const& modID, JsonExpectedValue& value, bool onlyNameAndDesc) {
|
||||
this->init(key, modID);
|
||||
value.needs("type");
|
||||
value.has("platforms");
|
||||
value.has("name").into(m_impl->name);
|
||||
value.has("description").into(m_impl->description);
|
||||
if (!onlyNameAndDesc) {
|
||||
|
@ -239,31 +240,39 @@ Result<std::shared_ptr<IntSettingV3>> IntSettingV3::parse(std::string const& key
|
|||
root.has("min").into(ret->m_impl->minValue);
|
||||
root.has("max").into(ret->m_impl->maxValue);
|
||||
if (auto controls = root.has("control")) {
|
||||
controls.has("arrows");
|
||||
controls.has("big-arrows");
|
||||
controls.has("arrow-step").into(ret->m_impl->controls.arrowStepSize);
|
||||
if (!controls.has("arrows").template get<bool>()) {
|
||||
ret->m_impl->controls.arrowStepSize = 0;
|
||||
}
|
||||
controls.has("big-arrow-step").into(ret->m_impl->controls.bigArrowStepSize);
|
||||
if (!controls.has("big-arrows").template get<bool>()) {
|
||||
ret->m_impl->controls.bigArrowStepSize = 0;
|
||||
}
|
||||
controls.has("slider").into(ret->m_impl->controls.sliderEnabled);
|
||||
controls.has("slider-step").into(ret->m_impl->controls.sliderSnap);
|
||||
controls.has("input").into(ret->m_impl->controls.textInputEnabled);
|
||||
// Without "min" or "max" slider makes no sense
|
||||
if (!ret->m_impl->minValue || !ret->m_impl->maxValue) {
|
||||
if (ret->m_impl->controls.sliderEnabled) {
|
||||
log::warn(
|
||||
"Setting '{}' has \"controls.slider\" enabled but doesn't "
|
||||
"have both \"min\" and \"max\" defined - the slider has "
|
||||
"been force-disabled!",
|
||||
key
|
||||
);
|
||||
}
|
||||
ret->m_impl->controls.sliderEnabled = false;
|
||||
}
|
||||
controls.checkUnknownKeys();
|
||||
}
|
||||
|
||||
// Disable arrows if they aren't enabled
|
||||
// This silly code is because step size being 0 is what defines if they are enabled
|
||||
|
||||
// Small arrows are enabled by default
|
||||
if (!root.has("control").has("arrows").template get<bool>(true)) {
|
||||
ret->m_impl->controls.arrowStepSize = 0;
|
||||
}
|
||||
if (!root.has("control").has("big-arrows").template get<bool>()) {
|
||||
ret->m_impl->controls.bigArrowStepSize = 0;
|
||||
}
|
||||
|
||||
// Without "min" or "max" slider makes no sense
|
||||
if (!ret->m_impl->minValue || !ret->m_impl->maxValue) {
|
||||
if (ret->m_impl->controls.sliderEnabled && root.has("control").has("slider")) {
|
||||
log::warn(
|
||||
"Setting '{}' has \"controls.slider\" enabled but doesn't "
|
||||
"have both \"min\" and \"max\" defined - the slider has "
|
||||
"been force-disabled!",
|
||||
key
|
||||
);
|
||||
}
|
||||
ret->m_impl->controls.sliderEnabled = false;
|
||||
}
|
||||
|
||||
root.checkUnknownKeys();
|
||||
return root.ok(ret);
|
||||
|
@ -279,10 +288,10 @@ int64_t IntSettingV3::getDefaultValue() const {
|
|||
}
|
||||
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);
|
||||
return Err("Value must be at least {}", *m_impl->minValue);
|
||||
}
|
||||
if (m_impl->maxValue && value > *m_impl->maxValue) {
|
||||
return Err("value must be at most {}", *m_impl->maxValue);
|
||||
return Err("Value must be at most {}", *m_impl->maxValue);
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
@ -364,8 +373,8 @@ public:
|
|||
|
||||
struct {
|
||||
// 0 means not enabled
|
||||
size_t arrowStepSize = 1;
|
||||
size_t bigArrowStepSize = 5;
|
||||
double arrowStepSize = 1;
|
||||
double bigArrowStepSize = 5;
|
||||
bool sliderEnabled = true;
|
||||
std::optional<double> sliderSnap;
|
||||
bool textInputEnabled = true;
|
||||
|
@ -385,32 +394,38 @@ Result<std::shared_ptr<FloatSettingV3>> FloatSettingV3::parse(std::string const&
|
|||
root.has("min").into(ret->m_impl->minValue);
|
||||
root.has("max").into(ret->m_impl->maxValue);
|
||||
if (auto controls = root.has("control")) {
|
||||
controls.has("arrows");
|
||||
controls.has("big-arrows");
|
||||
controls.has("arrow-step").into(ret->m_impl->controls.arrowStepSize);
|
||||
if (!controls.has("arrows").template get<bool>()) {
|
||||
ret->m_impl->controls.arrowStepSize = 0;
|
||||
}
|
||||
controls.has("big-arrow-step").into(ret->m_impl->controls.bigArrowStepSize);
|
||||
if (!controls.has("big-arrows").template get<bool>()) {
|
||||
ret->m_impl->controls.bigArrowStepSize = 0;
|
||||
}
|
||||
controls.has("slider").into(ret->m_impl->controls.sliderEnabled);
|
||||
controls.has("slider-step").into(ret->m_impl->controls.sliderSnap);
|
||||
controls.has("input").into(ret->m_impl->controls.textInputEnabled);
|
||||
// Without "min" or "max" slider makes no sense
|
||||
if (!ret->m_impl->minValue || !ret->m_impl->maxValue) {
|
||||
if (ret->m_impl->controls.sliderEnabled) {
|
||||
log::warn(
|
||||
"Setting '{}' has \"controls.slider\" enabled but doesn't "
|
||||
"have both \"min\" and \"max\" defined - the slider has "
|
||||
"been force-disabled!",
|
||||
key
|
||||
);
|
||||
}
|
||||
ret->m_impl->controls.sliderEnabled = false;
|
||||
}
|
||||
controls.checkUnknownKeys();
|
||||
}
|
||||
|
||||
// Disable arrows if they aren't enabled
|
||||
// Small arrows are enabled by default
|
||||
if (!root.has("control").has("arrows").template get<bool>(true)) {
|
||||
ret->m_impl->controls.arrowStepSize = 0;
|
||||
}
|
||||
if (!root.has("control").has("big-arrows").template get<bool>()) {
|
||||
ret->m_impl->controls.bigArrowStepSize = 0;
|
||||
}
|
||||
|
||||
// Without "min" or "max" slider makes no sense
|
||||
if (!ret->m_impl->minValue || !ret->m_impl->maxValue) {
|
||||
if (ret->m_impl->controls.sliderEnabled && root.has("control").has("slider")) {
|
||||
log::warn(
|
||||
"Setting '{}' has \"controls.slider\" enabled but doesn't "
|
||||
"have both \"min\" and \"max\" defined - the slider has "
|
||||
"been force-disabled!",
|
||||
key
|
||||
);
|
||||
}
|
||||
ret->m_impl->controls.sliderEnabled = false;
|
||||
}
|
||||
|
||||
root.checkUnknownKeys();
|
||||
return root.ok(ret);
|
||||
}
|
||||
|
@ -423,10 +438,10 @@ double FloatSettingV3::getDefaultValue() const {
|
|||
}
|
||||
Result<> FloatSettingV3::isValid(double value) const {
|
||||
if (m_impl->minValue && value < *m_impl->minValue) {
|
||||
return Err("value must be at least {}", *m_impl->minValue);
|
||||
return Err("Value must be at least {}", *m_impl->minValue);
|
||||
}
|
||||
if (m_impl->maxValue && value > *m_impl->maxValue) {
|
||||
return Err("value must be at most {}", *m_impl->maxValue);
|
||||
return Err("Value must be at most {}", *m_impl->maxValue);
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
@ -444,10 +459,10 @@ bool FloatSettingV3::isArrowsEnabled() const {
|
|||
bool FloatSettingV3::isBigArrowsEnabled() const {
|
||||
return m_impl->controls.bigArrowStepSize > 0;
|
||||
}
|
||||
size_t FloatSettingV3::getArrowStepSize() const {
|
||||
double FloatSettingV3::getArrowStepSize() const {
|
||||
return m_impl->controls.arrowStepSize;
|
||||
}
|
||||
size_t FloatSettingV3::getBigArrowStepSize() const {
|
||||
double FloatSettingV3::getBigArrowStepSize() const {
|
||||
return m_impl->controls.bigArrowStepSize;
|
||||
}
|
||||
bool FloatSettingV3::isSliderEnabled() const {
|
||||
|
@ -487,8 +502,8 @@ std::optional<Setting> FloatSettingV3::convertToLegacy() const {
|
|||
.controls = {
|
||||
.arrows = this->isArrowsEnabled(),
|
||||
.bigArrows = this->isBigArrowsEnabled(),
|
||||
.arrowStep = this->getArrowStepSize(),
|
||||
.bigArrowStep = this->getBigArrowStepSize(),
|
||||
.arrowStep = static_cast<size_t>(this->getArrowStepSize()),
|
||||
.bigArrowStep = static_cast<size_t>(this->getBigArrowStepSize()),
|
||||
.slider = this->isSliderEnabled(),
|
||||
.sliderStep = this->getSliderSnap(),
|
||||
.input = this->isInputEnabled(),
|
||||
|
@ -538,12 +553,12 @@ std::string StringSettingV3::getDefaultValue() const {
|
|||
Result<> StringSettingV3::isValid(std::string_view value) const {
|
||||
if (m_impl->match) {
|
||||
if (!std::regex_match(std::string(value), std::regex(*m_impl->match))) {
|
||||
return Err("value must match regex {}", *m_impl->match);
|
||||
return Err("Value must match regex {}", *m_impl->match);
|
||||
}
|
||||
}
|
||||
else if (m_impl->oneOf) {
|
||||
if (!ranges::contains(*m_impl->oneOf, std::string(value))) {
|
||||
return Err("value must be one of {}", fmt::join(*m_impl->oneOf, ", "));
|
||||
return Err("Value must be one of {}", fmt::join(*m_impl->oneOf, ", "));
|
||||
}
|
||||
}
|
||||
return Ok();
|
||||
|
@ -594,6 +609,7 @@ class FileSettingV3::Impl final {
|
|||
public:
|
||||
std::filesystem::path value;
|
||||
std::filesystem::path defaultValue;
|
||||
FileType fileType;
|
||||
std::optional<std::vector<utils::file::FilePickOptions::Filter>> filters;
|
||||
};
|
||||
|
||||
|
@ -610,19 +626,32 @@ Result<std::shared_ptr<FileSettingV3>> FileSettingV3::parse(std::string const& k
|
|||
// Replace known paths like `{gd-save-dir}/`
|
||||
try {
|
||||
ret->m_impl->defaultValue = fmt::format(
|
||||
fmt::runtime(ret->m_impl->defaultValue.string()),
|
||||
fmt::arg("gd-save-dir", dirs::getSaveDir()),
|
||||
fmt::arg("gd-game-dir", dirs::getGameDir()),
|
||||
fmt::arg("mod-config-dir", dirs::getModConfigDir() / modID),
|
||||
fmt::arg("mod-save-dir", dirs::getModsSaveDir() / modID),
|
||||
fmt::arg("temp-dir", dirs::getTempDir())
|
||||
fmt::runtime(ret->m_impl->defaultValue.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&) {
|
||||
return Err("Invalid format string for file setting path");
|
||||
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;
|
||||
|
||||
if (auto ty = root.has("filetype")) {
|
||||
ty.assertIsString();
|
||||
switch (hash(ty.template get<std::string>())) {
|
||||
case hash("any"): ret->m_impl->fileType = FileType::Any; break;
|
||||
case hash("file"): ret->m_impl->fileType = FileType::File; break;
|
||||
case hash("folder"): ret->m_impl->fileType = FileType::Folder; break;
|
||||
default: return Err(
|
||||
"Setting '{}' in mod {}: Invalid filetype \"{}\"",
|
||||
key, modID, ty.template get<std::string>()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto controls = root.has("control")) {
|
||||
auto filters = std::vector<file::FilePickOptions::Filter>();
|
||||
for (auto& item : controls.has("filters").items()) {
|
||||
|
@ -647,9 +676,24 @@ std::filesystem::path FileSettingV3::getDefaultValue() const {
|
|||
return m_impl->defaultValue;
|
||||
}
|
||||
Result<> FileSettingV3::isValid(std::filesystem::path const& value) const {
|
||||
if (m_impl->fileType != FileType::Any) {
|
||||
if (!std::filesystem::exists(value)) {
|
||||
return Err("{} must exist", m_impl->fileType == FileType::File ? "File" : "Folder");
|
||||
}
|
||||
if (m_impl->fileType == FileType::File && !std::filesystem::is_regular_file(value)) {
|
||||
return Err("Value must be a file");
|
||||
}
|
||||
if (m_impl->fileType == FileType::Folder && !std::filesystem::is_directory(value)) {
|
||||
return Err("Value must be a folder");
|
||||
}
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
||||
FileSettingV3::FileType FileSettingV3::getFileType() const {
|
||||
return m_impl->fileType;
|
||||
}
|
||||
|
||||
std::optional<std::vector<utils::file::FilePickOptions::Filter>> FileSettingV3::getFilters() const {
|
||||
return m_impl->filters;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue