folder settings & allow picking which dialog to use

This commit is contained in:
HJfod 2024-08-24 12:13:58 +03:00
parent 1a82d12b7b
commit 56f878ccb3
4 changed files with 71 additions and 56 deletions

View file

@ -328,16 +328,11 @@ namespace geode {
FileSettingV3(PrivateMarker); FileSettingV3(PrivateMarker);
static Result<std::shared_ptr<FileSettingV3>> parse(std::string const& key, std::string const& modID, matjson::Value const& json); 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; std::filesystem::path getDefaultValue() const override;
Result<> isValid(std::filesystem::path const& value) const override; Result<> isValid(std::filesystem::path const& value) const override;
FileType getFileType() const; bool isFolder() const;
bool useSaveDialog() const;
std::optional<std::vector<utils::file::FilePickOptions::Filter>> getFilters() const; std::optional<std::vector<utils::file::FilePickOptions::Filter>> getFilters() const;

View file

@ -21,6 +21,7 @@ private:
{ "float", &FloatSettingV3::parse }, { "float", &FloatSettingV3::parse },
{ "string", &StringSettingV3::parse }, { "string", &StringSettingV3::parse },
{ "file", &FileSettingV3::parse }, { "file", &FileSettingV3::parse },
{ "folder", &FileSettingV3::parse },
{ "path", &FileSettingV3::parse }, { "path", &FileSettingV3::parse },
{ "rgb", &Color3BSettingV3::parse }, { "rgb", &Color3BSettingV3::parse },
{ "color", &Color3BSettingV3::parse }, { "color", &Color3BSettingV3::parse },

View file

@ -347,17 +347,17 @@ bool FileSettingNodeV3::init(std::shared_ptr<FileSettingV3> setting, float width
labelBG->setScale(.25f); labelBG->setScale(.25f);
labelBG->setColor({ 0, 0, 0 }); labelBG->setColor({ 0, 0, 0 });
labelBG->setOpacity(90); labelBG->setOpacity(90);
labelBG->setContentSize({ 400, 80 }); labelBG->setContentSize({ 420, 80 });
this->getButtonMenu()->addChildAtPosition(labelBG, Anchor::Center, ccp(-15, 0)); this->getButtonMenu()->addChildAtPosition(labelBG, Anchor::Center, ccp(-10, 0));
m_fileIcon = CCSprite::create(); m_fileIcon = CCSprite::create();
this->getButtonMenu()->addChildAtPosition(m_fileIcon, Anchor::Left, ccp(3, 0)); this->getButtonMenu()->addChildAtPosition(m_fileIcon, Anchor::Left, ccp(5, 0));
m_nameLabel = CCLabelBMFont::create("", "bigFont.fnt"); m_nameLabel = CCLabelBMFont::create("", "bigFont.fnt");
this->getButtonMenu()->addChildAtPosition(m_nameLabel, Anchor::Left, ccp(11, 0), ccp(0, .5f)); this->getButtonMenu()->addChildAtPosition(m_nameLabel, Anchor::Left, ccp(13, 0), ccp(0, .5f));
auto selectSpr = CCSprite::createWithSpriteFrameName("GJ_plus2Btn_001.png"); auto selectSpr = CCSprite::createWithSpriteFrameName("GJ_plus2Btn_001.png");
selectSpr->setScale(.75f); selectSpr->setScale(.7f);
auto selectBtn = CCMenuItemSpriteExtra::create( auto selectBtn = CCMenuItemSpriteExtra::create(
selectSpr, this, menu_selector(FileSettingNodeV3::onPickFile) selectSpr, this, menu_selector(FileSettingNodeV3::onPickFile)
); );
@ -370,18 +370,21 @@ bool FileSettingNodeV3::init(std::shared_ptr<FileSettingV3> setting, float width
void FileSettingNodeV3::updateState() { void FileSettingNodeV3::updateState() {
SettingNodeV3::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( m_fileIcon->setDisplayFrame(CCSpriteFrameCache::get()->spriteFrameByName(
ty == FileSettingV3::FileType::File ? "file.png"_spr : "folderIcon_001.png" this->getSetting()->isFolder() ? "folderIcon_001.png" : "file.png"_spr
)); ));
limitNodeSize(m_fileIcon, ccp(10, 10), 1.f, .1f); limitNodeSize(m_fileIcon, ccp(10, 10), 1.f, .1f);
m_nameLabel->setString(m_path.filename().string().c_str()); if (m_path.empty()) {
m_nameLabel->limitLabelWidth(75, .4f, .1f); m_nameLabel->setString(this->getSetting()->isFolder() ? "No Folder Selected" : "No File Selected");
m_nameLabel->setColor(ccGRAY);
m_nameLabel->setOpacity(155);
}
else {
m_nameLabel->setString(m_path.filename().string().c_str());
m_nameLabel->setColor(ccWHITE);
m_nameLabel->setOpacity(255);
}
m_nameLabel->limitLabelWidth(75, .35f, .1f);
} }
void FileSettingNodeV3::onCommit() { void FileSettingNodeV3::onCommit() {
@ -407,9 +410,9 @@ void FileSettingNodeV3::onPickFile(CCObject*) {
} }
}); });
m_pickListener.setFilter(file::pick( m_pickListener.setFilter(file::pick(
this->getSetting()->getFileType() == FileSettingV3::FileType::Folder ? this->getSetting()->isFolder() ?
file::PickMode::OpenFolder : file::PickMode::OpenFolder :
file::PickMode::OpenFile, (this->getSetting()->useSaveDialog() ? file::PickMode::SaveFile : file::PickMode::OpenFile),
{ {
dirs::getGameDir(), dirs::getGameDir(),
this->getSetting()->getFilters().value_or(std::vector<file::FilePickOptions::Filter>()) this->getSetting()->getFilters().value_or(std::vector<file::FilePickOptions::Filter>())

View file

@ -609,7 +609,8 @@ class FileSettingV3::Impl final {
public: public:
std::filesystem::path value; std::filesystem::path value;
std::filesystem::path defaultValue; std::filesystem::path defaultValue;
FileType fileType; bool folder = false;
bool useSaveDialog = false; // this option makes no sense if folder = true
std::optional<std::vector<utils::file::FilePickOptions::Filter>> filters; std::optional<std::vector<utils::file::FilePickOptions::Filter>> filters;
}; };
@ -623,7 +624,7 @@ Result<std::shared_ptr<FileSettingV3>> FileSettingV3::parse(std::string const& k
ret->parseDefaultValue(root, ret->m_impl->defaultValue); ret->parseDefaultValue(root, ret->m_impl->defaultValue);
ret->m_impl->value = ret->m_impl->defaultValue; ret->m_impl->value = ret->m_impl->defaultValue;
// Replace known paths like `{gd-save-dir}/` // Replace known paths like `{gd-save-dir}/`
try { try {
ret->m_impl->defaultValue = fmt::format( ret->m_impl->defaultValue = fmt::format(
fmt::runtime(ret->m_impl->defaultValue.string()), fmt::runtime(ret->m_impl->defaultValue.string()),
@ -639,29 +640,41 @@ Result<std::shared_ptr<FileSettingV3>> FileSettingV3::parse(std::string const& k
} }
ret->m_impl->value = ret->m_impl->defaultValue; ret->m_impl->value = ret->m_impl->defaultValue;
if (auto ty = root.has("filetype")) { std::string type;
ty.assertIsString(); root.needs("type").into(type);
switch (hash(ty.template get<std::string>())) { if (type == "folder") {
case hash("any"): ret->m_impl->fileType = FileType::Any; break; ret->m_impl->folder = true;
case hash("file"): ret->m_impl->fileType = FileType::File; break; // folder-specific stuff if they ever exist
case hash("folder"): ret->m_impl->fileType = FileType::Folder; break; }
default: return Err( else if (type == "file" || type == "path") {
"Setting '{}' in mod {}: Invalid filetype \"{}\"", if (type == "path") {
key, modID, ty.template get<std::string>() log::warn(
"Setting '{}' in mod {}: the \"path\" type has been "
"deprecated, use \"type\": \"file\" or \"type\": \"folder\" instead",
key, modID
); );
} }
} std::string dialogType;
root.has("dialog").into(dialogType);
if (auto controls = root.has("control")) { switch (hash(dialogType)) {
auto filters = std::vector<file::FilePickOptions::Filter>(); case hash("save"): ret->m_impl->useSaveDialog = true; break;
for (auto& item : controls.has("filters").items()) { case hash("open"): ret->m_impl->useSaveDialog = false; break;
utils::file::FilePickOptions::Filter filter; case hash(""): break;
item.has("description").into(filter.description); default: return Err("Setting '{}' in mod {}: unknown \"dialog\" type \"{}\"", key, modID, dialogType);
item.has("files").into(filter.files);
filters.push_back(filter);
} }
if (!filters.empty()) {
ret->m_impl->filters.emplace(filters); // Filter controls only make sense for files but not for folders
if (auto controls = root.has("control")) {
auto filters = std::vector<file::FilePickOptions::Filter>();
for (auto& item : controls.has("filters").items()) {
utils::file::FilePickOptions::Filter filter;
item.has("description").into(filter.description);
item.has("files").into(filter.files);
filters.push_back(filter);
}
if (!filters.empty()) {
ret->m_impl->filters.emplace(filters);
}
} }
} }
@ -676,22 +689,25 @@ std::filesystem::path FileSettingV3::getDefaultValue() const {
return m_impl->defaultValue; return m_impl->defaultValue;
} }
Result<> FileSettingV3::isValid(std::filesystem::path const& value) const { Result<> FileSettingV3::isValid(std::filesystem::path const& value) const {
if (m_impl->fileType != FileType::Any) { std::error_code ec;
if (!std::filesystem::exists(value)) { if (m_impl->folder) {
return Err("{} must exist", m_impl->fileType == FileType::File ? "File" : "Folder"); if (!std::filesystem::is_directory(value, ec)) {
}
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 Err("Value must be a folder");
} }
} }
else {
if (!std::filesystem::is_regular_file(value, ec)) {
return Err("Value must be a file");
}
}
return Ok(); return Ok();
} }
FileSettingV3::FileType FileSettingV3::getFileType() const { bool FileSettingV3::isFolder() const {
return m_impl->fileType; return m_impl->folder;
}
bool FileSettingV3::useSaveDialog() const {
return m_impl->useSaveDialog;
} }
std::optional<std::vector<utils::file::FilePickOptions::Filter>> FileSettingV3::getFilters() const { std::optional<std::vector<utils::file::FilePickOptions::Filter>> FileSettingV3::getFilters() const {