mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-26 17:36:05 -05:00
index work!!
- add tag support for index - rename CategoryNode to TagNode - add them back to the UI + fix spacing issues related to them - deleted ModListView, now using a generic ListView with the mod cells added as children to it
This commit is contained in:
parent
e763e271bf
commit
84bdeb7beb
14 changed files with 339 additions and 408 deletions
|
@ -58,6 +58,7 @@ namespace geode {
|
||||||
std::unordered_set<PlatformID> platforms;
|
std::unordered_set<PlatformID> platforms;
|
||||||
} download;
|
} download;
|
||||||
bool isFeatured;
|
bool isFeatured;
|
||||||
|
std::unordered_set<std::string> tags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create IndexItem from a directory
|
* Create IndexItem from a directory
|
||||||
|
|
|
@ -122,6 +122,7 @@ Result<IndexItemHandle> IndexItem::createFromDir(
|
||||||
.platforms = platforms,
|
.platforms = platforms,
|
||||||
},
|
},
|
||||||
.isFeatured = root.has("is-featured").template get<bool>(),
|
.isFeatured = root.has("is-featured").template get<bool>(),
|
||||||
|
.tags = root.has("tags").template get<std::unordered_set<std::string>>()
|
||||||
});
|
});
|
||||||
if (checker.isError()) {
|
if (checker.isError()) {
|
||||||
return Err(checker.getError());
|
return Err(checker.getError());
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cocos2d.h>
|
|
||||||
|
|
||||||
USE_GEODE_NAMESPACE();
|
|
||||||
|
|
||||||
enum class CategoryNodeStyle {
|
|
||||||
Tag,
|
|
||||||
Dot,
|
|
||||||
};
|
|
||||||
|
|
||||||
class CategoryNode : public CCNode {
|
|
||||||
protected:
|
|
||||||
bool init(std::string const& category, CategoryNodeStyle style);
|
|
||||||
|
|
||||||
public:
|
|
||||||
static CategoryNode* create(
|
|
||||||
std::string const& category, CategoryNodeStyle style = CategoryNodeStyle::Tag
|
|
||||||
);
|
|
||||||
|
|
||||||
static ccColor3B categoryToColor(std::string const& category);
|
|
||||||
};
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "ModInfoPopup.hpp"
|
#include "ModInfoPopup.hpp"
|
||||||
|
|
||||||
#include "../dev/HookListLayer.hpp"
|
#include "../dev/HookListLayer.hpp"
|
||||||
#include "../list/ModListView.hpp"
|
#include "../list/ModListLayer.hpp"
|
||||||
#include "../settings/ModSettingsPopup.hpp"
|
#include "../settings/ModSettingsPopup.hpp"
|
||||||
#include "../settings/AdvancedSettingsPopup.hpp"
|
#include "../settings/AdvancedSettingsPopup.hpp"
|
||||||
#include <InternalLoader.hpp>
|
#include <InternalLoader.hpp>
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
#include <Geode/ui/BasedButton.hpp>
|
#include <Geode/ui/BasedButton.hpp>
|
||||||
#include <Geode/ui/IconButtonSprite.hpp>
|
#include <Geode/ui/IconButtonSprite.hpp>
|
||||||
#include <Geode/ui/GeodeUI.hpp>
|
#include <Geode/ui/GeodeUI.hpp>
|
||||||
|
#include <Geode/ui/MDPopup.hpp>
|
||||||
#include <Geode/utils/casts.hpp>
|
#include <Geode/utils/casts.hpp>
|
||||||
#include <Geode/utils/ranges.hpp>
|
#include <Geode/utils/ranges.hpp>
|
||||||
#include <Geode/utils/web.hpp>
|
#include <Geode/utils/web.hpp>
|
||||||
|
@ -30,9 +31,9 @@ static constexpr int const TAG_CONFIRM_UNINSTALL = 5;
|
||||||
static constexpr int const TAG_DELETE_SAVEDATA = 6;
|
static constexpr int const TAG_DELETE_SAVEDATA = 6;
|
||||||
static const CCSize LAYER_SIZE = { 440.f, 290.f };
|
static const CCSize LAYER_SIZE = { 440.f, 290.f };
|
||||||
|
|
||||||
bool ModInfoPopup::init(ModInfo const& info, ModListView* list) {
|
bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) {
|
||||||
m_noElasticity = true;
|
m_noElasticity = true;
|
||||||
m_list = list;
|
m_layer = list;
|
||||||
|
|
||||||
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
||||||
|
|
||||||
|
@ -274,7 +275,7 @@ void ModInfoPopup::onClose(CCObject* pSender) {
|
||||||
|
|
||||||
// LocalModInfoPopup
|
// LocalModInfoPopup
|
||||||
|
|
||||||
bool LocalModInfoPopup::init(Mod* mod, ModListView* list) {
|
bool LocalModInfoPopup::init(Mod* mod, ModListLayer* list) {
|
||||||
m_mod = mod;
|
m_mod = mod;
|
||||||
|
|
||||||
if (!ModInfoPopup::init(mod->getModInfo(), list))
|
if (!ModInfoPopup::init(mod->getModInfo(), list))
|
||||||
|
@ -458,7 +459,7 @@ void LocalModInfoPopup::onEnableMod(CCObject* sender) {
|
||||||
"OK"
|
"OK"
|
||||||
)
|
)
|
||||||
->show();
|
->show();
|
||||||
if (m_list) m_list->updateAllStates(nullptr);
|
if (m_layer) m_layer->updateAllStates(nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (as<CCMenuItemToggler*>(sender)->isToggled()) {
|
if (as<CCMenuItemToggler*>(sender)->isToggled()) {
|
||||||
|
@ -479,7 +480,7 @@ void LocalModInfoPopup::onEnableMod(CCObject* sender) {
|
||||||
)->show();
|
)->show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_list) m_list->updateAllStates(nullptr);
|
if (m_layer) m_layer->updateAllStates(nullptr);
|
||||||
as<CCMenuItemToggler*>(sender)->toggle(m_mod->isEnabled());
|
as<CCMenuItemToggler*>(sender)->toggle(m_mod->isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,7 +531,7 @@ void LocalModInfoPopup::FLAlert_Clicked(FLAlertLayer* layer, bool btn2) {
|
||||||
)->show();
|
)->show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_list) m_list->refreshList();
|
if (m_layer) m_layer->reloadList();
|
||||||
this->onClose(nullptr);
|
this->onClose(nullptr);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
@ -556,7 +557,7 @@ void LocalModInfoPopup::uninstall() {
|
||||||
layer->show();
|
layer->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalModInfoPopup* LocalModInfoPopup::create(Mod* mod, ModListView* list) {
|
LocalModInfoPopup* LocalModInfoPopup::create(Mod* mod, ModListLayer* list) {
|
||||||
auto ret = new LocalModInfoPopup;
|
auto ret = new LocalModInfoPopup;
|
||||||
if (ret && ret->init(mod, list)) {
|
if (ret && ret->init(mod, list)) {
|
||||||
ret->autorelease();
|
ret->autorelease();
|
||||||
|
@ -568,7 +569,7 @@ LocalModInfoPopup* LocalModInfoPopup::create(Mod* mod, ModListView* list) {
|
||||||
|
|
||||||
// IndexItemInfoPopup
|
// IndexItemInfoPopup
|
||||||
|
|
||||||
bool IndexItemInfoPopup::init(IndexItemHandle item, ModListView* list) {
|
bool IndexItemInfoPopup::init(IndexItemHandle item, ModListLayer* list) {
|
||||||
m_item = item;
|
m_item = item;
|
||||||
|
|
||||||
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
||||||
|
@ -608,7 +609,7 @@ ModInfo IndexItemInfoPopup::getModInfo() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexItemInfoPopup* IndexItemInfoPopup::create(
|
IndexItemInfoPopup* IndexItemInfoPopup::create(
|
||||||
IndexItemHandle item, ModListView* list
|
IndexItemHandle item, ModListLayer* list
|
||||||
) {
|
) {
|
||||||
auto ret = new IndexItemInfoPopup;
|
auto ret = new IndexItemInfoPopup;
|
||||||
if (ret && ret->init(item, list)) {
|
if (ret && ret->init(item, list)) {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
USE_GEODE_NAMESPACE();
|
USE_GEODE_NAMESPACE();
|
||||||
|
|
||||||
class ModListView;
|
class ModListLayer;
|
||||||
class ModObject;
|
class ModObject;
|
||||||
|
|
||||||
class DownloadStatusNode : public CCNode {
|
class DownloadStatusNode : public CCNode {
|
||||||
|
@ -28,7 +28,7 @@ public:
|
||||||
|
|
||||||
class ModInfoPopup : public FLAlertLayer {
|
class ModInfoPopup : public FLAlertLayer {
|
||||||
protected:
|
protected:
|
||||||
ModListView* m_list = nullptr;
|
ModListLayer* m_layer = nullptr;
|
||||||
DownloadStatusNode* m_installStatus = nullptr;
|
DownloadStatusNode* m_installStatus = nullptr;
|
||||||
IconButtonSprite* m_installBtnSpr;
|
IconButtonSprite* m_installBtnSpr;
|
||||||
CCMenuItemSpriteExtra* m_installBtn;
|
CCMenuItemSpriteExtra* m_installBtn;
|
||||||
|
@ -43,7 +43,7 @@ protected:
|
||||||
void onSupport(CCObject*);
|
void onSupport(CCObject*);
|
||||||
void onInfo(CCObject*);
|
void onInfo(CCObject*);
|
||||||
|
|
||||||
bool init(ModInfo const& info, ModListView* list);
|
bool init(ModInfo const& info, ModListLayer* list);
|
||||||
|
|
||||||
void keyDown(cocos2d::enumKeyCodes) override;
|
void keyDown(cocos2d::enumKeyCodes) override;
|
||||||
void onClose(cocos2d::CCObject*);
|
void onClose(cocos2d::CCObject*);
|
||||||
|
@ -56,7 +56,7 @@ class LocalModInfoPopup : public ModInfoPopup, public FLAlertLayerProtocol {
|
||||||
protected:
|
protected:
|
||||||
Mod* m_mod;
|
Mod* m_mod;
|
||||||
|
|
||||||
bool init(Mod* mod, ModListView* list);
|
bool init(Mod* mod, ModListLayer* list);
|
||||||
|
|
||||||
void onIssues(CCObject*);
|
void onIssues(CCObject*);
|
||||||
void onSettings(CCObject*);
|
void onSettings(CCObject*);
|
||||||
|
@ -74,18 +74,18 @@ protected:
|
||||||
ModInfo getModInfo() const override;
|
ModInfo getModInfo() const override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static LocalModInfoPopup* create(Mod* mod, ModListView* list);
|
static LocalModInfoPopup* create(Mod* mod, ModListLayer* list);
|
||||||
};
|
};
|
||||||
|
|
||||||
class IndexItemInfoPopup : public ModInfoPopup {
|
class IndexItemInfoPopup : public ModInfoPopup {
|
||||||
protected:
|
protected:
|
||||||
IndexItemHandle m_item;
|
IndexItemHandle m_item;
|
||||||
|
|
||||||
bool init(IndexItemHandle item, ModListView* list);
|
bool init(IndexItemHandle item, ModListLayer* list);
|
||||||
|
|
||||||
CCNode* createLogo(CCSize const& size) override;
|
CCNode* createLogo(CCSize const& size) override;
|
||||||
ModInfo getModInfo() const override;
|
ModInfo getModInfo() const override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static IndexItemInfoPopup* create(IndexItemHandle item, ModListView* list);
|
static IndexItemInfoPopup* create(IndexItemHandle item, ModListLayer* list);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#include "CategoryNode.hpp"
|
#include "TagNode.hpp"
|
||||||
|
#include <Geode/utils/general.hpp>
|
||||||
|
#include <cocos-ext.h>
|
||||||
|
#include <Geode/loader/Mod.hpp>
|
||||||
|
|
||||||
ccColor3B CategoryNode::categoryToColor(std::string const& category) {
|
ccColor3B TagNode::categoryToColor(std::string const& category) {
|
||||||
// all we need is to convert a string into some number
|
// all we need is to convert a string into some number
|
||||||
// between 0 and 360 and for that number to always be the
|
// between 0 and 360 and for that number to always be the
|
||||||
// same for the same string
|
// same for the same string
|
||||||
|
@ -17,8 +20,8 @@ ccColor3B CategoryNode::categoryToColor(std::string const& category) {
|
||||||
static_cast<GLubyte>(rgb.b * 255) };
|
static_cast<GLubyte>(rgb.b * 255) };
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CategoryNode::init(std::string const& category, CategoryNodeStyle style) {
|
bool TagNode::init(std::string const& category, TagNodeStyle style) {
|
||||||
if (style == CategoryNodeStyle::Dot) {
|
if (style == TagNodeStyle::Dot) {
|
||||||
auto dot = CCSprite::createWithSpriteFrameName("category-dot.png"_spr);
|
auto dot = CCSprite::createWithSpriteFrameName("category-dot.png"_spr);
|
||||||
dot->setColor(categoryToColor(category));
|
dot->setColor(categoryToColor(category));
|
||||||
dot->setPosition({ 20.f, 20.f });
|
dot->setPosition({ 20.f, 20.f });
|
||||||
|
@ -52,8 +55,8 @@ bool CategoryNode::init(std::string const& category, CategoryNodeStyle style) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CategoryNode* CategoryNode::create(std::string const& category, CategoryNodeStyle style) {
|
TagNode* TagNode::create(std::string const& category, TagNodeStyle style) {
|
||||||
auto ret = new CategoryNode();
|
auto ret = new TagNode();
|
||||||
if (ret && ret->init(category, style)) {
|
if (ret && ret->init(category, style)) {
|
||||||
ret->autorelease();
|
ret->autorelease();
|
||||||
return ret;
|
return ret;
|
22
loader/src/ui/internal/info/TagNode.hpp
Normal file
22
loader/src/ui/internal/info/TagNode.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cocos2d.h>
|
||||||
|
|
||||||
|
USE_GEODE_NAMESPACE();
|
||||||
|
|
||||||
|
enum class TagNodeStyle {
|
||||||
|
Tag,
|
||||||
|
Dot,
|
||||||
|
};
|
||||||
|
|
||||||
|
class TagNode : public CCNode {
|
||||||
|
protected:
|
||||||
|
bool init(std::string const& category, TagNodeStyle style);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static TagNode* create(
|
||||||
|
std::string const& category, TagNodeStyle style = TagNodeStyle::Tag
|
||||||
|
);
|
||||||
|
|
||||||
|
static ccColor3B categoryToColor(std::string const& category);
|
||||||
|
};
|
|
@ -1,5 +1,5 @@
|
||||||
#include "ModListCell.hpp"
|
#include "ModListCell.hpp"
|
||||||
#include "ModListView.hpp"
|
#include "ModListLayer.hpp"
|
||||||
#include "../info/ModInfoPopup.hpp"
|
#include "../info/ModInfoPopup.hpp"
|
||||||
#include <Geode/binding/StatsCell.hpp>
|
#include <Geode/binding/StatsCell.hpp>
|
||||||
#include <Geode/binding/FLAlertLayer.hpp>
|
#include <Geode/binding/FLAlertLayer.hpp>
|
||||||
|
@ -8,6 +8,7 @@
|
||||||
#include <Geode/binding/CCMenuItemToggler.hpp>
|
#include <Geode/binding/CCMenuItemToggler.hpp>
|
||||||
#include <Geode/ui/GeodeUI.hpp>
|
#include <Geode/ui/GeodeUI.hpp>
|
||||||
#include <InternalLoader.hpp>
|
#include <InternalLoader.hpp>
|
||||||
|
#include "../info/TagNode.hpp"
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
static bool tryOrAlert(Result<T> const& res, char const* title) {
|
static bool tryOrAlert(Result<T> const& res, char const* title) {
|
||||||
|
@ -17,45 +18,46 @@ static bool tryOrAlert(Result<T> const& res, char const* title) {
|
||||||
return res.isOk();
|
return res.isOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
ModListCell::ModListCell(char const* name, CCSize const& size)
|
|
||||||
: TableViewCell(name, size.width, size.height) {}
|
|
||||||
|
|
||||||
void ModListCell::draw() {
|
void ModListCell::draw() {
|
||||||
reinterpret_cast<StatsCell*>(this)->StatsCell::draw();
|
reinterpret_cast<StatsCell*>(this)->StatsCell::draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModListCell::setupInfo(ModInfo const& info, bool spaceForCategories) {
|
float ModListCell::getLogoSize() const {
|
||||||
m_mainLayer->setVisible(true);
|
return m_height / 1.5f;
|
||||||
m_backgroundLayer->setOpacity(255);
|
}
|
||||||
|
|
||||||
|
void ModListCell::setupInfo(ModInfo const& info, bool spaceForTags) {
|
||||||
m_menu = CCMenu::create();
|
m_menu = CCMenu::create();
|
||||||
m_menu->setPosition(m_width - 40.f, m_height / 2);
|
m_menu->setPosition(m_width - 40.f, m_height / 2);
|
||||||
m_mainLayer->addChild(m_menu);
|
this->addChild(m_menu);
|
||||||
|
|
||||||
auto logoSize = m_height / 1.5f;
|
auto logoSize = this->getLogoSize();
|
||||||
|
|
||||||
auto logoSpr = this->createLogo({ logoSize, logoSize });
|
auto logoSpr = this->createLogo({ logoSize, logoSize });
|
||||||
logoSpr->setPosition({ logoSize / 2 + 12.f, m_height / 2 });
|
logoSpr->setPosition({ logoSize / 2 + 12.f, m_height / 2 });
|
||||||
m_mainLayer->addChild(logoSpr);
|
this->addChild(logoSpr);
|
||||||
|
|
||||||
bool hasDesc =
|
bool hasDesc =
|
||||||
m_display == ModListDisplay::Expanded &&
|
m_layer->getDisplay() == ModListDisplay::Expanded &&
|
||||||
info.m_description.has_value();
|
info.m_description.has_value();
|
||||||
|
|
||||||
auto titleLabel = CCLabelBMFont::create(info.m_name.c_str(), "bigFont.fnt");
|
auto titleLabel = CCLabelBMFont::create(info.m_name.c_str(), "bigFont.fnt");
|
||||||
titleLabel->setAnchorPoint({ .0f, .5f });
|
titleLabel->setAnchorPoint({ .0f, .5f });
|
||||||
titleLabel->setPositionX(m_height / 2 + logoSize / 2 + 13.f);
|
titleLabel->setPositionX(m_height / 2 + logoSize / 2 + 13.f);
|
||||||
if (hasDesc && spaceForCategories) {
|
if (hasDesc && spaceForTags) {
|
||||||
titleLabel->setPositionY(m_height / 2 + 20.f);
|
titleLabel->setPositionY(m_height / 2 + 20.f);
|
||||||
}
|
}
|
||||||
else if (hasDesc || spaceForCategories) {
|
else if (spaceForTags) {
|
||||||
|
titleLabel->setPositionY(m_height / 2 + 12.f);
|
||||||
|
}
|
||||||
|
else if (hasDesc) {
|
||||||
titleLabel->setPositionY(m_height / 2 + 15.f);
|
titleLabel->setPositionY(m_height / 2 + 15.f);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
titleLabel->setPositionY(m_height / 2 + 7.f);
|
titleLabel->setPositionY(m_height / 2 + 7.f);
|
||||||
}
|
}
|
||||||
titleLabel->limitLabelWidth(m_width / 2 - 40.f, .5f, .1f);
|
titleLabel->limitLabelWidth(m_width / 2 - 40.f, .5f, .1f);
|
||||||
m_mainLayer->addChild(titleLabel);
|
this->addChild(titleLabel);
|
||||||
|
|
||||||
auto versionLabel = CCLabelBMFont::create(info.m_version.toString().c_str(), "bigFont.fnt");
|
auto versionLabel = CCLabelBMFont::create(info.m_version.toString().c_str(), "bigFont.fnt");
|
||||||
versionLabel->setAnchorPoint({ .0f, .5f });
|
versionLabel->setAnchorPoint({ .0f, .5f });
|
||||||
|
@ -65,23 +67,23 @@ void ModListCell::setupInfo(ModInfo const& info, bool spaceForCategories) {
|
||||||
titleLabel->getPositionY() - 1.f
|
titleLabel->getPositionY() - 1.f
|
||||||
);
|
);
|
||||||
versionLabel->setColor({ 0, 255, 0 });
|
versionLabel->setColor({ 0, 255, 0 });
|
||||||
m_mainLayer->addChild(versionLabel);
|
this->addChild(versionLabel);
|
||||||
|
|
||||||
auto creatorStr = "by " + info.m_developer;
|
auto creatorStr = "by " + info.m_developer;
|
||||||
auto creatorLabel = CCLabelBMFont::create(creatorStr.c_str(), "goldFont.fnt");
|
auto creatorLabel = CCLabelBMFont::create(creatorStr.c_str(), "goldFont.fnt");
|
||||||
creatorLabel->setAnchorPoint({ .0f, .5f });
|
creatorLabel->setAnchorPoint({ .0f, .5f });
|
||||||
creatorLabel->setScale(.43f);
|
creatorLabel->setScale(.43f);
|
||||||
creatorLabel->setPositionX(m_height / 2 + logoSize / 2 + 13.f);
|
creatorLabel->setPositionX(m_height / 2 + logoSize / 2 + 13.f);
|
||||||
if (hasDesc && spaceForCategories) {
|
if (hasDesc && spaceForTags) {
|
||||||
creatorLabel->setPositionY(m_height / 2 + 7.5f);
|
creatorLabel->setPositionY(m_height / 2 + 7.5f);
|
||||||
}
|
}
|
||||||
else if (hasDesc || spaceForCategories) {
|
else if (hasDesc || spaceForTags) {
|
||||||
creatorLabel->setPositionY(m_height / 2);
|
creatorLabel->setPositionY(m_height / 2);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
creatorLabel->setPositionY(m_height / 2 - 7.f);
|
creatorLabel->setPositionY(m_height / 2 - 7.f);
|
||||||
}
|
}
|
||||||
m_mainLayer->addChild(creatorLabel);
|
this->addChild(creatorLabel);
|
||||||
|
|
||||||
if (hasDesc) {
|
if (hasDesc) {
|
||||||
auto descBG = CCScale9Sprite::create("square02b_001.png", { 0.0f, 0.0f, 80.0f, 80.0f });
|
auto descBG = CCScale9Sprite::create("square02b_001.png", { 0.0f, 0.0f, 80.0f, 80.0f });
|
||||||
|
@ -90,48 +92,41 @@ void ModListCell::setupInfo(ModInfo const& info, bool spaceForCategories) {
|
||||||
descBG->setContentSize({ m_width * 2, 60.f });
|
descBG->setContentSize({ m_width * 2, 60.f });
|
||||||
descBG->setAnchorPoint({ .0f, .5f });
|
descBG->setAnchorPoint({ .0f, .5f });
|
||||||
descBG->setPositionX(m_height / 2 + logoSize / 2 + 13.f);
|
descBG->setPositionX(m_height / 2 + logoSize / 2 + 13.f);
|
||||||
if (spaceForCategories) {
|
if (spaceForTags) {
|
||||||
descBG->setPositionY(m_height / 2 - 7.5f);
|
descBG->setPositionY(m_height / 2 - 7.5f);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
descBG->setPositionY(m_height / 2 - 17.f);
|
descBG->setPositionY(m_height / 2 - 17.f);
|
||||||
}
|
}
|
||||||
descBG->setScale(.25f);
|
descBG->setScale(.25f);
|
||||||
m_mainLayer->addChild(descBG);
|
this->addChild(descBG);
|
||||||
|
|
||||||
auto descText = CCLabelBMFont::create(info.m_description.value().c_str(), "chatFont.fnt");
|
m_description = CCLabelBMFont::create(info.m_description.value().c_str(), "chatFont.fnt");
|
||||||
descText->setAnchorPoint({ .0f, .5f });
|
m_description->setAnchorPoint({ .0f, .5f });
|
||||||
descText->setPosition(m_height / 2 + logoSize / 2 + 18.f, descBG->getPositionY());
|
m_description->setPosition(m_height / 2 + logoSize / 2 + 18.f, descBG->getPositionY());
|
||||||
descText->limitLabelWidth(m_width / 2 - 10.f, .5f, .1f);
|
m_description->limitLabelWidth(m_width / 2 - 10.f, .5f, .1f);
|
||||||
m_mainLayer->addChild(descText);
|
this->addChild(m_description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModListCell::updateBGColor(int index) {
|
bool ModListCell::init(ModListLayer* list, CCSize const& size) {
|
||||||
if (index % 2) {
|
m_width = size.width;
|
||||||
m_backgroundLayer->setColor(ccc3(0xc2, 0x72, 0x3e));
|
m_height = size.height;
|
||||||
}
|
m_layer = list;
|
||||||
else m_backgroundLayer->setColor(ccc3(0xa1, 0x58, 0x2c));
|
this->setContentSize(size);
|
||||||
m_backgroundLayer->setOpacity(0xff);
|
this->setID("mod-list-cell");
|
||||||
}
|
|
||||||
|
|
||||||
bool ModListCell::init(ModListView* list, ModListDisplay display) {
|
|
||||||
m_list = list;
|
|
||||||
m_display = display;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModCell
|
// ModCell
|
||||||
|
|
||||||
ModCell::ModCell(const char* name, CCSize const& size)
|
|
||||||
: ModListCell(name, size) {}
|
|
||||||
|
|
||||||
ModCell* ModCell::create(
|
ModCell* ModCell::create(
|
||||||
ModListView* list, ModListDisplay display,
|
Mod* mod,
|
||||||
const char* key, CCSize const& size
|
ModListLayer* list,
|
||||||
|
CCSize const& size
|
||||||
) {
|
) {
|
||||||
auto ret = new ModCell(key, size);
|
auto ret = new ModCell();
|
||||||
if (ret && ret->init(list, display)) {
|
if (ret && ret->init(mod, list, size)) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
CC_SAFE_DELETE(ret);
|
CC_SAFE_DELETE(ret);
|
||||||
|
@ -148,7 +143,7 @@ void ModCell::onEnable(CCObject* sender) {
|
||||||
"need to <cg>restart</c> the game to have it fully unloaded.",
|
"need to <cg>restart</c> the game to have it fully unloaded.",
|
||||||
"OK"
|
"OK"
|
||||||
)->show();
|
)->show();
|
||||||
m_list->updateAllStates(this);
|
m_layer->updateAllStates(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!as<CCMenuItemToggler*>(sender)->isToggled()) {
|
if (!as<CCMenuItemToggler*>(sender)->isToggled()) {
|
||||||
|
@ -157,7 +152,7 @@ void ModCell::onEnable(CCObject* sender) {
|
||||||
else {
|
else {
|
||||||
tryOrAlert(m_mod->disable(), "Error disabling mod");
|
tryOrAlert(m_mod->disable(), "Error disabling mod");
|
||||||
}
|
}
|
||||||
m_list->updateAllStates(this);
|
m_layer->updateAllStates(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModCell::onUnresolvedInfo(CCObject*) {
|
void ModCell::onUnresolvedInfo(CCObject*) {
|
||||||
|
@ -176,7 +171,7 @@ void ModCell::onUnresolvedInfo(CCObject*) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModCell::onInfo(CCObject*) {
|
void ModCell::onInfo(CCObject*) {
|
||||||
LocalModInfoPopup::create(m_mod, m_list)->show();
|
LocalModInfoPopup::create(m_mod, m_layer)->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModCell::updateState() {
|
void ModCell::updateState() {
|
||||||
|
@ -192,7 +187,14 @@ void ModCell::updateState() {
|
||||||
m_unresolvedExMark->setVisible(unresolved);
|
m_unresolvedExMark->setVisible(unresolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModCell::loadFromMod(Mod* mod) {
|
bool ModCell::init(
|
||||||
|
Mod* mod,
|
||||||
|
ModListLayer* list,
|
||||||
|
CCSize const& size
|
||||||
|
) {
|
||||||
|
if (!ModListCell::init(list, size))
|
||||||
|
return false;
|
||||||
|
|
||||||
m_mod = mod;
|
m_mod = mod;
|
||||||
|
|
||||||
this->setupInfo(mod->getModInfo(), false);
|
this->setupInfo(mod->getModInfo(), false);
|
||||||
|
@ -238,6 +240,8 @@ void ModCell::loadFromMod(Mod* mod) {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
this->updateState();
|
this->updateState();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CCNode* ModCell::createLogo(CCSize const& size) {
|
CCNode* ModCell::createLogo(CCSize const& size) {
|
||||||
|
@ -246,29 +250,34 @@ CCNode* ModCell::createLogo(CCSize const& size) {
|
||||||
|
|
||||||
// IndexItemCell
|
// IndexItemCell
|
||||||
|
|
||||||
IndexItemCell::IndexItemCell(char const* name, CCSize const& size)
|
|
||||||
: ModListCell(name, size) {}
|
|
||||||
|
|
||||||
void IndexItemCell::onInfo(CCObject*) {
|
void IndexItemCell::onInfo(CCObject*) {
|
||||||
IndexItemInfoPopup::create(m_item, m_list)->show();
|
IndexItemInfoPopup::create(m_item, m_layer)->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexItemCell* IndexItemCell::create(
|
IndexItemCell* IndexItemCell::create(
|
||||||
ModListView* list, ModListDisplay display,
|
IndexItemHandle item,
|
||||||
const char* key, CCSize const& size
|
ModListLayer* list,
|
||||||
|
CCSize const& size
|
||||||
) {
|
) {
|
||||||
auto ret = new IndexItemCell(key, size);
|
auto ret = new IndexItemCell();
|
||||||
if (ret && ret->init(list, display)) {
|
if (ret && ret->init(item, list, size)) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
CC_SAFE_DELETE(ret);
|
CC_SAFE_DELETE(ret);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexItemCell::loadFromItem(IndexItemHandle item) {
|
bool IndexItemCell::init(
|
||||||
|
IndexItemHandle item,
|
||||||
|
ModListLayer* list,
|
||||||
|
CCSize const& size
|
||||||
|
) {
|
||||||
|
if (!ModListCell::init(list, size))
|
||||||
|
return false;
|
||||||
|
|
||||||
m_item = item;
|
m_item = item;
|
||||||
|
|
||||||
this->setupInfo(item->info, true);
|
this->setupInfo(item->info, item->tags.size());
|
||||||
|
|
||||||
auto viewSpr = ButtonSprite::create(
|
auto viewSpr = ButtonSprite::create(
|
||||||
"View", "bigFont.fnt", "GJ_button_01.png", .8f
|
"View", "bigFont.fnt", "GJ_button_01.png", .8f
|
||||||
|
@ -280,26 +289,28 @@ void IndexItemCell::loadFromItem(IndexItemHandle item) {
|
||||||
);
|
);
|
||||||
m_menu->addChild(viewBtn);
|
m_menu->addChild(viewBtn);
|
||||||
|
|
||||||
// if (hasCategories) {
|
if (item->tags.size()) {
|
||||||
// float x = m_height / 2 + logoSize / 2 + 13.f;
|
float x = m_height / 2 + this->getLogoSize() / 2 + 13.f;
|
||||||
// for (auto& category : modobj->m_index.m_categories) {
|
for (auto& category : item->tags) {
|
||||||
// auto node = CategoryNode::create(category);
|
auto node = TagNode::create(category);
|
||||||
// node->setAnchorPoint({ .0f, .5f });
|
node->setAnchorPoint({ .0f, .5f });
|
||||||
// node->setPositionX(x);
|
node->setPositionX(x);
|
||||||
// node->setScale(.3f);
|
node->setScale(.3f);
|
||||||
// if (hasDesc) {
|
if (m_description) {
|
||||||
// node->setPositionY(m_height / 2 - 23.f);
|
node->setPositionY(m_height / 2 - 23.f);
|
||||||
// }
|
}
|
||||||
// else {
|
else {
|
||||||
// node->setPositionY(m_height / 2 - 17.f);
|
node->setPositionY(m_height / 2 - 12.f);
|
||||||
// }
|
}
|
||||||
// m_mainLayer->addChild(node);
|
this->addChild(node);
|
||||||
|
|
||||||
// x += node->getScaledContentSize().width + 5.f;
|
x += node->getScaledContentSize().width + 5.f;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
this->updateState();
|
this->updateState();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexItemCell::updateState() {}
|
void IndexItemCell::updateState() {}
|
||||||
|
@ -310,9 +321,6 @@ CCNode* IndexItemCell::createLogo(CCSize const& size) {
|
||||||
|
|
||||||
// InvalidGeodeFileCell
|
// InvalidGeodeFileCell
|
||||||
|
|
||||||
InvalidGeodeFileCell::InvalidGeodeFileCell(const char* name, CCSize const& size)
|
|
||||||
: ModListCell(name, size) {}
|
|
||||||
|
|
||||||
void InvalidGeodeFileCell::onInfo(CCObject*) {
|
void InvalidGeodeFileCell::onInfo(CCObject*) {
|
||||||
FLAlertLayer::create(
|
FLAlertLayer::create(
|
||||||
this, "Error Info",
|
this, "Error Info",
|
||||||
|
@ -345,36 +353,29 @@ void InvalidGeodeFileCell::FLAlert_Clicked(FLAlertLayer*, bool btn2) {
|
||||||
)->show();
|
)->show();
|
||||||
}
|
}
|
||||||
(void)Loader::get()->refreshModsList();
|
(void)Loader::get()->refreshModsList();
|
||||||
m_list->refreshList();
|
m_layer->reloadList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InvalidGeodeFileCell* InvalidGeodeFileCell::create(
|
bool InvalidGeodeFileCell::init(
|
||||||
ModListView* list, ModListDisplay display,
|
InvalidGeodeFile const& info,
|
||||||
char const* key, CCSize const& size
|
ModListLayer* list,
|
||||||
|
CCSize const& size
|
||||||
) {
|
) {
|
||||||
auto ret = new InvalidGeodeFileCell(key, size);
|
if (!ModListCell::init(list, size))
|
||||||
if (ret && ret->init(list, display)) {
|
return false;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
CC_SAFE_DELETE(ret);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InvalidGeodeFileCell::loadFromInfo(InvalidGeodeFile const& info) {
|
|
||||||
m_info = info;
|
m_info = info;
|
||||||
|
|
||||||
m_mainLayer->setVisible(true);
|
|
||||||
|
|
||||||
auto menu = CCMenu::create();
|
auto menu = CCMenu::create();
|
||||||
menu->setPosition(m_width - m_height, m_height / 2);
|
menu->setPosition(m_width - m_height, m_height / 2);
|
||||||
m_mainLayer->addChild(menu);
|
this->addChild(menu);
|
||||||
|
|
||||||
auto titleLabel = CCLabelBMFont::create("Failed to Load", "bigFont.fnt");
|
auto titleLabel = CCLabelBMFont::create("Failed to Load", "bigFont.fnt");
|
||||||
titleLabel->setAnchorPoint({ .0f, .5f });
|
titleLabel->setAnchorPoint({ .0f, .5f });
|
||||||
titleLabel->setScale(.5f);
|
titleLabel->setScale(.5f);
|
||||||
titleLabel->setPosition(m_height / 2, m_height / 2 + 7.f);
|
titleLabel->setPosition(m_height / 2, m_height / 2 + 7.f);
|
||||||
m_mainLayer->addChild(titleLabel);
|
this->addChild(titleLabel);
|
||||||
|
|
||||||
auto pathLabel = CCLabelBMFont::create(
|
auto pathLabel = CCLabelBMFont::create(
|
||||||
m_info.m_path.string().c_str(),
|
m_info.m_path.string().c_str(),
|
||||||
|
@ -384,7 +385,7 @@ void InvalidGeodeFileCell::loadFromInfo(InvalidGeodeFile const& info) {
|
||||||
pathLabel->setScale(.43f);
|
pathLabel->setScale(.43f);
|
||||||
pathLabel->setPosition(m_height / 2, m_height / 2 - 7.f);
|
pathLabel->setPosition(m_height / 2, m_height / 2 - 7.f);
|
||||||
pathLabel->setColor({ 255, 255, 0 });
|
pathLabel->setColor({ 255, 255, 0 });
|
||||||
m_mainLayer->addChild(pathLabel);
|
this->addChild(pathLabel);
|
||||||
|
|
||||||
auto whySpr = ButtonSprite::create(
|
auto whySpr = ButtonSprite::create(
|
||||||
"Info", 0, 0, "bigFont.fnt", "GJ_button_01.png", 0, .8f
|
"Info", 0, 0, "bigFont.fnt", "GJ_button_01.png", 0, .8f
|
||||||
|
@ -395,6 +396,22 @@ void InvalidGeodeFileCell::loadFromInfo(InvalidGeodeFile const& info) {
|
||||||
whySpr, this, menu_selector(InvalidGeodeFileCell::onInfo)
|
whySpr, this, menu_selector(InvalidGeodeFileCell::onInfo)
|
||||||
);
|
);
|
||||||
menu->addChild(viewBtn);
|
menu->addChild(viewBtn);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
InvalidGeodeFileCell* InvalidGeodeFileCell::create(
|
||||||
|
InvalidGeodeFile const& file,
|
||||||
|
ModListLayer* list,
|
||||||
|
CCSize const& size
|
||||||
|
) {
|
||||||
|
auto ret = new InvalidGeodeFileCell();
|
||||||
|
if (ret && ret->init(file, list, size)) {
|
||||||
|
ret->autorelease();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
CC_SAFE_DELETE(ret);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InvalidGeodeFileCell::updateState() {}
|
void InvalidGeodeFileCell::updateState() {}
|
||||||
|
|
|
@ -8,33 +8,45 @@
|
||||||
|
|
||||||
USE_GEODE_NAMESPACE();
|
USE_GEODE_NAMESPACE();
|
||||||
|
|
||||||
class ModListView;
|
class ModListLayer;
|
||||||
enum class ModListDisplay;
|
enum class ModListDisplay;
|
||||||
|
|
||||||
class ModListCell : public TableViewCell {
|
/**
|
||||||
|
* Base class for mod list items
|
||||||
|
*/
|
||||||
|
class ModListCell : public CCLayer {
|
||||||
protected:
|
protected:
|
||||||
ModListView* m_list;
|
float m_width;
|
||||||
|
float m_height;
|
||||||
|
ModListLayer* m_layer;
|
||||||
CCMenu* m_menu;
|
CCMenu* m_menu;
|
||||||
|
CCLabelBMFont* m_description;
|
||||||
CCMenuItemToggler* m_enableToggle = nullptr;
|
CCMenuItemToggler* m_enableToggle = nullptr;
|
||||||
CCMenuItemSpriteExtra* m_unresolvedExMark;
|
CCMenuItemSpriteExtra* m_unresolvedExMark;
|
||||||
ModListDisplay m_display;
|
|
||||||
|
|
||||||
ModListCell(char const* name, CCSize const& size);
|
bool init(ModListLayer* list, CCSize const& size);
|
||||||
bool init(ModListView* list, ModListDisplay display);
|
void setupInfo(ModInfo const& info, bool spaceForTags);
|
||||||
void setupInfo(ModInfo const& info, bool spaceForCategories);
|
|
||||||
void draw() override;
|
void draw() override;
|
||||||
|
|
||||||
|
float getLogoSize() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void updateBGColor(int index);
|
|
||||||
virtual void updateState() = 0;
|
virtual void updateState() = 0;
|
||||||
virtual CCNode* createLogo(CCSize const& size) = 0;
|
virtual CCNode* createLogo(CCSize const& size) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mod list item for a mod
|
||||||
|
*/
|
||||||
class ModCell : public ModListCell {
|
class ModCell : public ModListCell {
|
||||||
protected:
|
protected:
|
||||||
Mod* m_mod;
|
Mod* m_mod;
|
||||||
|
|
||||||
ModCell(char const* name, CCSize const& size);
|
bool init(
|
||||||
|
Mod* mod,
|
||||||
|
ModListLayer* list,
|
||||||
|
CCSize const& size
|
||||||
|
);
|
||||||
|
|
||||||
void onInfo(CCObject*);
|
void onInfo(CCObject*);
|
||||||
void onEnable(CCObject*);
|
void onEnable(CCObject*);
|
||||||
|
@ -42,50 +54,64 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ModCell* create(
|
static ModCell* create(
|
||||||
ModListView* list, ModListDisplay display,
|
Mod* mod,
|
||||||
const char* key, CCSize const& size
|
ModListLayer* list,
|
||||||
|
CCSize const& size
|
||||||
);
|
);
|
||||||
|
|
||||||
void loadFromMod(Mod* mod);
|
|
||||||
void updateState() override;
|
void updateState() override;
|
||||||
CCNode* createLogo(CCSize const& size) override;
|
CCNode* createLogo(CCSize const& size) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mod list item for an index item
|
||||||
|
*/
|
||||||
class IndexItemCell : public ModListCell {
|
class IndexItemCell : public ModListCell {
|
||||||
protected:
|
protected:
|
||||||
IndexItemHandle m_item;
|
IndexItemHandle m_item;
|
||||||
|
|
||||||
IndexItemCell(char const* name, CCSize const& size);
|
bool init(
|
||||||
|
IndexItemHandle item,
|
||||||
|
ModListLayer* list,
|
||||||
|
CCSize const& size
|
||||||
|
);
|
||||||
|
|
||||||
void onInfo(CCObject*);
|
void onInfo(CCObject*);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static IndexItemCell* create(
|
static IndexItemCell* create(
|
||||||
ModListView* list, ModListDisplay display,
|
IndexItemHandle item,
|
||||||
const char* key, CCSize const& size
|
ModListLayer* list,
|
||||||
|
CCSize const& size
|
||||||
);
|
);
|
||||||
|
|
||||||
void loadFromItem(IndexItemHandle item);
|
|
||||||
void updateState() override;
|
void updateState() override;
|
||||||
CCNode* createLogo(CCSize const& size) override;
|
CCNode* createLogo(CCSize const& size) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mod list item for an invalid Geode package
|
||||||
|
*/
|
||||||
class InvalidGeodeFileCell : public ModListCell, public FLAlertLayerProtocol {
|
class InvalidGeodeFileCell : public ModListCell, public FLAlertLayerProtocol {
|
||||||
protected:
|
protected:
|
||||||
InvalidGeodeFile m_info;
|
InvalidGeodeFile m_info;
|
||||||
|
|
||||||
InvalidGeodeFileCell(char const* name, CCSize const& size);
|
bool init(
|
||||||
|
InvalidGeodeFile const& file,
|
||||||
|
ModListLayer* list,
|
||||||
|
CCSize const& size
|
||||||
|
);
|
||||||
|
|
||||||
void onInfo(CCObject*);
|
void onInfo(CCObject*);
|
||||||
void FLAlert_Clicked(FLAlertLayer*, bool btn2) override;
|
void FLAlert_Clicked(FLAlertLayer*, bool btn2) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static InvalidGeodeFileCell* create(
|
static InvalidGeodeFileCell* create(
|
||||||
ModListView* list, ModListDisplay display,
|
InvalidGeodeFile const& file,
|
||||||
const char* key, CCSize const& size
|
ModListLayer* list,
|
||||||
|
CCSize const& size
|
||||||
);
|
);
|
||||||
|
|
||||||
void loadFromInfo(InvalidGeodeFile const& file);
|
|
||||||
void updateState() override;
|
void updateState() override;
|
||||||
CCNode* createLogo(CCSize const& size) override;
|
CCNode* createLogo(CCSize const& size) override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "ModListLayer.hpp"
|
#include "ModListLayer.hpp"
|
||||||
|
#include "ModListCell.hpp"
|
||||||
#include "SearchFilterPopup.hpp"
|
#include "SearchFilterPopup.hpp"
|
||||||
|
|
||||||
#include <Geode/binding/ButtonSprite.hpp>
|
#include <Geode/binding/ButtonSprite.hpp>
|
||||||
|
@ -14,11 +14,42 @@
|
||||||
#include <Geode/ui/Notification.hpp>
|
#include <Geode/ui/Notification.hpp>
|
||||||
#include <Geode/utils/casts.hpp>
|
#include <Geode/utils/casts.hpp>
|
||||||
#include <Geode/loader/Dirs.hpp>
|
#include <Geode/loader/Dirs.hpp>
|
||||||
|
#include <Geode/loader/Loader.hpp>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <Geode/ui/ListView.hpp>
|
||||||
|
|
||||||
static ModListType g_tab = ModListType::Installed;
|
static ModListType g_tab = ModListType::Installed;
|
||||||
static ModListLayer* g_instance = nullptr;
|
static ModListLayer* g_instance = nullptr;
|
||||||
|
|
||||||
|
static void sortInstalledMods(std::vector<Mod*>& mods) {
|
||||||
|
if (!mods.size()) return;
|
||||||
|
// keep track of first object
|
||||||
|
size_t frontIndex = 0;
|
||||||
|
auto front = mods.front();
|
||||||
|
for (auto mod = mods.begin(); mod != mods.end(); mod++) {
|
||||||
|
// move mods with updates to front
|
||||||
|
if (auto item = Index::get()->getItem(*mod)) {
|
||||||
|
if (Index::get()->updateAvailable(item)) {
|
||||||
|
// swap first object and updatable mod
|
||||||
|
// if the updatable mod is the first object,
|
||||||
|
// nothing changes
|
||||||
|
std::rotate(mods.begin(), mod, mod + 1);
|
||||||
|
|
||||||
|
// get next object at front for next mod
|
||||||
|
// to sort
|
||||||
|
frontIndex++;
|
||||||
|
front = mods[frontIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<Mod*> sortedInstalledMods() {
|
||||||
|
auto mods = Loader::get()->getAllMods();
|
||||||
|
sortInstalledMods(mods);
|
||||||
|
return std::move(mods);
|
||||||
|
}
|
||||||
|
|
||||||
bool ModListLayer::init() {
|
bool ModListLayer::init() {
|
||||||
if (!CCLayer::init()) return false;
|
if (!CCLayer::init()) return false;
|
||||||
|
|
||||||
|
@ -216,11 +247,15 @@ void ModListLayer::reloadList() {
|
||||||
m_list->removeFromParent();
|
m_list->removeFromParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto items = ModListView::modsForType(g_tab);
|
auto items = this->createModCells(g_tab);
|
||||||
|
|
||||||
// create new list
|
// create new list
|
||||||
auto list = ModListView::create(items, m_display);
|
auto list = ListView::create(
|
||||||
list->setLayer(this);
|
items,
|
||||||
|
this->getCellSize().height,
|
||||||
|
this->getListSize().width,
|
||||||
|
this->getListSize().height
|
||||||
|
);
|
||||||
|
|
||||||
// set list status
|
// set list status
|
||||||
if (!items->count()) {
|
if (!items->count()) {
|
||||||
|
@ -306,6 +341,68 @@ void ModListLayer::reloadList() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CCSize ModListLayer::getListSize() const {
|
||||||
|
return { 358.f, 190.f };
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSize ModListLayer::getCellSize() const {
|
||||||
|
return {
|
||||||
|
getListSize().width,
|
||||||
|
m_display == ModListDisplay::Expanded ? 60.f : 40.f
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ModListDisplay ModListLayer::getDisplay() const {
|
||||||
|
return m_display;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCArray* ModListLayer::createModCells(ModListType type) {
|
||||||
|
auto mods = CCArray::create();
|
||||||
|
switch (type) {
|
||||||
|
default:
|
||||||
|
case ModListType::Installed: {
|
||||||
|
// failed mods first
|
||||||
|
for (auto const& mod : Loader::get()->getFailedMods()) {
|
||||||
|
mods->addObject(InvalidGeodeFileCell::create(mod, this, this->getCellSize()));
|
||||||
|
}
|
||||||
|
// internal geode representation always at the top
|
||||||
|
auto imod = Loader::getInternalMod();
|
||||||
|
mods->addObject(ModCell::create(imod, this, this->getCellSize()));
|
||||||
|
|
||||||
|
// then other mods
|
||||||
|
for (auto const& mod : sortedInstalledMods()) {
|
||||||
|
// if the mod is no longer installed nor
|
||||||
|
// loaded, it's as good as not existing
|
||||||
|
// (because it doesn't)
|
||||||
|
if (mod->isUninstalled() && !mod->isLoaded()) continue;
|
||||||
|
mods->addObject(ModCell::create(mod, this, this->getCellSize()));
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case ModListType::Download: {
|
||||||
|
for (auto const& item : Index::get()->getItems()) {
|
||||||
|
mods->addObject(IndexItemCell::create(item, this, this->getCellSize()));
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case ModListType::Featured: {
|
||||||
|
// todo: featured
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
return mods;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModListLayer::updateAllStates(ModListCell* toggled) {
|
||||||
|
for (auto cell : CCArrayExt<GenericListCell>(
|
||||||
|
m_list->m_listView->m_tableView->m_cellArray
|
||||||
|
)) {
|
||||||
|
auto node = static_cast<ModListCell*>(cell->getChildByID("mod-list-cell"));
|
||||||
|
if (toggled != node) {
|
||||||
|
node->updateState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ModListLayer::onCheckForUpdates(CCObject*) {
|
void ModListLayer::onCheckForUpdates(CCObject*) {
|
||||||
// store instance in a global so the
|
// store instance in a global so the
|
||||||
// layer stays in memory even if the
|
// layer stays in memory even if the
|
||||||
|
@ -331,10 +428,6 @@ void ModListLayer::onIndexUpdate(IndexUpdateEvent* event) {
|
||||||
}, event->status);
|
}, event->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModListLayer::textChanged(CCTextInputNode* input) {
|
|
||||||
this->reloadList();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModListLayer::onExit(CCObject*) {
|
void ModListLayer::onExit(CCObject*) {
|
||||||
CCDirector::sharedDirector()->replaceScene(
|
CCDirector::sharedDirector()->replaceScene(
|
||||||
CCTransitionFade::create(.5f, MenuLayer::scene(false))
|
CCTransitionFade::create(.5f, MenuLayer::scene(false))
|
||||||
|
@ -365,12 +458,6 @@ void ModListLayer::onResetSearch(CCObject*) {
|
||||||
m_searchInput->setString("");
|
m_searchInput->setString("");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModListLayer::keyDown(enumKeyCodes key) {
|
|
||||||
if (key == KEY_Escape) {
|
|
||||||
this->onExit(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModListLayer::onTab(CCObject* pSender) {
|
void ModListLayer::onTab(CCObject* pSender) {
|
||||||
if (pSender) {
|
if (pSender) {
|
||||||
g_tab = static_cast<ModListType>(pSender->getTag());
|
g_tab = static_cast<ModListType>(pSender->getTag());
|
||||||
|
@ -394,6 +481,16 @@ void ModListLayer::onTab(CCObject* pSender) {
|
||||||
toggleTab(m_featuredTabBtn);
|
toggleTab(m_featuredTabBtn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModListLayer::keyDown(enumKeyCodes key) {
|
||||||
|
if (key == KEY_Escape) {
|
||||||
|
this->onExit(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModListLayer::textChanged(CCTextInputNode* input) {
|
||||||
|
this->reloadList();
|
||||||
|
}
|
||||||
|
|
||||||
ModListLayer* ModListLayer::create() {
|
ModListLayer* ModListLayer::create() {
|
||||||
// return global instance if one exists
|
// return global instance if one exists
|
||||||
if (g_instance) return g_instance;
|
if (g_instance) return g_instance;
|
||||||
|
|
|
@ -1,13 +1,23 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ModListView.hpp"
|
|
||||||
|
|
||||||
#include <Geode/binding/TextInputDelegate.hpp>
|
#include <Geode/binding/TextInputDelegate.hpp>
|
||||||
#include <Geode/loader/Index.hpp>
|
#include <Geode/loader/Index.hpp>
|
||||||
|
|
||||||
USE_GEODE_NAMESPACE();
|
USE_GEODE_NAMESPACE();
|
||||||
|
|
||||||
class SearchFilterPopup;
|
class SearchFilterPopup;
|
||||||
|
class ModListCell;
|
||||||
|
|
||||||
|
enum class ModListType {
|
||||||
|
Installed,
|
||||||
|
Download,
|
||||||
|
Featured,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ModListDisplay {
|
||||||
|
Concise,
|
||||||
|
Expanded,
|
||||||
|
};
|
||||||
|
|
||||||
class ModListLayer : public CCLayer, public TextInputDelegate {
|
class ModListLayer : public CCLayer, public TextInputDelegate {
|
||||||
protected:
|
protected:
|
||||||
|
@ -46,11 +56,18 @@ protected:
|
||||||
void createSearchControl();
|
void createSearchControl();
|
||||||
void onIndexUpdate(IndexUpdateEvent* event);
|
void onIndexUpdate(IndexUpdateEvent* event);
|
||||||
|
|
||||||
|
CCArray* createModCells(ModListType type);
|
||||||
|
CCSize getCellSize() const;
|
||||||
|
CCSize getListSize() const;
|
||||||
|
|
||||||
friend class SearchFilterPopup;
|
friend class SearchFilterPopup;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ModListLayer* create();
|
static ModListLayer* create();
|
||||||
static ModListLayer* scene();
|
static ModListLayer* scene();
|
||||||
|
void updateAllStates(ModListCell* except = nullptr);
|
||||||
|
|
||||||
|
ModListDisplay getDisplay() const;
|
||||||
|
|
||||||
void reloadList();
|
void reloadList();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,164 +0,0 @@
|
||||||
#include "ModListView.hpp"
|
|
||||||
|
|
||||||
#include "../info/CategoryNode.hpp"
|
|
||||||
#include "ModListLayer.hpp"
|
|
||||||
#include "ModListCell.hpp"
|
|
||||||
|
|
||||||
#include <Geode/binding/ButtonSprite.hpp>
|
|
||||||
#include <Geode/binding/CCMenuItemSpriteExtra.hpp>
|
|
||||||
#include <Geode/binding/TableView.hpp>
|
|
||||||
#include <Geode/binding/CCMenuItemToggler.hpp>
|
|
||||||
#include <Geode/binding/CCContentLayer.hpp>
|
|
||||||
#include <Geode/loader/Mod.hpp>
|
|
||||||
#include <Geode/utils/casts.hpp>
|
|
||||||
#include <Geode/utils/cocos.hpp>
|
|
||||||
#include <Geode/utils/string.hpp>
|
|
||||||
#include <Geode/loader/Index.hpp>
|
|
||||||
#include <InternalLoader.hpp>
|
|
||||||
|
|
||||||
void ModListView::updateAllStates(ModListCell* toggled) {
|
|
||||||
for (auto cell : CCArrayExt<ModListCell>(m_tableView->m_cellArray)) {
|
|
||||||
if (toggled != cell) {
|
|
||||||
cell->updateState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModListView::setupList() {
|
|
||||||
m_itemSeparation = m_display == ModListDisplay::Expanded ? 60.f : 40.0f;
|
|
||||||
|
|
||||||
if (!m_entries->count()) return;
|
|
||||||
|
|
||||||
m_tableView->reloadData();
|
|
||||||
|
|
||||||
// fix content layer content size so the
|
|
||||||
// list is properly aligned to the top
|
|
||||||
auto coverage = calculateChildCoverage(m_tableView->m_contentLayer);
|
|
||||||
m_tableView->m_contentLayer->setContentSize({
|
|
||||||
-coverage.origin.x + coverage.size.width,
|
|
||||||
-coverage.origin.y + coverage.size.height
|
|
||||||
});
|
|
||||||
|
|
||||||
if (m_entries->count() == 1) {
|
|
||||||
m_tableView->moveToTopWithOffset(m_itemSeparation * 2);
|
|
||||||
}
|
|
||||||
else if (m_entries->count() == 2) {
|
|
||||||
m_tableView->moveToTopWithOffset(-m_itemSeparation);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_tableView->moveToTop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TableViewCell* ModListView::getListCell(char const* key) {
|
|
||||||
return ModCell::create(this, m_display, key, { m_width, m_itemSeparation });
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModListView::loadCell(TableViewCell* cell, unsigned int index) {
|
|
||||||
auto obj = m_entries->objectAtIndex(index);
|
|
||||||
if (auto mod = typeinfo_cast<ModObject*>(obj)) {
|
|
||||||
as<ModCell*>(cell)->loadFromMod(mod->mod);
|
|
||||||
}
|
|
||||||
if (auto mod = typeinfo_cast<IndexItemObject*>(obj)) {
|
|
||||||
// as<IndexItemCell*>(cell)->loadFromItem(mod->item);
|
|
||||||
}
|
|
||||||
if (auto failed = typeinfo_cast<InvalidGeodeFileObject*>(obj)) {
|
|
||||||
as<InvalidGeodeFileCell*>(cell)->loadFromInfo(failed->info);
|
|
||||||
}
|
|
||||||
as<ModListCell*>(cell)->updateBGColor(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sortInstalledMods(std::vector<Mod*>& mods) {
|
|
||||||
if (!mods.size()) return;
|
|
||||||
// keep track of first object
|
|
||||||
size_t frontIndex = 0;
|
|
||||||
auto front = mods.front();
|
|
||||||
for (auto mod = mods.begin(); mod != mods.end(); mod++) {
|
|
||||||
// move mods with updates to front
|
|
||||||
if (auto item = Index::get()->getItem(*mod)) {
|
|
||||||
if (Index::get()->updateAvailable(item)) {
|
|
||||||
// swap first object and updatable mod
|
|
||||||
// if the updatable mod is the first object,
|
|
||||||
// nothing changes
|
|
||||||
std::rotate(mods.begin(), mod, mod + 1);
|
|
||||||
|
|
||||||
// get next object at front for next mod
|
|
||||||
// to sort
|
|
||||||
frontIndex++;
|
|
||||||
front = mods[frontIndex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<Mod*> sortedInstalledMods() {
|
|
||||||
auto mods = Loader::get()->getAllMods();
|
|
||||||
sortInstalledMods(mods);
|
|
||||||
return std::move(mods);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ModListView::init(CCArray* mods, ModListDisplay display) {
|
|
||||||
m_display = display;
|
|
||||||
return CustomListView::init(mods, BoomListType::Default, 358.f, 190.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
CCArray* ModListView::modsForType(ModListType type) {
|
|
||||||
auto mods = CCArray::create();
|
|
||||||
switch (type) {
|
|
||||||
default:
|
|
||||||
case ModListType::Installed: {
|
|
||||||
// failed mods first
|
|
||||||
for (auto const& mod : Loader::get()->getFailedMods()) {
|
|
||||||
mods->addObject(new InvalidGeodeFileObject(mod));
|
|
||||||
}
|
|
||||||
// internal geode representation always at the top
|
|
||||||
auto imod = Loader::getInternalMod();
|
|
||||||
mods->addObject(new ModObject(imod));
|
|
||||||
|
|
||||||
// then other mods
|
|
||||||
for (auto const& mod : sortedInstalledMods()) {
|
|
||||||
// if the mod is no longer installed nor
|
|
||||||
// loaded, it's as good as not existing
|
|
||||||
// (because it doesn't)
|
|
||||||
if (mod->isUninstalled() && !mod->isLoaded()) continue;
|
|
||||||
mods->addObject(new ModObject(mod));
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ModListType::Download: {
|
|
||||||
for (auto const& item : Index::get()->getItems()) {
|
|
||||||
mods->addObject(new IndexItemObject(item));
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ModListType::Featured: {
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
return mods;
|
|
||||||
}
|
|
||||||
|
|
||||||
ModListView* ModListView::create(CCArray* mods, ModListDisplay display) {
|
|
||||||
auto pRet = new ModListView;
|
|
||||||
if (pRet) {
|
|
||||||
if (pRet->init(mods, display)) {
|
|
||||||
pRet->autorelease();
|
|
||||||
return pRet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CC_SAFE_DELETE(pRet);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ModListView* ModListView::create(ModListType type, ModListDisplay display) {
|
|
||||||
return ModListView::create(modsForType(type), display);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModListView::setLayer(ModListLayer* layer) {
|
|
||||||
m_layer = layer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModListView::refreshList() {
|
|
||||||
if (m_layer) {
|
|
||||||
m_layer->reloadList();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Geode/binding/CustomListView.hpp>
|
|
||||||
#include <Geode/binding/FLAlertLayerProtocol.hpp>
|
|
||||||
#include <Geode/binding/TableViewCell.hpp>
|
|
||||||
#include <Geode/loader/Index.hpp>
|
|
||||||
#include <Geode/loader/Loader.hpp>
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
USE_GEODE_NAMESPACE();
|
|
||||||
|
|
||||||
enum class ModListType {
|
|
||||||
Installed,
|
|
||||||
Download,
|
|
||||||
Featured,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ModListDisplay {
|
|
||||||
Concise,
|
|
||||||
Expanded,
|
|
||||||
};
|
|
||||||
|
|
||||||
class ModListLayer;
|
|
||||||
class ModListCell;
|
|
||||||
|
|
||||||
// for passing invalid files as CCObject
|
|
||||||
struct InvalidGeodeFileObject : public CCObject {
|
|
||||||
InvalidGeodeFile info;
|
|
||||||
inline InvalidGeodeFileObject(InvalidGeodeFile const& info) : info(info) {
|
|
||||||
this->autorelease();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ModObject : public CCObject {
|
|
||||||
Mod* mod;
|
|
||||||
inline ModObject(Mod* mod) : mod(mod) {
|
|
||||||
this->autorelease();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IndexItemObject : public CCObject {
|
|
||||||
IndexItemHandle item;
|
|
||||||
inline IndexItemObject(IndexItemHandle item) : item(item) {
|
|
||||||
this->autorelease();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ModListView : public CustomListView {
|
|
||||||
protected:
|
|
||||||
ModListLayer* m_layer = nullptr;
|
|
||||||
ModListDisplay m_display;
|
|
||||||
|
|
||||||
void setupList() override;
|
|
||||||
TableViewCell* getListCell(char const* key) override;
|
|
||||||
void loadCell(TableViewCell* cell, unsigned int index) override;
|
|
||||||
|
|
||||||
bool init(CCArray* mods, ModListDisplay display);
|
|
||||||
|
|
||||||
public:
|
|
||||||
static ModListView* create(CCArray* mods, ModListDisplay display);
|
|
||||||
static ModListView* create(ModListType type, ModListDisplay display);
|
|
||||||
static CCArray* modsForType(ModListType type);
|
|
||||||
|
|
||||||
void updateAllStates(ModListCell* except = nullptr);
|
|
||||||
void setLayer(ModListLayer* layer);
|
|
||||||
void refreshList();
|
|
||||||
};
|
|
|
@ -1,8 +1,7 @@
|
||||||
#include "SearchFilterPopup.hpp"
|
#include "SearchFilterPopup.hpp"
|
||||||
|
|
||||||
#include "../info/CategoryNode.hpp"
|
#include "../info/TagNode.hpp"
|
||||||
#include "ModListLayer.hpp"
|
#include "ModListLayer.hpp"
|
||||||
#include "ModListView.hpp"
|
|
||||||
|
|
||||||
#include <Geode/binding/GameToolbox.hpp>
|
#include <Geode/binding/GameToolbox.hpp>
|
||||||
#include <Geode/binding/CCMenuItemToggler.hpp>
|
#include <Geode/binding/CCMenuItemToggler.hpp>
|
||||||
|
|
Loading…
Reference in a new issue