Compare commits

...

5 commits

Author SHA1 Message Date
TheSillyDoggo
cca048207d
Merge bd6bfb661f into 1ff24f09c6 2024-11-18 18:20:11 -06:00
HJfod
1ff24f09c6 finish grid view 2024-11-19 00:18:23 +02:00
HJfod
6e86b38990 fix vv version 2024-11-18 21:31:17 +02:00
Explodingbill
bd6bfb661f asdf 2024-11-16 15:03:10 +11:00
Explodingbill
03e8220dfe Add OverlayManager 2024-11-16 13:48:59 +11:00
18 changed files with 214 additions and 33 deletions

View file

@ -0,0 +1,41 @@
#pragma once
#include "../DefaultInclude.hpp"
#include <cocos2d.h>
#include <vector>
#include <span>
#include <Geode/utils/cocos.hpp>
namespace geode
{
/*
Because cocos only allows for one notification node (a node drawn last, above the fps counter and everything),
I added this, a simple class to add nodes to a general notification node so that mods dont interfere with each other.
*/
class GEODE_DLL OverlayManager : private cocos2d::CCNode
{
private:
std::vector<cocos2d::CCNode*> nodes;
public:
/// @brief Get the overlay manager instance, and if it doesnt exist, sets the notification node to it
static OverlayManager* get();
/// @brief Adds a node to the overlay manager, overlays are sorted by ZOrder, the higher the order is the later it draws. This will retain the node
void addNode(cocos2d::CCNode* node);
/// @brief Removes a node from the overlay manager, stopping it from being drawn. This will release the node
void removeNode(cocos2d::CCNode* node);
/// @brief Util to get the highest ZOrder of all nodes
int getHighestOverlayZOrder();
/// @brief Util to get the lowest ZOrder of all nodes
int getLowestOverlayZOrder();
/// @brief Gets all the overlays
std::vector<cocos2d::CCNode*> getOverlays();
};
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -1079,7 +1079,7 @@ void Loader::Impl::installModManuallyFromFile(std::filesystem::path const& path,
createQuickPopup(
"Already Installed",
fmt::format(
"The mod <cy>{}</c> <cj>v{}</c> has already been installed "
"The mod <cy>{}</c> <cj>{}</c> has already been installed "
"as version <cl>{}</c>. Do you want to <co>replace the "
"installed version with the file</c>?",
meta.getID(), meta.getVersion(),

View file

@ -19,6 +19,8 @@
#include "ui/mods/sources/ModListSource.hpp"
#include <loader/LoaderImpl.hpp>
static ModListDisplay MOD_LIST_DISPLAY = ModListDisplay::SmallList;
bool ModsStatusNode::init() {
if (!CCNode::init())
return false;
@ -649,7 +651,7 @@ void ModsLayer::gotoTab(ModListSource* src) {
m_currentSource = src;
// Update the state of the current list
m_lists.at(m_currentSource)->updateDisplay(m_display);
m_lists.at(m_currentSource)->updateDisplay(MOD_LIST_DISPLAY);
m_lists.at(m_currentSource)->activateSearch(m_showSearch);
m_lists.at(m_currentSource)->updateState();
}
@ -711,7 +713,7 @@ void ModsLayer::updateState() {
// Update display button
for (auto btn : m_displayBtns) {
static_cast<GeodeSquareSprite*>(btn->getNormalImage())->setState(
static_cast<ModListDisplay>(btn->getTag()) == m_display
static_cast<ModListDisplay>(btn->getTag()) == MOD_LIST_DISPLAY
);
}
}
@ -744,10 +746,11 @@ void ModsLayer::onGoToPage(CCObject*) {
popup->show();
}
void ModsLayer::onDisplay(CCObject* sender) {
m_display = static_cast<ModListDisplay>(sender->getTag());
MOD_LIST_DISPLAY = static_cast<ModListDisplay>(sender->getTag());
// Make sure to avoid a crash
if (m_currentSource) {
m_lists.at(m_currentSource)->updateDisplay(m_display);
m_lists.at(m_currentSource)->updateDisplay(MOD_LIST_DISPLAY);
m_lists.at(m_currentSource)->reloadPage();
}
this->updateState();
}

View file

@ -66,7 +66,6 @@ protected:
ModsStatusNode* m_statusNode;
EventListener<UpdateModListStateFilter> m_updateStateListener;
bool m_showSearch = true;
ModListDisplay m_display = ModListDisplay::SmallList;
std::vector<CCMenuItemSpriteExtra*> m_displayBtns;
bool init();

View file

@ -54,6 +54,10 @@ bool ModItem::init(ModSource&& source) {
m_versionLabel->setLayoutOptions(AxisLayoutOptions::create()->setScaleLimits(std::nullopt, .7f));
m_titleContainer->addChild(m_versionLabel);
m_versionDownloadSeparator = CCLabelBMFont::create("", "bigFont.fnt");
m_versionDownloadSeparator->setOpacity(155);
m_titleContainer->addChild(m_versionDownloadSeparator);
m_titleContainer->setLayout(
RowLayout::create()
->setDefaultScaleLimits(.1f, 1.f)
@ -180,10 +184,7 @@ bool ModItem::init(ModSource&& source) {
}
}
auto viewBtn = CCMenuItemSpriteExtra::create(
spr,
this, menu_selector(ModItem::onView)
);
auto viewBtn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(ModItem::onView));
viewBtn->setID("view-button");
m_viewMenu->addChild(viewBtn);
@ -229,10 +230,23 @@ bool ModItem::init(ModSource&& source) {
m_badgeContainer->addChild(CCSprite::createWithSpriteFrameName("tag-featured.png"_spr));
}
if (metadata.tags.contains("paid")) {
m_badgeContainer->addChild(CCSprite::createWithSpriteFrameName("tag-paid.png"_spr));
auto shortVer = CCSprite::createWithSpriteFrameName("tag-paid.png"_spr);
shortVer->setTag(1);
m_badgeContainer->addChild(shortVer);
auto longVer = CCSprite::createWithSpriteFrameName("tag-paid-long.png"_spr);
longVer->setTag(2);
m_badgeContainer->addChild(longVer);
}
if (metadata.tags.contains("joke")) {
m_badgeContainer->addChild(CCSprite::createWithSpriteFrameName("tag-joke.png"_spr));
}
if (metadata.tags.contains("modtober24")) {
m_badgeContainer->addChild(CCSprite::createWithSpriteFrameName("tag-modtober.png"_spr));
auto shortVer = CCSprite::createWithSpriteFrameName("tag-modtober.png"_spr);
shortVer->setTag(1);
m_badgeContainer->addChild(shortVer);
auto longVer = CCSprite::createWithSpriteFrameName("tag-modtober-long.png"_spr);
longVer->setTag(2);
m_badgeContainer->addChild(longVer);
}
// Show mod download count here already so people can make informed decisions
@ -242,17 +256,18 @@ bool ModItem::init(ModSource&& source) {
auto downloads = CCLabelBMFont::create(numToAbbreviatedString(metadata.downloadCount).c_str(), "bigFont.fnt");
downloads->setID("downloads-label");
downloads->setColor("mod-list-version-label"_cc3b);
downloads->limitLabelWidth(80, .5f, .1f);
downloads->limitLabelWidth(125, 1.f, .1f);
m_downloadCountContainer->addChildAtPosition(downloads, Anchor::Right, ccp(-0, 0), ccp(1, .5f));
auto downloadsIcon = CCSprite::createWithSpriteFrameName("GJ_downloadsIcon_001.png");
downloadsIcon->setID("downloads-icon-sprite");
downloadsIcon->setScale(.75f);
m_downloadCountContainer->addChildAtPosition(downloadsIcon, Anchor::Left, ccp(5, 0));
downloadsIcon->setScale(1.2f);
m_downloadCountContainer->addChildAtPosition(downloadsIcon, Anchor::Left, ccp(8, 0));
// m_downloadCountContainer scale is controlled in updateState
m_downloadCountContainer->setContentSize({
downloads->getScaledContentWidth() + downloadsIcon->getScaledContentWidth(),
25
30
});
m_downloadCountContainer->updateLayout();
@ -338,7 +353,7 @@ void ModItem::updateState() {
// Update the size of the mod cell itself
if (m_display == ModListDisplay::Grid) {
auto widthWithoutGaps = m_targetWidth - 10;
auto widthWithoutGaps = m_targetWidth - 7.5f;
this->setContentSize(ccp(widthWithoutGaps / roundf(widthWithoutGaps / 80), 100));
m_bg->setContentSize(m_obContentSize / m_bg->getScale());
}
@ -358,14 +373,19 @@ void ModItem::updateState() {
m_titleContainer->insertBefore(m_titleLabel, nullptr);
}
// Show download separator if there is something to separate and we're in grid view
m_versionDownloadSeparator->setVisible(m_downloadCountContainer && m_display == ModListDisplay::Grid);
// Download counts go next to the version like on the website on grid view
if (m_downloadCountContainer) {
m_downloadCountContainer->removeFromParent();
if (m_display == ModListDisplay::Grid) {
m_titleContainer->insertAfter(m_downloadCountContainer, m_versionLabel);
m_titleContainer->insertAfter(m_downloadCountContainer, m_versionDownloadSeparator);
m_downloadCountContainer->setLayoutOptions(AxisLayoutOptions::create()->setScaleLimits(.1f, .7f));
}
else {
m_viewMenu->addChild(m_downloadCountContainer);
m_downloadCountContainer->setLayoutOptions(AxisLayoutOptions::create()->setScaleLimits(.1f, .6f));
}
}
@ -373,14 +393,31 @@ void ModItem::updateState() {
if (m_badgeContainer) {
m_badgeContainer->removeFromParent();
if (m_display == ModListDisplay::Grid) {
m_badgeContainer->setLayout(ColumnLayout::create()->setAutoGrowAxis(true));
m_badgeContainer->setScale(.25f);
this->addChildAtPosition(m_badgeContainer, Anchor::TopLeft, ccp(5, -5), ccp(0, 1));
m_badgeContainer->setLayout(
ColumnLayout::create()
->setAxisReverse(true)
->setAutoGrowAxis(true)
->setAxisAlignment(AxisAlignment::Start)
);
m_badgeContainer->getLayout()->ignoreInvisibleChildren(true);
m_badgeContainer->setScale(.3f);
this->addChildAtPosition(m_badgeContainer, Anchor::TopLeft, ccp(5, -2), ccp(0, 1));
}
else {
m_badgeContainer->setLayout(RowLayout::create()->setAutoGrowAxis(true));
m_badgeContainer->setLayout(
RowLayout::create()
->setAutoGrowAxis(true)
);
m_badgeContainer->getLayout()->ignoreInvisibleChildren(true);
m_titleContainer->addChild(m_badgeContainer);
}
// Long tags don't fit in the grid UI
for (auto child : CCArrayExt<CCNode*>(m_badgeContainer->getChildren())) {
if (child->getTag() > 0) {
child->setVisible(child->getTag() == (m_display == ModListDisplay::Grid ? 1 : 2));
}
}
m_badgeContainer->updateLayout();
}
// On Grid View logo has constant size
@ -558,6 +595,9 @@ void ModItem::updateState() {
m_recommendedBy->updateLayout();
}
limitNodeWidth(m_downloadWaiting, m_titleContainer->getContentWidth(), 1.f, .1f);
limitNodeWidth(m_downloadBarContainer, m_titleContainer->getContentWidth(), 1.f, .1f);
// Update positioning (jesus)
switch (m_display) {
case ModListDisplay::Grid: {

View file

@ -48,6 +48,7 @@ protected:
Ref<CCNode> m_downloadCountContainer;
ModListDisplay m_display = ModListDisplay::SmallList;
float m_targetWidth = 300;
CCLabelBMFont* m_versionDownloadSeparator;
/**
* @warning Make sure `getMetadata` and `createModLogo` are callable

View file

@ -6,6 +6,22 @@
#include "../ModsLayer.hpp"
#include "../popups/ModtoberPopup.hpp"
static size_t getDisplayPageSize(ModListSource* src, ModListDisplay display) {
if (src->isLocalModsOnly() && Mod::get()->template getSettingValue<bool>("infinite-local-mods-list")) {
return std::numeric_limits<size_t>::max();
}
return display == ModListDisplay::Grid ? 16 : 10;
}
$execute {
listenForSettingChanges("infinite-local-mods-list", [](bool value) {
InstalledModListSource::get(InstalledModListType::All)->reset();
InstalledModListSource::get(InstalledModListType::OnlyErrors)->reset();
InstalledModListSource::get(InstalledModListType::OnlyOutdated)->reset();
// Updates is technically a server mod list :-) So I left it out here
});
}
bool ModList::init(ModListSource* src, CCSize const& size) {
if (!CCNode::init())
return false;
@ -179,7 +195,7 @@ bool ModList::init(ModListSource* src, CCSize const& size) {
m_searchInput->setCallback([this](auto const&) {
// If the source is already in memory, we can immediately update the
// search query
if (typeinfo_cast<InstalledModListSource*>(m_source)) {
if (m_source->isLocalModsOnly()) {
m_source->search(m_searchInput->getString());
return;
}
@ -550,6 +566,7 @@ void ModList::updateTopContainer() {
void ModList::updateDisplay(ModListDisplay display) {
m_display = display;
m_source->setPageSize(getDisplayPageSize(m_source, m_display));
// Update all BaseModItems that are children of the list
// There may be non-BaseModItems there (like separators) so gotta be type-safe
@ -570,7 +587,7 @@ void ModList::updateDisplay(ModListDisplay display) {
m_list->m_contentLayer->setLayout(
RowLayout::create()
->setGrowCrossAxis(true)
->setAxisAlignment(AxisAlignment::Center)
->setAxisAlignment(AxisAlignment::Start)
->setGap(2.5f)
);
}
@ -635,6 +652,9 @@ void ModList::gotoPage(size_t page, bool update) {
m_list->m_contentLayer->removeAllChildren();
m_page = page;
// Update page size (if needed)
m_source->setPageSize(getDisplayPageSize(m_source, m_display));
// Start loading new page with generic loading message
this->showStatus(ModListUnkProgressStatus(), "Loading...");
m_listener.setFilter(m_source->loadPage(page, update));

View file

@ -137,11 +137,8 @@ bool InstalledModListSource::isDefaultQuery() const {
return m_query.isDefault();
}
$execute {
listenForSettingChanges("infinite-local-mods-list", [](bool value) {
auto size = value ? std::numeric_limits<size_t>::max() : 10;
InstalledModListSource::get(InstalledModListType::All)->setPageSize(size);
InstalledModListSource::get(InstalledModListType::OnlyErrors)->setPageSize(size);
// Updates is technically a server mod list :-) So I left it out here
});
bool InstalledModListSource::isLocalModsOnly() const {
return m_type == InstalledModListType::All ||
m_type == InstalledModListType::OnlyErrors ||
m_type == InstalledModListType::OnlyOutdated;
}

View file

@ -62,9 +62,11 @@ std::optional<size_t> ModListSource::getItemCount() const {
return m_cachedItemCount;
}
void ModListSource::setPageSize(size_t size) {
if (m_pageSize != size) {
m_pageSize = size;
this->reset();
}
}
void ModListSource::reset() {
this->resetQuery();

View file

@ -78,6 +78,8 @@ public:
std::optional<size_t> getItemCount() const;
void setPageSize(size_t size);
virtual bool isLocalModsOnly() const = 0;
static void clearAllCaches();
};
@ -139,6 +141,8 @@ public:
InstalledModsQuery const& getQuery() const;
InvalidateQueryAfter<InstalledModsQuery> getQueryMut();
bool isDefaultQuery() const override;
bool isLocalModsOnly() const override;
};
enum class ServerModListType {
@ -171,6 +175,8 @@ public:
bool isDefaultQuery() const override;
server::ModsQuery createDefaultQuery() const;
ServerModListType getType() const;
bool isLocalModsOnly() const override;
};
class ModPackListSource : public ModListSource {
@ -187,6 +193,8 @@ public:
std::unordered_set<std::string> getModTags() const override;
void setModTags(std::unordered_set<std::string> const& tags) override;
bool isDefaultQuery() const override;
bool isLocalModsOnly() const override;
};
bool weightedFuzzyMatch(std::string const& str, std::string const& kw, double weight, double& out);

View file

@ -21,3 +21,7 @@ void ModPackListSource::setModTags(std::unordered_set<std::string> const& set) {
bool ModPackListSource::isDefaultQuery() const {
return true;
}
bool ModPackListSource::isLocalModsOnly() const {
return false;
}

View file

@ -115,3 +115,7 @@ server::ModsQuery ServerModListSource::createDefaultQuery() const {
ServerModListType ServerModListSource::getType() const {
return m_type;
}
bool ServerModListSource::isLocalModsOnly() const {
return false;
}

View file

@ -0,0 +1,62 @@
#include <Geode/ui/OverlayManager.hpp>
using namespace geode::prelude;
OverlayManager* OverlayManager::get()
{
static OverlayManager* instance;
if (!instance)
{
instance = new OverlayManager();
CCDirector::get()->setNotificationNode(instance);
}
return instance;
}
void OverlayManager::addNode(CCNode* node)
{
this->addChild(node);
nodes.push_back(node);
}
void OverlayManager::removeNode(CCNode* node)
{
this->removeChild(node);
std::erase(nodes, node);
}
int OverlayManager::getHighestOverlayZOrder()
{
int z = INT_MIN;
for (auto node : nodes)
{
if (node->getZOrder() > z)
z = node->getZOrder();
}
return z;
}
int OverlayManager::getLowestOverlayZOrder()
{
int z = INT_MAX;
for (auto node : nodes)
{
if (node->getZOrder() < z)
z = node->getZOrder();
}
return z;
}
std::vector<CCNode*> OverlayManager::getOverlays()
{
return nodes;
}