mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-27 01:45:35 -05:00
improve index related ui
- hide install list behind a popup - remove android and ios filters - don't show not installable mods - allow quick popups to be completely cancelled by esc
This commit is contained in:
parent
3707418355
commit
73169fbf22
11 changed files with 191 additions and 41 deletions
|
@ -243,6 +243,12 @@ namespace geode {
|
||||||
* Check if any of the mods on the index have updates available
|
* Check if any of the mods on the index have updates available
|
||||||
*/
|
*/
|
||||||
bool areUpdatesAvailable() const;
|
bool areUpdatesAvailable() const;
|
||||||
|
/**
|
||||||
|
* Checks if the mod and its required dependencies can be installed
|
||||||
|
* @param item Item to get the list for
|
||||||
|
* @returns Success if the mod and its required dependencies can be installed, an error otherwise
|
||||||
|
*/
|
||||||
|
Result<> canInstall(IndexItemHandle item) const;
|
||||||
/**
|
/**
|
||||||
* Get the list of items needed to install this item (dependencies, etc.)
|
* Get the list of items needed to install this item (dependencies, etc.)
|
||||||
* @param item Item to get the list for
|
* @param item Item to get the list for
|
||||||
|
|
|
@ -96,4 +96,14 @@ namespace geode {
|
||||||
char const* title, std::string const& content, char const* btn1, char const* btn2,
|
char const* title, std::string const& content, char const* btn1, char const* btn2,
|
||||||
float width, utils::MiniFunction<void(FLAlertLayer*, bool)> selected, bool doShow = true
|
float width, utils::MiniFunction<void(FLAlertLayer*, bool)> selected, bool doShow = true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
GEODE_DLL FLAlertLayer* createQuickPopup(
|
||||||
|
char const* title, std::string const& content, char const* btn1, char const* btn2,
|
||||||
|
utils::MiniFunction<void(FLAlertLayer*, bool)> selected, bool doShow, bool cancelledByEscape
|
||||||
|
);
|
||||||
|
|
||||||
|
GEODE_DLL FLAlertLayer* createQuickPopup(
|
||||||
|
char const* title, std::string const& content, char const* btn1, char const* btn2,
|
||||||
|
float width, utils::MiniFunction<void(FLAlertLayer*, bool)> selected, bool doShow, bool cancelledByEscape
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -547,19 +547,18 @@ bool Index::areUpdatesAvailable() const {
|
||||||
|
|
||||||
// Item installation
|
// Item installation
|
||||||
|
|
||||||
Result<IndexInstallList> Index::getInstallList(IndexItemHandle item) const {
|
Result<> Index::canInstall(IndexItemHandle item) const {
|
||||||
if (!item->getAvailablePlatforms().count(GEODE_PLATFORM_TARGET)) {
|
if (!item->getAvailablePlatforms().count(GEODE_PLATFORM_TARGET)) {
|
||||||
return Err("Mod is not available on {}", GEODE_PLATFORM_NAME);
|
return Err("Mod is not available on {}", GEODE_PLATFORM_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexInstallList list;
|
|
||||||
list.target = item;
|
|
||||||
// TODO: ui for picking recommended and suggested mods
|
|
||||||
for (auto& dep : item->getMetadata().getDependencies()) {
|
for (auto& dep : item->getMetadata().getDependencies()) {
|
||||||
// if the dep is resolved, then all its dependencies must be installed
|
// if the dep is resolved, then all its dependencies must be installed
|
||||||
// already in order for that to have happened
|
// already in order for that to have happened
|
||||||
if (dep.isResolved()) continue;
|
if (dep.isResolved()) continue;
|
||||||
|
|
||||||
|
if (dep.importance != ModMetadata::Dependency::Importance::Required) continue;
|
||||||
|
|
||||||
// check if this dep is available in the index
|
// check if this dep is available in the index
|
||||||
if (auto depItem = this->getItem(dep.id, dep.version)) {
|
if (auto depItem = this->getItem(dep.id, dep.version)) {
|
||||||
if (!depItem->getAvailablePlatforms().count(GEODE_PLATFORM_TARGET)) {
|
if (!depItem->getAvailablePlatforms().count(GEODE_PLATFORM_TARGET)) {
|
||||||
|
@ -569,12 +568,55 @@ Result<IndexInstallList> Index::getInstallList(IndexItemHandle item) const {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// recursively add dependencies
|
// recursively add dependencies
|
||||||
|
GEODE_UNWRAP_INTO(auto deps, this->canInstall(depItem));
|
||||||
|
}
|
||||||
|
// otherwise user must get this dependency manually from somewhere
|
||||||
|
else {
|
||||||
|
return Err(
|
||||||
|
"Dependency {} version {} not found in the index! Likely "
|
||||||
|
"reason is that the version of the dependency this mod "
|
||||||
|
"depends on is not available. Please let the developer "
|
||||||
|
"of the mod ({}) know!",
|
||||||
|
dep.id, dep.version.toString(), item->getMetadata().getDeveloper()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<IndexInstallList> Index::getInstallList(IndexItemHandle item) const {
|
||||||
|
if (!item->getAvailablePlatforms().count(GEODE_PLATFORM_TARGET)) {
|
||||||
|
return Err("Mod is not available on {}", GEODE_PLATFORM_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexInstallList list;
|
||||||
|
list.target = item;
|
||||||
|
for (auto& dep : item->getMetadata().getDependencies()) {
|
||||||
|
// if the dep is resolved, then all its dependencies must be installed
|
||||||
|
// already in order for that to have happened
|
||||||
|
if (dep.isResolved()) continue;
|
||||||
|
|
||||||
|
if (dep.importance == ModMetadata::Dependency::Importance::Suggested) continue;
|
||||||
|
|
||||||
|
// check if this dep is available in the index
|
||||||
|
if (auto depItem = this->getItem(dep.id, dep.version)) {
|
||||||
|
if (!depItem->getAvailablePlatforms().count(GEODE_PLATFORM_TARGET)) {
|
||||||
|
// it's fine to not install optional dependencies
|
||||||
|
if (dep.importance != ModMetadata::Dependency::Importance::Required) continue;
|
||||||
|
return Err(
|
||||||
|
"Dependency {} is not available on {}",
|
||||||
|
dep.id, GEODE_PLATFORM_NAME
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// recursively add dependencies
|
||||||
GEODE_UNWRAP_INTO(auto deps, this->getInstallList(depItem));
|
GEODE_UNWRAP_INTO(auto deps, this->getInstallList(depItem));
|
||||||
ranges::push(list.list, deps.list);
|
ranges::push(list.list, deps.list);
|
||||||
}
|
}
|
||||||
// otherwise user must get this dependency manually from somewhere
|
// otherwise user must get this dependency manually from somewhere
|
||||||
// else
|
|
||||||
else {
|
else {
|
||||||
|
// it's fine to not install optional dependencies
|
||||||
|
if (dep.importance != ModMetadata::Dependency::Importance::Required) continue;
|
||||||
return Err(
|
return Err(
|
||||||
"Dependency {} version {} not found in the index! Likely "
|
"Dependency {} version {} not found in the index! Likely "
|
||||||
"reason is that the version of the dependency this mod "
|
"reason is that the version of the dependency this mod "
|
||||||
|
|
|
@ -750,7 +750,37 @@ void IndexItemInfoPopup::onInstallProgress(ModInstallEvent* event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexItemInfoPopup::onInstall(CCObject*) {
|
void IndexItemInfoPopup::onInstall(CCObject*) {
|
||||||
|
createQuickPopup(
|
||||||
|
"Confirm Install",
|
||||||
|
"Installing this mod requires a few other mods to be installed. "
|
||||||
|
"Would you like to continue with <cy>recommended settings</c> or "
|
||||||
|
"<cb>customize</c> which mods to install?",
|
||||||
|
"Recommended", "Customize", 320.f,
|
||||||
|
[&](FLAlertLayer*, bool btn2) {
|
||||||
|
if (!btn2) {
|
||||||
|
auto canInstall = Index::get()->canInstall(m_item);
|
||||||
|
if (!canInstall) {
|
||||||
|
FLAlertLayer::create(
|
||||||
|
"Unable to Install",
|
||||||
|
canInstall.unwrapErr(),
|
||||||
|
"OK"
|
||||||
|
)->show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->preInstall();
|
||||||
|
Index::get()->install(m_item);
|
||||||
|
}
|
||||||
|
else {
|
||||||
InstallListPopup::create(m_item, [&](IndexInstallList const& list) {
|
InstallListPopup::create(m_item, [&](IndexInstallList const& list) {
|
||||||
|
this->preInstall();
|
||||||
|
Index::get()->install(list);
|
||||||
|
})->show();
|
||||||
|
}
|
||||||
|
}, true, true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IndexItemInfoPopup::preInstall() {
|
||||||
if (m_latestVersionLabel) {
|
if (m_latestVersionLabel) {
|
||||||
m_latestVersionLabel->setVisible(false);
|
m_latestVersionLabel->setVisible(false);
|
||||||
}
|
}
|
||||||
|
@ -761,9 +791,6 @@ void IndexItemInfoPopup::onInstall(CCObject*) {
|
||||||
);
|
);
|
||||||
m_installBtnSpr->setString("Cancel");
|
m_installBtnSpr->setString("Cancel");
|
||||||
m_installBtnSpr->setBG("GJ_button_06.png", false);
|
m_installBtnSpr->setBG("GJ_button_06.png", false);
|
||||||
|
|
||||||
Index::get()->install(list);
|
|
||||||
})->show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexItemInfoPopup::onCancel(CCObject*) {
|
void IndexItemInfoPopup::onCancel(CCObject*) {
|
||||||
|
|
|
@ -100,6 +100,8 @@ protected:
|
||||||
void onInstall(CCObject*);
|
void onInstall(CCObject*);
|
||||||
void onCancel(CCObject*);
|
void onCancel(CCObject*);
|
||||||
|
|
||||||
|
void preInstall();
|
||||||
|
|
||||||
CCNode* createLogo(CCSize const& size) override;
|
CCNode* createLogo(CCSize const& size) override;
|
||||||
ModMetadata getMetadata() const override;
|
ModMetadata getMetadata() const override;
|
||||||
|
|
||||||
|
|
|
@ -229,7 +229,7 @@ bool IndexItemInstallListCell::init(
|
||||||
|
|
||||||
if (importance != ModMetadata::Dependency::Importance::Required) {
|
if (importance != ModMetadata::Dependency::Importance::Required) {
|
||||||
message->setCString("N/A (Optional)");
|
message->setCString("N/A (Optional)");
|
||||||
message->setColor({ 120, 15, 15 });
|
message->setColor({ 163, 24, 24 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ bool UnknownInstallListCell::init(
|
||||||
message->setColor({ 240, 31, 31 });
|
message->setColor({ 240, 31, 31 });
|
||||||
if (optional) {
|
if (optional) {
|
||||||
message->setCString("Missing (Optional)");
|
message->setCString("Missing (Optional)");
|
||||||
message->setColor({ 120, 15, 15 });
|
message->setColor({ 163, 24, 24 });
|
||||||
}
|
}
|
||||||
this->addChild(message);
|
this->addChild(message);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -97,8 +97,7 @@ static std::optional<int> queryMatch(ModListQuery const& query, Mod* mod) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<int> queryMatch(ModListQuery const& query, IndexItemHandle item) {
|
static std::optional<int> queryMatch(ModListQuery const& query, IndexItemHandle item) {
|
||||||
// if no force visibility was provided and item is already installed, don't
|
// if no force visibility was provided and item is already installed, don't show it
|
||||||
// show it
|
|
||||||
if (!query.forceVisibility && Loader::get()->isModInstalled(item->getMetadata().getID())) {
|
if (!query.forceVisibility && Loader::get()->isModInstalled(item->getMetadata().getID())) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
@ -114,6 +113,16 @@ static std::optional<int> queryMatch(ModListQuery const& query, IndexItemHandle
|
||||||
})) {
|
})) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
// if no force visibility was provided and item is already installed, don't show it
|
||||||
|
auto canInstall = Index::get()->canInstall(item);
|
||||||
|
if (!query.forceInvalid && !canInstall) {
|
||||||
|
log::warn(
|
||||||
|
"Removing {} from the list because it cannot be installed: {}",
|
||||||
|
item->getMetadata().getID(),
|
||||||
|
canInstall.unwrapErr()
|
||||||
|
);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
// otherwise match keywords
|
// otherwise match keywords
|
||||||
if (auto match = queryMatchKeywords(query, item->getMetadata())) {
|
if (auto match = queryMatchKeywords(query, item->getMetadata())) {
|
||||||
auto weighted = match.value();
|
auto weighted = match.value();
|
||||||
|
@ -190,7 +199,8 @@ CCArray* ModListLayer::createModCells(ModListType type, ModListQuery const& quer
|
||||||
// sort the mods by match score
|
// sort the mods by match score
|
||||||
std::multimap<int, IndexItemHandle> sorted;
|
std::multimap<int, IndexItemHandle> sorted;
|
||||||
|
|
||||||
for (auto const& item : Index::get()->getItems()) {
|
auto index = Index::get();
|
||||||
|
for (auto const& item : index->getItems()) {
|
||||||
if (auto match = queryMatch(query, item)) {
|
if (auto match = queryMatch(query, item)) {
|
||||||
sorted.insert({ match.value(), item });
|
sorted.insert({ match.value(), item });
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,15 @@ struct ModListQuery {
|
||||||
*/
|
*/
|
||||||
std::optional<std::string> keywords;
|
std::optional<std::string> keywords;
|
||||||
/**
|
/**
|
||||||
* Force mods to be shown on the list unless they explicitly mismatch some
|
* Force already installed mods to be shown on the list unless they explicitly mismatch some
|
||||||
* tags (used to show installed mods on index)
|
* tags (used to show installed mods on index)
|
||||||
*/
|
*/
|
||||||
bool forceVisibility;
|
bool forceVisibility;
|
||||||
|
/**
|
||||||
|
* Force not installable mods to be shown on the list unless they explicitly mismatch some
|
||||||
|
* tags (used to show installed mods on index)
|
||||||
|
*/
|
||||||
|
bool forceInvalid;
|
||||||
/**
|
/**
|
||||||
* Empty means current platform
|
* Empty means current platform
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
|
|
||||||
#include <Geode/binding/GameToolbox.hpp>
|
#include <Geode/binding/GameToolbox.hpp>
|
||||||
#include <Geode/binding/CCMenuItemToggler.hpp>
|
#include <Geode/binding/CCMenuItemToggler.hpp>
|
||||||
#include <Geode/ui/SelectList.hpp>
|
|
||||||
|
// re-add when we actually add the platforms
|
||||||
|
const float iosAndAndroidSize = 45.f;
|
||||||
|
|
||||||
bool SearchFilterPopup::setup(ModListLayer* layer, ModListType type) {
|
bool SearchFilterPopup::setup(ModListLayer* layer, ModListType type) {
|
||||||
m_noElasticity = true;
|
m_noElasticity = true;
|
||||||
|
@ -14,66 +16,77 @@ bool SearchFilterPopup::setup(ModListLayer* layer, ModListType type) {
|
||||||
this->setTitle("Search Filters");
|
this->setTitle("Search Filters");
|
||||||
|
|
||||||
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
||||||
auto pos = CCPoint { winSize.width / 2 - 140.f, winSize.height / 2 + 45.f };
|
auto pos = CCPoint { winSize.width / 2 - 140.f, winSize.height / 2 + 45.f - iosAndAndroidSize * 0.25f };
|
||||||
|
|
||||||
// platforms
|
// platforms
|
||||||
|
|
||||||
auto platformTitle = CCLabelBMFont::create("Platforms", "goldFont.fnt");
|
auto platformTitle = CCLabelBMFont::create("Platforms", "goldFont.fnt");
|
||||||
platformTitle->setPosition(winSize.width / 2 - 85.f, winSize.height / 2 + 75.f);
|
platformTitle->setAnchorPoint({ 0.5f, 1.f });
|
||||||
|
platformTitle->setPosition(winSize.width / 2 - 85.f, winSize.height / 2 + 81.5f - iosAndAndroidSize * 0.25f);
|
||||||
platformTitle->setScale(.5f);
|
platformTitle->setScale(.5f);
|
||||||
m_mainLayer->addChild(platformTitle);
|
m_mainLayer->addChild(platformTitle);
|
||||||
|
|
||||||
auto platformBG = CCScale9Sprite::create("square02b_001.png", { 0.0f, 0.0f, 80.0f, 80.0f });
|
auto platformBG = CCScale9Sprite::create("square02b_001.png", { 0.0f, 0.0f, 80.0f, 80.0f });
|
||||||
platformBG->setColor({ 0, 0, 0 });
|
platformBG->setColor({ 0, 0, 0 });
|
||||||
platformBG->setOpacity(90);
|
platformBG->setOpacity(90);
|
||||||
platformBG->setContentSize({ 290.f, 205.f });
|
platformBG->setContentSize({ 290.f, 205.f - iosAndAndroidSize * 2.f });
|
||||||
platformBG->setPosition(winSize.width / 2 - 85.f, winSize.height / 2 + 11.f);
|
platformBG->setAnchorPoint({ 0.5f, 1.f });
|
||||||
|
platformBG->setPosition(winSize.width / 2 - 85.f, winSize.height / 2 + 62.25f - iosAndAndroidSize * 0.25f);
|
||||||
platformBG->setScale(.5f);
|
platformBG->setScale(.5f);
|
||||||
m_mainLayer->addChild(platformBG);
|
m_mainLayer->addChild(platformBG);
|
||||||
|
|
||||||
this->enable(this->addPlatformToggle("Windows", PlatformID::Windows, pos), type);
|
this->enable(this->addPlatformToggle("Windows", PlatformID::Windows, pos), type);
|
||||||
this->enable(this->addPlatformToggle("macOS", PlatformID::MacOS, pos), type);
|
this->enable(this->addPlatformToggle("macOS", PlatformID::MacOS, pos), type);
|
||||||
this->enable(this->addPlatformToggle("IOS", PlatformID::iOS, pos), type);
|
//this->enable(this->addPlatformToggle("IOS", PlatformID::iOS, pos), type);
|
||||||
this->enable(this->addPlatformToggle("Android", PlatformID::Android, pos), type);
|
//this->enable(this->addPlatformToggle("Android", PlatformID::Android, pos), type);
|
||||||
|
|
||||||
// show installed
|
// show installed
|
||||||
|
|
||||||
auto installedTitle = CCLabelBMFont::create("Other", "goldFont.fnt");
|
auto installedTitle = CCLabelBMFont::create("Other", "goldFont.fnt");
|
||||||
installedTitle->setPosition(winSize.width / 2 - 85.f, winSize.height / 2 - 57.f);
|
installedTitle->setAnchorPoint({ 0.5f, 1.f });
|
||||||
|
installedTitle->setPosition(winSize.width / 2 - 85.f, winSize.height / 2 - 50.5f + iosAndAndroidSize - iosAndAndroidSize * 0.25f);
|
||||||
installedTitle->setScale(.5f);
|
installedTitle->setScale(.5f);
|
||||||
m_mainLayer->addChild(installedTitle);
|
m_mainLayer->addChild(installedTitle);
|
||||||
|
|
||||||
auto installedBG = CCScale9Sprite::create("square02b_001.png", { 0.0f, 0.0f, 80.0f, 80.0f });
|
auto installedBG = CCScale9Sprite::create("square02b_001.png", { 0.0f, 0.0f, 80.0f, 80.0f });
|
||||||
installedBG->setColor({ 0, 0, 0 });
|
installedBG->setColor({ 0, 0, 0 });
|
||||||
installedBG->setOpacity(90);
|
installedBG->setOpacity(90);
|
||||||
installedBG->setContentSize({ 290.f, 65.f });
|
installedBG->setContentSize({ 290.f, 110.f });
|
||||||
installedBG->setPosition(winSize.width / 2 - 85.f, winSize.height / 2 - 85.f);
|
installedBG->setAnchorPoint({ 0.5f, 1.f });
|
||||||
|
installedBG->setPosition(winSize.width / 2 - 85.f, winSize.height / 2 - 68.75f + iosAndAndroidSize - iosAndAndroidSize * 0.25f);
|
||||||
installedBG->setScale(.5f);
|
installedBG->setScale(.5f);
|
||||||
m_mainLayer->addChild(installedBG);
|
m_mainLayer->addChild(installedBG);
|
||||||
|
|
||||||
pos = CCPoint { winSize.width / 2 - 140.f, winSize.height / 2 - 85.f };
|
pos = CCPoint { winSize.width / 2 - 140.f, winSize.height / 2 - 85.f + iosAndAndroidSize - iosAndAndroidSize * 0.25f };
|
||||||
|
|
||||||
this->addToggle(
|
this->addToggle(
|
||||||
"Show Installed", menu_selector(SearchFilterPopup::onShowInstalled),
|
"Show Installed", menu_selector(SearchFilterPopup::onShowInstalled),
|
||||||
m_modLayer->getQuery().forceVisibility, 0, pos
|
m_modLayer->getQuery().forceVisibility, 0, pos
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this->addToggle(
|
||||||
|
"Show Invalid", menu_selector(SearchFilterPopup::onShowInvalid),
|
||||||
|
m_modLayer->getQuery().forceInvalid, 1, pos
|
||||||
|
);
|
||||||
|
|
||||||
// tags
|
// tags
|
||||||
|
|
||||||
auto tagsTitle = CCLabelBMFont::create("Tags", "goldFont.fnt");
|
auto tagsTitle = CCLabelBMFont::create("Tags", "goldFont.fnt");
|
||||||
tagsTitle->setPosition(winSize.width / 2 + 85.f, winSize.height / 2 + 75.f);
|
tagsTitle->setAnchorPoint({ 0.5f, 1.f });
|
||||||
|
tagsTitle->setPosition(winSize.width / 2 + 85.f, winSize.height / 2 + 81.5f - iosAndAndroidSize * 0.25f);
|
||||||
tagsTitle->setScale(.5f);
|
tagsTitle->setScale(.5f);
|
||||||
m_mainLayer->addChild(tagsTitle);
|
m_mainLayer->addChild(tagsTitle);
|
||||||
|
|
||||||
auto tagsBG = CCScale9Sprite::create("square02b_001.png", { 0.0f, 0.0f, 80.0f, 80.0f });
|
auto tagsBG = CCScale9Sprite::create("square02b_001.png", { 0.0f, 0.0f, 80.0f, 80.0f });
|
||||||
tagsBG->setColor({ 0, 0, 0 });
|
tagsBG->setColor({ 0, 0, 0 });
|
||||||
tagsBG->setOpacity(90);
|
tagsBG->setOpacity(90);
|
||||||
tagsBG->setContentSize({ 290.f, 328.f });
|
tagsBG->setContentSize({ 290.f, 328.f - iosAndAndroidSize });
|
||||||
tagsBG->setPosition(winSize.width / 2 + 85.f, winSize.height / 2 - 19.5f);
|
tagsBG->setAnchorPoint({ 0.5f, 1.f });
|
||||||
|
tagsBG->setPosition(winSize.width / 2 + 85.f, winSize.height / 2 + 62.5f - iosAndAndroidSize * 0.25f);
|
||||||
tagsBG->setScale(.5f);
|
tagsBG->setScale(.5f);
|
||||||
m_mainLayer->addChild(tagsBG);
|
m_mainLayer->addChild(tagsBG);
|
||||||
|
|
||||||
pos = CCPoint { winSize.width / 2 + 30.f, winSize.height / 2 + 45.f };
|
pos = CCPoint { winSize.width / 2 + 30.f, winSize.height / 2 + 45.f - iosAndAndroidSize * 0.25f };
|
||||||
|
|
||||||
for (auto& tag : Index::get()->getTags()) {
|
for (auto& tag : Index::get()->getTags()) {
|
||||||
auto toggle = CCMenuItemToggler::createWithStandardSprites(
|
auto toggle = CCMenuItemToggler::createWithStandardSprites(
|
||||||
|
@ -116,6 +129,11 @@ void SearchFilterPopup::onShowInstalled(CCObject* sender) {
|
||||||
m_modLayer->getQuery().forceVisibility = !toggle->isToggled();
|
m_modLayer->getQuery().forceVisibility = !toggle->isToggled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SearchFilterPopup::onShowInvalid(CCObject* sender) {
|
||||||
|
auto toggle = static_cast<CCMenuItemToggler*>(sender);
|
||||||
|
m_modLayer->getQuery().forceInvalid = !toggle->isToggled();
|
||||||
|
}
|
||||||
|
|
||||||
void SearchFilterPopup::enable(CCMenuItemToggler* toggle, ModListType type) {
|
void SearchFilterPopup::enable(CCMenuItemToggler* toggle, ModListType type) {
|
||||||
if (type == ModListType::Installed) {
|
if (type == ModListType::Installed) {
|
||||||
toggle->setEnabled(false);
|
toggle->setEnabled(false);
|
||||||
|
@ -162,7 +180,7 @@ void SearchFilterPopup::onClose(CCObject* sender) {
|
||||||
|
|
||||||
SearchFilterPopup* SearchFilterPopup::create(ModListLayer* layer, ModListType type) {
|
SearchFilterPopup* SearchFilterPopup::create(ModListLayer* layer, ModListType type) {
|
||||||
auto ret = new SearchFilterPopup();
|
auto ret = new SearchFilterPopup();
|
||||||
if (ret && ret->init(350.f, 240.f, layer, type)) {
|
if (ret && ret->init(350.f, 240.f - iosAndAndroidSize * 0.5f, layer, type)) {
|
||||||
ret->autorelease();
|
ret->autorelease();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ protected:
|
||||||
|
|
||||||
void onPlatformToggle(CCObject*);
|
void onPlatformToggle(CCObject*);
|
||||||
void onShowInstalled(CCObject*);
|
void onShowInstalled(CCObject*);
|
||||||
|
void onShowInvalid(CCObject*);
|
||||||
void onTag(CCObject*);
|
void onTag(CCObject*);
|
||||||
|
|
||||||
void enable(CCMenuItemToggler* toggle, ModListType type);
|
void enable(CCMenuItemToggler* toggle, ModListType type);
|
||||||
|
|
|
@ -5,8 +5,18 @@ using namespace geode::prelude;
|
||||||
class QuickPopup : public FLAlertLayer, public FLAlertLayerProtocol {
|
class QuickPopup : public FLAlertLayer, public FLAlertLayerProtocol {
|
||||||
protected:
|
protected:
|
||||||
MiniFunction<void(FLAlertLayer*, bool)> m_selected;
|
MiniFunction<void(FLAlertLayer*, bool)> m_selected;
|
||||||
|
bool m_cancelledByEscape;
|
||||||
|
bool m_usedEscape = false;
|
||||||
|
|
||||||
|
void keyBackClicked() override {
|
||||||
|
m_usedEscape = true;
|
||||||
|
FLAlertLayer::keyBackClicked();
|
||||||
|
}
|
||||||
|
|
||||||
void FLAlert_Clicked(FLAlertLayer* layer, bool btn2) override {
|
void FLAlert_Clicked(FLAlertLayer* layer, bool btn2) override {
|
||||||
|
if (m_cancelledByEscape && m_usedEscape) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (m_selected) {
|
if (m_selected) {
|
||||||
m_selected(layer, btn2);
|
m_selected(layer, btn2);
|
||||||
}
|
}
|
||||||
|
@ -15,10 +25,11 @@ protected:
|
||||||
public:
|
public:
|
||||||
static QuickPopup* create(
|
static QuickPopup* create(
|
||||||
char const* title, std::string const& content, char const* btn1, char const* btn2,
|
char const* title, std::string const& content, char const* btn1, char const* btn2,
|
||||||
float width, MiniFunction<void(FLAlertLayer*, bool)> selected
|
float width, MiniFunction<void(FLAlertLayer*, bool)> selected, bool cancelledByEscape
|
||||||
) {
|
) {
|
||||||
auto inst = new QuickPopup;
|
auto inst = new QuickPopup;
|
||||||
inst->m_selected = selected;
|
inst->m_selected = selected;
|
||||||
|
inst->m_cancelledByEscape = cancelledByEscape;
|
||||||
if (inst && inst->init(inst, title, content, btn1, btn2, width, false, .0f)) {
|
if (inst && inst->init(inst, title, content, btn1, btn2, width, false, .0f)) {
|
||||||
inst->autorelease();
|
inst->autorelease();
|
||||||
return inst;
|
return inst;
|
||||||
|
@ -32,7 +43,7 @@ FLAlertLayer* geode::createQuickPopup(
|
||||||
char const* title, std::string const& content, char const* btn1, char const* btn2, float width,
|
char const* title, std::string const& content, char const* btn1, char const* btn2, float width,
|
||||||
MiniFunction<void(FLAlertLayer*, bool)> selected, bool doShow
|
MiniFunction<void(FLAlertLayer*, bool)> selected, bool doShow
|
||||||
) {
|
) {
|
||||||
auto ret = QuickPopup::create(title, content, btn1, btn2, width, selected);
|
auto ret = QuickPopup::create(title, content, btn1, btn2, width, selected, false);
|
||||||
if (doShow) {
|
if (doShow) {
|
||||||
ret->show();
|
ret->show();
|
||||||
}
|
}
|
||||||
|
@ -45,3 +56,21 @@ FLAlertLayer* geode::createQuickPopup(
|
||||||
) {
|
) {
|
||||||
return createQuickPopup(title, content, btn1, btn2, 350.f, selected, doShow);
|
return createQuickPopup(title, content, btn1, btn2, 350.f, selected, doShow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FLAlertLayer* geode::createQuickPopup(
|
||||||
|
char const* title, std::string const& content, char const* btn1, char const* btn2, float width,
|
||||||
|
MiniFunction<void(FLAlertLayer*, bool)> selected, bool doShow, bool cancelledByEscape
|
||||||
|
) {
|
||||||
|
auto ret = QuickPopup::create(title, content, btn1, btn2, width, selected, cancelledByEscape);
|
||||||
|
if (doShow) {
|
||||||
|
ret->show();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAlertLayer* geode::createQuickPopup(
|
||||||
|
char const* title, std::string const& content, char const* btn1, char const* btn2,
|
||||||
|
MiniFunction<void(FLAlertLayer*, bool)> selected, bool doShow, bool cancelledByEscape
|
||||||
|
) {
|
||||||
|
return createQuickPopup(title, content, btn1, btn2, 350.f, selected, doShow, cancelledByEscape);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue