mirror of
https://github.com/geode-sdk/geode.git
synced 2025-03-25 04:11:42 -04:00
Improved Popup class; makeMemberFunction & makeMenuSelector; one-time
info alerts; improved some UI stuff
This commit is contained in:
parent
78415153b5
commit
8d7a46f6ab
13 changed files with 248 additions and 144 deletions
cmake
loader
include/Geode
resources
src
|
@ -9,6 +9,14 @@ else()
|
|||
endif()
|
||||
|
||||
function(create_geode_file proname)
|
||||
message(
|
||||
DEPRECATION
|
||||
"create_geode_file has been deprecated, and will
|
||||
be replaced by create_geode_file_v2 in the future.
|
||||
Do note that create_geode_file_v2 will be *renamed*
|
||||
to create_geode_file"
|
||||
)
|
||||
|
||||
message(STATUS "Creating geode file")
|
||||
|
||||
if(GEODE_CLI STREQUAL "GEODE_CLI-NOTFOUND")
|
||||
|
@ -24,6 +32,22 @@ function(create_geode_file proname)
|
|||
|
||||
endfunction()
|
||||
|
||||
function(create_geode_file_v2 proname)
|
||||
message(STATUS "Creating geode file")
|
||||
|
||||
if(GEODE_CLI STREQUAL "GEODE_CLI-NOTFOUND")
|
||||
message(WARNING "create_geode_file called, but Geode CLI was not found - You will need to manually package the .geode files")
|
||||
else()
|
||||
|
||||
add_custom_target(${proname}_PACKAGE ALL
|
||||
DEPENDS ${proname}
|
||||
COMMAND ${GEODE_CLI} package new ${CMAKE_CURRENT_SOURCE_DIR} --out $<TARGET_FILE_DIR:${proname}>/${proname}.geode --install
|
||||
VERBATIM USES_TERMINAL
|
||||
)
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
function(package_geode_resources proname src dest prefix)
|
||||
message(STATUS "Packaging resources from ${src} with prefix ${prefix} into ${dest}")
|
||||
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
#include <Geode/Bindings.hpp>
|
||||
|
||||
namespace geode {
|
||||
template<typename T, typename... InitArgs>
|
||||
template<typename... InitArgs>
|
||||
class GEODE_DLL Popup : public FLAlertLayer {
|
||||
protected:
|
||||
cocos2d::CCSize m_size;
|
||||
cocos2d::extension::CCScale9Sprite* m_bgSprite;
|
||||
cocos2d::CCLabelBMFont* m_title = nullptr;
|
||||
|
||||
bool init(
|
||||
float width,
|
||||
|
@ -16,13 +17,13 @@ namespace geode {
|
|||
const char* bg = "GJ_square01.png"
|
||||
) {
|
||||
auto winSize = cocos2d::CCDirector::sharedDirector()->getWinSize();
|
||||
m_size = cocos2d::CCSize{width, height};
|
||||
m_size = cocos2d::CCSize { width, height };
|
||||
|
||||
if (!this->initWithColor({0, 0, 0, 105})) return false;
|
||||
if (!this->initWithColor({ 0, 0, 0, 105 })) return false;
|
||||
m_mainLayer = cocos2d::CCLayer::create();
|
||||
this->addChild(m_mainLayer);
|
||||
|
||||
m_bgSprite = cocos2d::extension::CCScale9Sprite::create(bg, {0.0f, 0.0f, 80.0f, 80.0f});
|
||||
m_bgSprite = cocos2d::extension::CCScale9Sprite::create(bg, { 0, 0, 80, 80 });
|
||||
m_bgSprite->setContentSize(m_size);
|
||||
m_bgSprite->setPosition(winSize.width / 2, winSize.height / 2);
|
||||
m_mainLayer->addChild(m_bgSprite);
|
||||
|
@ -33,13 +34,20 @@ namespace geode {
|
|||
cocos2d::CCDirector::sharedDirector()->getTouchDispatcher()->incrementForcePrio(2);
|
||||
this->registerWithTouchDispatcher();
|
||||
|
||||
this->setup(args...);
|
||||
if (!setup(std::forward<InitArgs>(args)...)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto closeSpr = cocos2d::CCSprite::createWithSpriteFrameName("GJ_closeBtn_001.png");
|
||||
closeSpr->setScale(.8f);
|
||||
|
||||
auto closeBtn = CCMenuItemSpriteExtra::create(closeSpr, this, (cocos2d::SEL_MenuHandler)(&Popup::onClose));
|
||||
closeBtn->setPosition(-m_size.width / 2 + 3.f, m_size.height / 2 - 3.f);
|
||||
auto closeBtn = CCMenuItemSpriteExtra::create(
|
||||
closeSpr, this, (cocos2d::SEL_MenuHandler)(&Popup::onClose)
|
||||
);
|
||||
closeBtn->setPosition(
|
||||
-m_size.width / 2 + 3.f,
|
||||
m_size.height / 2 - 3.f
|
||||
);
|
||||
m_buttonMenu->addChild(closeBtn);
|
||||
|
||||
this->setKeypadEnabled(true);
|
||||
|
@ -48,7 +56,7 @@ namespace geode {
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual void setup(InitArgs... args) = 0;
|
||||
virtual bool setup(InitArgs... args) = 0;
|
||||
|
||||
void keyDown(cocos2d::enumKeyCodes key) {
|
||||
if (key == cocos2d::enumKeyCodes::KEY_Escape) return this->onClose(nullptr);
|
||||
|
@ -60,6 +68,21 @@ namespace geode {
|
|||
this->setKeyboardEnabled(false);
|
||||
this->removeFromParentAndCleanup(true);
|
||||
}
|
||||
|
||||
void setTitle(const char* title, const char* font = "goldFont.fnt") {
|
||||
if (m_title) {
|
||||
m_title->setString(title);
|
||||
} else {
|
||||
auto winSize = cocos2d::CCDirector::sharedDirector()->getWinSize();
|
||||
m_title = cocos2d::CCLabelBMFont::create(title, font);
|
||||
m_title->setPosition(
|
||||
winSize.width / 2,
|
||||
winSize.height / 2 + m_size.height / 2 - 20.f
|
||||
);
|
||||
m_mainLayer->addChild(m_title, 2);
|
||||
}
|
||||
m_title->limitLabelWidth(m_size.width - 20.f, .7f, .1f);
|
||||
}
|
||||
};
|
||||
|
||||
void GEODE_DLL createQuickPopup(
|
||||
|
|
|
@ -56,7 +56,11 @@ namespace geode {
|
|||
* structures, this class can handle either
|
||||
* one universally. All relevant vtables are
|
||||
* stored in-class to avoid needing to
|
||||
* `dynamic_cast` everything.
|
||||
* `dynamic_cast` everything. This way of
|
||||
* storing vtables also means that anything
|
||||
* which satisfies these 3 vtables can be used,
|
||||
* even if its true UX representation is
|
||||
* actually not a label.
|
||||
*/
|
||||
struct Label {
|
||||
/**
|
||||
|
|
|
@ -372,4 +372,92 @@ namespace geode::cocos {
|
|||
auto selectorFromFn(std::function<F> fn) {
|
||||
return SelectorWrapper(fn);
|
||||
}
|
||||
|
||||
// namespace for storing implementation stuff for
|
||||
// inline member functions
|
||||
namespace {
|
||||
// class that holds the lambda (probably should've just used
|
||||
// std::function but hey, this one's heap-free!)
|
||||
template<class F, class Ret, class... Args>
|
||||
struct LambdaHolder {
|
||||
bool m_assigned = false;
|
||||
// lambdas don't implement operator= so we
|
||||
// gotta do this wacky union stuff
|
||||
union {
|
||||
F m_lambda;
|
||||
};
|
||||
LambdaHolder() {}
|
||||
~LambdaHolder() {
|
||||
if (m_assigned) {
|
||||
m_lambda.~F();
|
||||
}
|
||||
}
|
||||
Ret operator()(Args... args) {
|
||||
if (m_assigned) {
|
||||
return m_lambda(std::forward<Args>(args)...);
|
||||
} else {
|
||||
if constexpr (!std::is_void_v<Ret>) {
|
||||
return Ret();
|
||||
}
|
||||
}
|
||||
}
|
||||
void assign(F&& func) {
|
||||
if (!m_assigned) {
|
||||
new (&m_lambda) F(func);
|
||||
m_assigned = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Extract parameters and return type from a lambda
|
||||
template<class Func>
|
||||
struct ExtractLambda : public ExtractLambda<decltype(&Func::operator())> {};
|
||||
|
||||
template<class C, class R, class... Args>
|
||||
struct ExtractLambda<R(C::*)(Args...) const> {
|
||||
using Ret = R;
|
||||
using Params = std::tuple<Args...>;
|
||||
};
|
||||
|
||||
// Class for storing the member function
|
||||
template<class Base, class Func, class Args>
|
||||
struct InlineMemberFunction;
|
||||
|
||||
template<class Base, class Func, class... Args>
|
||||
struct InlineMemberFunction<Base, Func, std::tuple<Args...>> : public Base {
|
||||
// this class isn't instantiated anywhere, and is
|
||||
// just used as a proxy to redirect the member function
|
||||
// to the lambda
|
||||
static inline LambdaHolder<Func, typename ExtractLambda<Func>::Ret, Args...> s_selector {};
|
||||
typename ExtractLambda<Func>::Ret onSelector(Args... args) {
|
||||
return s_selector(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a lambda into a member function pointer. Useful for creating
|
||||
* callbacks that have to be members of a class without having to deal
|
||||
* with all of the boilerplate associated with defining a new class
|
||||
* member function.
|
||||
*/
|
||||
template<class Base, class Func>
|
||||
static auto makeMemberFunction(Func&& function) {
|
||||
InlineMemberFunction<Base, Func, typename ExtractLambda<Func>::Params>::s_selector.assign(std::move(function));
|
||||
return &InlineMemberFunction<Base, Func, typename ExtractLambda<Func>::Params>::onSelector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SEL_MenuHandler out of a lambda with optional captures. Useful
|
||||
* for adding callbacks to CCMenuItemSpriteExtras without needing to add
|
||||
* the callback as a member to a class. Use the GEODE_MENU_SELECTOR class
|
||||
* for even more concise code.
|
||||
*/
|
||||
template<class Func>
|
||||
static cocos2d::SEL_MenuHandler makeMenuSelector(Func&& selector) {
|
||||
return (cocos2d::SEL_MenuHandler)(makeMemberFunction<cocos2d::CCObject, Func>(std::move(selector)));
|
||||
}
|
||||
|
||||
#define GEODE_MENU_SELECTOR(senderArg, ...) \
|
||||
makeMenuSelector([=](senderArg) { __VA_ARGS__; })
|
||||
}
|
||||
|
|
BIN
loader/resources/sort.png
Normal file
BIN
loader/resources/sort.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 3 KiB |
|
@ -70,6 +70,22 @@ bool InternalLoader::platformConsoleReady() const {
|
|||
return m_platformConsoleReady;
|
||||
}
|
||||
|
||||
bool InternalLoader::shownInfoAlert(std::string const& key) {
|
||||
if (m_shownInfoAlerts.count(key)) {
|
||||
return true;
|
||||
}
|
||||
m_shownInfoAlerts.insert(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
void InternalLoader::saveInfoAlerts(nlohmann::json& json) {
|
||||
json["alerts"] = m_shownInfoAlerts;
|
||||
}
|
||||
|
||||
void InternalLoader::loadInfoAlerts(nlohmann::json& json) {
|
||||
m_shownInfoAlerts = json["alerts"].get<std::unordered_set<std::string>>();
|
||||
}
|
||||
|
||||
#if defined(GEODE_IS_WINDOWS)
|
||||
void InternalLoader::platformMessageBox(const char* title, const char* info) {
|
||||
MessageBoxA(nullptr, title, info, MB_OK);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <Geode/loader/Loader.hpp>
|
||||
#include <Geode/loader/Log.hpp>
|
||||
#include <Geode/utils/Result.hpp>
|
||||
#include <unordered_set>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
|
@ -20,9 +21,16 @@ protected:
|
|||
std::vector<std::function<void(void)>> m_gdThreadQueue;
|
||||
mutable std::mutex m_gdThreadMutex;
|
||||
bool m_platformConsoleReady = false;
|
||||
std::unordered_set<std::string> m_shownInfoAlerts;
|
||||
|
||||
void saveInfoAlerts(nlohmann::json& json);
|
||||
void loadInfoAlerts(nlohmann::json& json);
|
||||
|
||||
InternalLoader();
|
||||
~InternalLoader();
|
||||
|
||||
friend class Loader;
|
||||
|
||||
public:
|
||||
static InternalLoader* get();
|
||||
|
||||
|
@ -30,6 +38,13 @@ public:
|
|||
|
||||
bool loadHooks();
|
||||
|
||||
/**
|
||||
* Check if a one-time event has been shown to the user,
|
||||
* and set it to true if not. Will return the previous
|
||||
* state of the event before setting it to true
|
||||
*/
|
||||
bool shownInfoAlert(std::string const& key);
|
||||
|
||||
void queueInGDThread(std::function<void GEODE_CALL(void)> func);
|
||||
void executeGDThreadQueue();
|
||||
|
||||
|
|
|
@ -192,6 +192,7 @@ Result<> Loader::saveSettings() {
|
|||
json["mods"][id] = value;
|
||||
}
|
||||
json["succesfully-closed"] = true;
|
||||
InternalLoader::get()->saveInfoAlerts(json);
|
||||
auto path = this->getGeodeSaveDirectory() / "mods.json";
|
||||
return file_utils::writeString(path, json.dump(4));
|
||||
}
|
||||
|
@ -233,6 +234,7 @@ Result<> Loader::loadSettings() {
|
|||
m_loadedSettings.m_mods.insert({ key, mod });
|
||||
}
|
||||
}
|
||||
InternalLoader::get()->loadInfoAlerts(json);
|
||||
return Ok();
|
||||
} catch(std::exception const& e) {
|
||||
return Err(e.what());
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <Geode/ui/BasedButton.hpp>
|
||||
#include "SearchFilterPopup.hpp"
|
||||
#include <Geode/ui/Notification.hpp>
|
||||
#include <optional>
|
||||
|
||||
static ModListType g_tab = ModListType::Installed;
|
||||
static ModListLayer* g_instance = nullptr;
|
||||
|
@ -124,17 +125,21 @@ std::tuple<CCNode*, CCTextInputNode*> ModListLayer::createSearchControl() {
|
|||
auto menu = CCMenu::create();
|
||||
menu->setPosition(340.f, 15.f);
|
||||
|
||||
// filters
|
||||
auto filterSpr = EditorButtonSprite::createWithSpriteFrameName(
|
||||
"filters.png"_spr, 1.0f, EditorBaseColor::Gray
|
||||
);
|
||||
filterSpr->setScale(.7f);
|
||||
|
||||
auto filterBtn = CCMenuItemSpriteExtra::create(
|
||||
filterSpr, this, menu_selector(ModListLayer::onSearchFilters)
|
||||
filterSpr, this, makeMenuSelector([this](CCObject*) {
|
||||
SearchFilterPopup::create(this)->show();
|
||||
})
|
||||
);
|
||||
filterBtn->setPosition(-8.f, 0.f);
|
||||
filterBtn->setPosition(-10.f, 0.f);
|
||||
menu->addChild(filterBtn);
|
||||
|
||||
// search button
|
||||
auto searchSpr = CCSprite::createWithSpriteFrameName("gj_findBtn_001.png");
|
||||
searchSpr->setScale(.7f);
|
||||
|
||||
|
@ -152,16 +157,17 @@ std::tuple<CCNode*, CCTextInputNode*> ModListLayer::createSearchControl() {
|
|||
m_searchClearBtn->setVisible(false);
|
||||
menu->addChild(m_searchClearBtn);
|
||||
|
||||
// search input
|
||||
auto inputBG = CCScale9Sprite::create(
|
||||
"square02b_001.png", { 0.0f, 0.0f, 80.0f, 80.0f }
|
||||
);
|
||||
inputBG->setColor({ 126, 59, 7 });
|
||||
inputBG->setContentSize({ 530.f, 40.f });
|
||||
inputBG->setPosition(153.f, 15.f);
|
||||
inputBG->setContentSize({ 550.f, 40.f });
|
||||
inputBG->setPosition(150.f, 15.f);
|
||||
inputBG->setScale(.5f);
|
||||
layer->addChild(inputBG);
|
||||
|
||||
auto input = CCTextInputNode::create(250.f, 20.f, "Search Mods...", "bigFont.fnt");
|
||||
auto input = CCTextInputNode::create(260.f, 20.f, "Search Mods...", "bigFont.fnt");
|
||||
input->setLabelPlaceholderColor({ 150, 150, 150 });
|
||||
input->setLabelPlaceholderScale(.4f);
|
||||
input->setMaxLabelScale(.4f);
|
||||
|
@ -170,6 +176,7 @@ std::tuple<CCNode*, CCTextInputNode*> ModListLayer::createSearchControl() {
|
|||
input->m_placeholderLabel->setAnchorPoint({ .0f, .5f });
|
||||
|
||||
layer->addChild(menu);
|
||||
|
||||
return { layer, input };
|
||||
}
|
||||
|
||||
|
@ -278,7 +285,7 @@ void ModListLayer::reloadList() {
|
|||
|
||||
m_searchInput = std::get<1>(search);
|
||||
m_searchInput->setPosition(
|
||||
winSize.width / 2 - 155.f,
|
||||
winSize.width / 2 - 160.f,
|
||||
winSize.height / 2 + 95.f
|
||||
);
|
||||
m_searchInput->setZOrder(60);
|
||||
|
@ -397,10 +404,6 @@ void ModListLayer::onTab(CCObject* pSender) {
|
|||
toggleTab(m_featuredTabBtn);
|
||||
}
|
||||
|
||||
void ModListLayer::onSearchFilters(CCObject*) {
|
||||
SearchFilterPopup::create(this)->show();
|
||||
}
|
||||
|
||||
ModListLayer* ModListLayer::create() {
|
||||
// return global instance if one exists
|
||||
if (g_instance) return g_instance;
|
||||
|
|
|
@ -37,7 +37,6 @@ protected:
|
|||
void onResetSearch(CCObject*);
|
||||
void keyDown(enumKeyCodes) override;
|
||||
void onTab(CCObject*);
|
||||
void onSearchFilters(CCObject*);
|
||||
void textChanged(CCTextInputNode*) override;
|
||||
void indexUpdateProgress(
|
||||
UpdateStatus status,
|
||||
|
|
|
@ -3,6 +3,15 @@
|
|||
#include <Geode/utils/WackyGeodeMacros.hpp>
|
||||
#include <Index.hpp>
|
||||
#include "ModListLayer.hpp"
|
||||
#include <InternalLoader.hpp>
|
||||
|
||||
template<class T>
|
||||
static bool tryOrAlert(Result<T> const& res, const char* title) {
|
||||
if (!res) {
|
||||
FLAlertLayer::create(title, res.error(), "OK")->show();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
ModCell::ModCell(const char* name, CCSize size) :
|
||||
TableViewCell(name, size.width, size.height) {}
|
||||
|
@ -234,50 +243,24 @@ void ModCell::updateBGColor(int index) {
|
|||
}
|
||||
|
||||
void ModCell::onEnable(CCObject* pSender) {
|
||||
// if (!APIInternal::get()->m_shownEnableWarning) {
|
||||
// APIInternal::get()->m_shownEnableWarning = true;
|
||||
// FLAlertLayer::create(
|
||||
// "Notice",
|
||||
// "<cb>Disabling</c> a <cy>mod</c> removes its hooks & patches and "
|
||||
// "calls its user-defined disable function if one exists. You may "
|
||||
// "still see some effects of the mod left however, and you may "
|
||||
// "need to <cg>restart</c> the game to have it fully unloaded.",
|
||||
// "OK"
|
||||
// )->show();
|
||||
// m_list->updateAllStates(this);
|
||||
// return;
|
||||
// }
|
||||
if (!InternalLoader::get()->shownInfoAlert("mod-disable-vs-unload")) {
|
||||
FLAlertLayer::create(
|
||||
"Notice",
|
||||
"<cb>Disabling</c> a <cy>mod</c> removes its hooks & patches and "
|
||||
"calls its user-defined disable function if one exists. You may "
|
||||
"still see some effects of the mod left however, and you may "
|
||||
"need to <cg>restart</c> the game to have it fully unloaded.",
|
||||
"OK"
|
||||
)->show();
|
||||
m_list->updateAllStates(this);
|
||||
return;
|
||||
}
|
||||
if (!as<CCMenuItemToggler*>(pSender)->isToggled()) {
|
||||
auto res = m_obj->m_mod->load();
|
||||
if (!res) {
|
||||
FLAlertLayer::create(
|
||||
nullptr,
|
||||
"Error Loading Mod",
|
||||
res.error(),
|
||||
"OK", nullptr
|
||||
)->show();
|
||||
}
|
||||
else {
|
||||
auto res = m_obj->m_mod->enable();
|
||||
if (!res) {
|
||||
FLAlertLayer::create(
|
||||
nullptr,
|
||||
"Error Enabling Mod",
|
||||
res.error(),
|
||||
"OK", nullptr
|
||||
)->show();
|
||||
}
|
||||
if (tryOrAlert(m_obj->m_mod->enable(), "Error enabling mod")) {
|
||||
tryOrAlert(m_obj->m_mod->load(), "Error loading mod");
|
||||
}
|
||||
} else {
|
||||
auto res = m_obj->m_mod->disable();
|
||||
if (!res) {
|
||||
FLAlertLayer::create(
|
||||
nullptr,
|
||||
"Error Disabling Mod",
|
||||
res.error(),
|
||||
"OK", nullptr
|
||||
)->show();
|
||||
}
|
||||
tryOrAlert(m_obj->m_mod->disable(), "Error disabling mod");
|
||||
}
|
||||
m_list->updateAllStates(this);
|
||||
}
|
||||
|
|
|
@ -2,98 +2,48 @@
|
|||
#include "ModListLayer.hpp"
|
||||
#include "ModListView.hpp"
|
||||
|
||||
bool SearchFilterPopup::init(ModListLayer* layer) {
|
||||
this->m_noElasticity = true;
|
||||
bool SearchFilterPopup::setup(ModListLayer* layer) {
|
||||
// todo: clean this shitty ass popup up
|
||||
m_noElasticity = true;
|
||||
m_modLayer = layer;
|
||||
|
||||
this->m_modLayer = layer;
|
||||
this->setTitle("Match Fields");
|
||||
|
||||
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
CCSize size { 280.f, 250.f };
|
||||
auto pos = CCPoint { winSize.width / 2 - 55.f, winSize.height / 2 + 50.f };
|
||||
|
||||
if (!this->initWithColor({ 0, 0, 0, 105 })) return false;
|
||||
this->m_mainLayer = CCLayer::create();
|
||||
this->addChild(this->m_mainLayer);
|
||||
|
||||
auto bg = CCScale9Sprite::create("GJ_square05.png", { 0.0f, 0.0f, 80.0f, 80.0f });
|
||||
bg->setContentSize(size);
|
||||
bg->setPosition(winSize.width / 2, winSize.height / 2);
|
||||
this->m_mainLayer->addChild(bg);
|
||||
|
||||
this->m_buttonMenu = CCMenu::create();
|
||||
this->m_mainLayer->addChild(this->m_buttonMenu);
|
||||
|
||||
auto nameLabel = CCLabelBMFont::create("Search Filters", "goldFont.fnt");
|
||||
nameLabel->setPosition(winSize.width / 2, winSize.height / 2 + 100.f);
|
||||
nameLabel->setScale(.7f);
|
||||
this->m_mainLayer->addChild(nameLabel, 2);
|
||||
|
||||
this->m_pos = CCPoint { winSize.width / 2 - 45.f, 86.f };
|
||||
|
||||
this->addToggle("Name", ModListView::SearchFlags::Name);
|
||||
this->addToggle("ID", ModListView::SearchFlags::ID);
|
||||
this->addToggle("Credits", ModListView::SearchFlags::Credits);
|
||||
this->addToggle("Description", ModListView::SearchFlags::Description);
|
||||
this->addToggle("Details", ModListView::SearchFlags::Details);
|
||||
this->addToggle("Developer", ModListView::SearchFlags::Developer);
|
||||
|
||||
CCDirector::sharedDirector()->getTouchDispatcher()->incrementForcePrio(2);
|
||||
this->registerWithTouchDispatcher();
|
||||
|
||||
auto closeSpr = CCSprite::createWithSpriteFrameName("GJ_closeBtn_001.png");
|
||||
closeSpr->setScale(1.0f);
|
||||
|
||||
auto closeBtn = CCMenuItemSpriteExtra::create(
|
||||
closeSpr,
|
||||
this,
|
||||
(SEL_MenuHandler)&SearchFilterPopup::onClose
|
||||
);
|
||||
closeBtn->setUserData(reinterpret_cast<void*>(this));
|
||||
|
||||
this->m_buttonMenu->addChild(closeBtn);
|
||||
|
||||
closeBtn->setPosition( - size.width / 2, size.height / 2 );
|
||||
|
||||
this->setKeypadEnabled(true);
|
||||
this->setTouchEnabled(true);
|
||||
this->addToggle("Name", ModListView::SearchFlags::Name, pos);
|
||||
this->addToggle("ID", ModListView::SearchFlags::ID, pos);
|
||||
this->addToggle("Credits", ModListView::SearchFlags::Credits, pos);
|
||||
this->addToggle("Description", ModListView::SearchFlags::Description, pos);
|
||||
this->addToggle("Details", ModListView::SearchFlags::Details, pos);
|
||||
this->addToggle("Developer", ModListView::SearchFlags::Developer, pos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SearchFilterPopup::addToggle(const char* title, int flag) {
|
||||
void SearchFilterPopup::addToggle(const char* title, int flag, CCPoint& pos) {
|
||||
GameToolbox::createToggleButton(
|
||||
title, menu_selector(SearchFilterPopup::onToggle),
|
||||
this->m_modLayer->m_searchFlags & flag,
|
||||
this->m_buttonMenu, this->m_pos, this,
|
||||
this->m_buttonMenu, .5f, .5f, 100.f,
|
||||
m_modLayer->m_searchFlags & flag,
|
||||
m_buttonMenu, pos, this,
|
||||
m_buttonMenu, .5f, .5f, 100.f,
|
||||
{ 10.f, .0f }, nullptr, false, flag, nullptr
|
||||
)->setTag(flag);
|
||||
this->m_pos.y += 25.f;
|
||||
}
|
||||
|
||||
void SearchFilterPopup::keyDown(cocos2d::enumKeyCodes key) {
|
||||
if (key == KEY_Escape)
|
||||
return onClose(nullptr);
|
||||
if (key == KEY_Space)
|
||||
return;
|
||||
return FLAlertLayer::keyDown(key);
|
||||
}
|
||||
|
||||
void SearchFilterPopup::onClose(cocos2d::CCObject*) {
|
||||
this->setKeyboardEnabled(false);
|
||||
this->removeFromParentAndCleanup(true);
|
||||
pos.y -= 25.f;
|
||||
}
|
||||
|
||||
void SearchFilterPopup::onToggle(cocos2d::CCObject* pSender) {
|
||||
if (as<CCMenuItemToggler*>(pSender)->isToggled()) {
|
||||
this->m_modLayer->m_searchFlags &= ~pSender->getTag();
|
||||
m_modLayer->m_searchFlags &= ~pSender->getTag();
|
||||
} else {
|
||||
this->m_modLayer->m_searchFlags |= pSender->getTag();
|
||||
m_modLayer->m_searchFlags |= pSender->getTag();
|
||||
}
|
||||
}
|
||||
|
||||
SearchFilterPopup* SearchFilterPopup::create(ModListLayer* layer) {
|
||||
auto ret = new SearchFilterPopup();
|
||||
if (ret && ret->init(layer)) {
|
||||
if (ret && ret->init(200.f, 200.f, layer, "GJ_square05.png")) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1,24 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/Geode.hpp>
|
||||
#include <Geode/ui/Popup.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
class ModListLayer;
|
||||
|
||||
class SearchFilterPopup : public FLAlertLayer {
|
||||
protected:
|
||||
ModListLayer* m_modLayer;
|
||||
CCPoint m_pos;
|
||||
class SearchFilterPopup : public Popup<ModListLayer*> {
|
||||
protected:
|
||||
ModListLayer* m_modLayer;
|
||||
|
||||
bool init(ModListLayer* layer);
|
||||
void addToggle(const char* title, int flag);
|
||||
bool setup(ModListLayer* layer) override;
|
||||
void addToggle(const char* title, int flag, CCPoint& pos);
|
||||
|
||||
void keyDown(cocos2d::enumKeyCodes) override;
|
||||
void onClose(cocos2d::CCObject*);
|
||||
void onToggle(cocos2d::CCObject*);
|
||||
|
||||
public:
|
||||
static SearchFilterPopup* create(ModListLayer* layer);
|
||||
void onToggle(cocos2d::CCObject*);
|
||||
|
||||
public:
|
||||
static SearchFilterPopup* create(ModListLayer* layer);
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue