mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-27 01:45:35 -05:00
Compare commits
11 commits
0e8d4c60bc
...
9fe3d133e9
Author | SHA1 | Date | |
---|---|---|---|
|
9fe3d133e9 | ||
|
3081164600 | ||
|
bebc7b4074 | ||
|
5645399a9f | ||
|
1a201e1d65 | ||
|
5592ef68c3 | ||
|
da92090108 | ||
|
64d9a289a3 | ||
|
fb504cbf83 | ||
|
9834cb2a22 | ||
|
ecec11fa93 |
20 changed files with 217 additions and 201 deletions
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -1,15 +1,25 @@
|
|||
# Geode Changelog
|
||||
|
||||
## v4.0.0-alpha.2
|
||||
## v4.0.0-beta.1
|
||||
* Button to manually install mods from files (e881dc5)
|
||||
* Add `ModRequestedAction::Update` (e881dc5)
|
||||
* Add `ModMetadata::checkGeodeVersion` and `ModMetadata::checkTargetVersions` (e881dc5)
|
||||
* Add `geode::createModLogo` for creating a logo from a `.geode` package (e881dc5)
|
||||
* Tags now use names provided by the server (893b03e)
|
||||
* Add web support for multiple request headers with same name (#1150)
|
||||
* Fix `Task::chain` using the wrong type in the impl (22a11b9)
|
||||
* Fix installing mods not checking the current version (#1148)
|
||||
* Fix searching for mods ignoring geode and gd version (#1153)
|
||||
* Fix crash when checking tags (01807fe)
|
||||
* Fix 'Outdated' label being visible while updating (6679a69)
|
||||
* Fix log nesting issue (0e8d4c6)
|
||||
* Remove forward compat message box as it confuses users (5592ef6)
|
||||
* Fix crash on opening mod changelogs (9834cb2)
|
||||
* Make `ColorPickPopup` pimpl (1a201e1)
|
||||
* Fix lag issue in `ColorPickPopup` (3081164)
|
||||
* Change return type of `ModSettingsManager::save` (da92090)
|
||||
* Fix every misspelling of successfully (#1151)
|
||||
* Allow building geode itself in debug mode (5645399)
|
||||
|
||||
## v4.0.0-alpha.1
|
||||
* Support for the 2.2074 update
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
4.0.0-alpha.1
|
||||
4.0.0-beta.1
|
||||
|
|
|
@ -72,19 +72,27 @@ elseif (GEODE_TARGET_PLATFORM STREQUAL "Win64")
|
|||
target_link_libraries(${PROJECT_NAME} INTERFACE
|
||||
${GEODE_LOADER_PATH}/include/link/win64/libcocos2d.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/libExtensions.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/ssl.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/crypto.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/nghttp2.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/ngtcp2.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/nghttp3.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/ngtcp2_crypto_boringssl.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/libcurl.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/glew32.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/gdstring.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/fmod.lib
|
||||
opengl32
|
||||
)
|
||||
|
||||
if (PROJECT_IS_TOP_LEVEL AND CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
target_link_libraries(${PROJECT_NAME} INTERFACE
|
||||
${GEODE_LOADER_PATH}/include/link/win64/gd-libcurl.lib
|
||||
)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} INTERFACE
|
||||
${GEODE_LOADER_PATH}/include/link/win64/ssl.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/crypto.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/nghttp2.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/ngtcp2.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/nghttp3.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/ngtcp2_crypto_boringssl.lib
|
||||
${GEODE_LOADER_PATH}/include/link/win64/libcurl.lib
|
||||
)
|
||||
endif()
|
||||
|
||||
# Windows links against .lib and not .dll
|
||||
set(GEODE_OUTPUT_NAME "Geode")
|
||||
set(GEODE_PLATFORM_BINARY "Geode.lib")
|
||||
|
|
|
@ -208,9 +208,9 @@ namespace cocos2d
|
|||
|
||||
/**
|
||||
* Custom function added for geode; returns if the
|
||||
* zip file was succesfully decoded.
|
||||
* zip file was successfully decoded.
|
||||
*
|
||||
* @return true if the zip was succesfully loaded,
|
||||
* @return true if the zip was successfully loaded,
|
||||
* false otherwise.
|
||||
*
|
||||
* @since geode v1.0.0
|
||||
|
|
|
@ -40,12 +40,8 @@ namespace geode {
|
|||
* The format of the savedata will be an object with the keys being
|
||||
* setting IDs and then the values the values of the saved settings
|
||||
* @note If saving a setting fails, it will log a warning to the console
|
||||
* @warning This will overwrite the whole `json` parameter - be sure to
|
||||
* pass the full settings savedata to `load()` so you can be sure that
|
||||
* unregistered custom settings' saved values don't disappear!
|
||||
* @todo in v4: make this return the value instead lol
|
||||
*/
|
||||
void save(matjson::Value& json);
|
||||
matjson::Value save();
|
||||
|
||||
/**
|
||||
* Get the savedata for settings, aka the JSON object that contains all
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace geode {
|
|||
virtual void updateColor(cocos2d::ccColor4B const& color) {}
|
||||
};
|
||||
|
||||
// todo in v4: make this pimpl and maybe use events over the delegate?
|
||||
// todo in v4: maybe use events over the delegate?
|
||||
// thing with events is that if you just filter via ColorPickPopup* it
|
||||
// won't work unless you automatically detach the filter when closing the
|
||||
// popup (otherwise opening another popup really quickly will just be
|
||||
|
@ -24,18 +24,8 @@ namespace geode {
|
|||
public cocos2d::extension::ColorPickerDelegate,
|
||||
public TextInputDelegate {
|
||||
protected:
|
||||
cocos2d::ccColor4B m_color;
|
||||
cocos2d::ccColor4B m_originalColor;
|
||||
cocos2d::extension::CCControlColourPicker* m_picker;
|
||||
Slider* m_opacitySlider = nullptr;
|
||||
TextInput* m_rInput;
|
||||
TextInput* m_gInput;
|
||||
TextInput* m_bInput;
|
||||
TextInput* m_hexInput;
|
||||
TextInput* m_opacityInput = nullptr;
|
||||
ColorPickPopupDelegate* m_delegate = nullptr;
|
||||
cocos2d::CCSprite* m_newColorSpr;
|
||||
CCMenuItemSpriteExtra* m_resetBtn;
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
|
||||
static constexpr auto TAG_OPACITY_INPUT = 0;
|
||||
static constexpr auto TAG_R_INPUT = 1;
|
||||
|
@ -43,10 +33,13 @@ namespace geode {
|
|||
static constexpr auto TAG_B_INPUT = 3;
|
||||
static constexpr auto TAG_HEX_INPUT = 4;
|
||||
|
||||
ColorPickPopup();
|
||||
~ColorPickPopup();
|
||||
bool setup(cocos2d::ccColor4B const& color, bool isRGBA) override;
|
||||
|
||||
void onOpacitySlider(cocos2d::CCObject* sender);
|
||||
void onReset(cocos2d::CCObject* sender);
|
||||
void onClose(cocos2d::CCObject* sender) override;
|
||||
|
||||
void textChanged(CCTextInputNode* input) override;
|
||||
void colorValueChanged(cocos2d::ccColor3B color) override;
|
||||
|
|
|
@ -95,7 +95,7 @@ namespace geode {
|
|||
enum class Status {
|
||||
/// The task is still running or waiting to start
|
||||
Pending,
|
||||
/// The task has succesfully finished
|
||||
/// The task has successfully finished
|
||||
Finished,
|
||||
/// The task has been cancelled
|
||||
Cancelled,
|
||||
|
@ -1032,4 +1032,4 @@ auto operator co_await(geode::Task<T, P> task) {
|
|||
template <class T, class P, class... Args>
|
||||
struct std::coroutine_traits<geode::Task<T, P>, Args...> {
|
||||
using promise_type = geode::geode_internal::TaskPromise<T, P>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -850,7 +850,7 @@ namespace geode::cocos {
|
|||
* @param permissive If true, strings like "f" are considered valid
|
||||
* representations of the color white. Useful for UIs that allow entering
|
||||
* a hex color. Empty strings evaluate to pure white
|
||||
* @returns A ccColor3B if it could be succesfully parsed, or an error
|
||||
* @returns A ccColor3B if it could be successfully parsed, or an error
|
||||
* indicating the failure reason
|
||||
*/
|
||||
GEODE_DLL Result<cocos2d::ccColor3B> cc3bFromHexString(std::string const& hexValue, bool permissive = false);
|
||||
|
@ -863,7 +863,7 @@ namespace geode::cocos {
|
|||
* @param permissive If true, strings like "f" are considered valid
|
||||
* representations of the color white. Useful for UIs that allow entering
|
||||
* a hex color. Empty strings evaluate to pure white
|
||||
* @returns A ccColor4B if it could be succesfully parsed, or an error
|
||||
* @returns A ccColor4B if it could be successfully parsed, or an error
|
||||
* indicating the failure reason
|
||||
*/
|
||||
GEODE_DLL Result<cocos2d::ccColor4B> cc4bFromHexString(std::string const& hexValue, bool requireAlpha = false, bool permissive = false);
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "../DefaultInclude.hpp"
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
|
@ -64,9 +63,7 @@ namespace geode {
|
|||
|
||||
template <typename T>
|
||||
std::string intToHex(T i) {
|
||||
std::stringstream stream;
|
||||
stream << std::showbase << std::setbase(16) << (uint64_t)i;
|
||||
return stream.str();
|
||||
return fmt::format("{:#x}", i);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,15 +72,16 @@ namespace geode {
|
|||
* @param num Number to convert to string
|
||||
* @param precision Precision of the converted number
|
||||
* @returns Number as string
|
||||
* @note Precision has no effect on integers
|
||||
*/
|
||||
template <class Num>
|
||||
std::string numToString(Num num, size_t precision = 0) {
|
||||
std::stringstream ss;
|
||||
if (precision) {
|
||||
ss << std::fixed << std::setprecision(precision);
|
||||
if constexpr (std::is_floating_point_v<Num>) {
|
||||
if (precision) {
|
||||
return fmt::format("{:.{}f}", num, precision);
|
||||
}
|
||||
}
|
||||
ss << num;
|
||||
return ss.str();
|
||||
return fmt::to_string(num);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -83,6 +83,15 @@ namespace geode::utils::web {
|
|||
|
||||
std::vector<std::string> headers() const;
|
||||
std::optional<std::string> header(std::string_view name) const;
|
||||
|
||||
/**
|
||||
* Retrieves a list of all headers from the response with a given name - there can be
|
||||
* multiple headers with the same name, such as Set-Cookie, with each cookie in a separate
|
||||
* header
|
||||
* @param name name of the header
|
||||
* @return std::optional<std::vector<std::string>>
|
||||
*/
|
||||
std::optional<std::vector<std::string>> getAllHeadersNamed(std::string_view name) const;
|
||||
};
|
||||
|
||||
class GEODE_DLL WebProgress final {
|
||||
|
@ -286,9 +295,9 @@ namespace geode::utils::web {
|
|||
/**
|
||||
* Gets the request headers
|
||||
*
|
||||
* @return std::unordered_map<std::string, std::string>
|
||||
* @return std::unordered_map<std::string, std::vector<std::string>>
|
||||
*/
|
||||
std::unordered_map<std::string, std::string> getHeaders() const;
|
||||
std::unordered_map<std::string, std::vector<std::string>> getHeaders() const;
|
||||
|
||||
/**
|
||||
* Gets the parameters inside the URL
|
||||
|
|
BIN
loader/include/link/win64/gd-libcurl.lib
Normal file
BIN
loader/include/link/win64/gd-libcurl.lib
Normal file
Binary file not shown.
Binary file not shown.
|
@ -67,13 +67,13 @@ void tryShowForwardCompat() {
|
|||
return;
|
||||
|
||||
// TODO: change text later
|
||||
console::messageBox(
|
||||
"Forward Compatibility Warning",
|
||||
"Geode is running in a newer version of GD than Geode targets.\n"
|
||||
"UI is going to be disabled, platform console is forced on and crashes can be more common.\n"
|
||||
"However, if your game crashes, it is probably caused by an outdated mod and not Geode itself.",
|
||||
Severity::Warning
|
||||
);
|
||||
// console::messageBox(
|
||||
// "Forward Compatibility Warning",
|
||||
// "Geode is running in a newer version of GD than Geode targets.\n"
|
||||
// "UI is going to be disabled, platform console is forced on and crashes can be more common.\n"
|
||||
// "However, if your game crashes, it is probably caused by an outdated mod and not Geode itself.",
|
||||
// Severity::Warning
|
||||
// );
|
||||
|
||||
Mod::get()->setSavedValue<std::string>(
|
||||
"last-forward-compat-warn-popup-ver",
|
||||
|
|
|
@ -1073,7 +1073,7 @@ void Loader::Impl::installModManuallyFromFile(std::filesystem::path const& path,
|
|||
createQuickPopup(
|
||||
"Mod Installed",
|
||||
fmt::format(
|
||||
"Mod <co>{}</c> has been succesfully installed from file! "
|
||||
"Mod <co>{}</c> has been successfully installed from file! "
|
||||
"<cy>Do you want to delete the original file?</c>",
|
||||
meta.getName()
|
||||
),
|
||||
|
@ -1092,7 +1092,7 @@ void Loader::Impl::installModManuallyFromFile(std::filesystem::path const& path,
|
|||
"OK"
|
||||
)->show();
|
||||
}
|
||||
// No need to show a confirmation popup if succesful since that's
|
||||
// No need to show a confirmation popup if successful since that's
|
||||
// to be assumed via pressing the button on the previous popup
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,8 +210,7 @@ Result<> Mod::Impl::saveData() {
|
|||
}
|
||||
|
||||
// ModSettingsManager keeps track of the whole savedata
|
||||
matjson::Value json;
|
||||
m_settings->save(json);
|
||||
matjson::Value json = m_settings->save();
|
||||
|
||||
// saveData is expected to be synchronous, and always called from GD thread
|
||||
ModStateEvent(m_self, ModEventType::DataSaved).post();
|
||||
|
|
|
@ -214,12 +214,12 @@ Result<> ModSettingsManager::load(matjson::Value const& json) {
|
|||
}
|
||||
return Ok();
|
||||
}
|
||||
void ModSettingsManager::save(matjson::Value& json) {
|
||||
matjson::Value ModSettingsManager::save() {
|
||||
for (auto& [key, _] : m_impl->settings) {
|
||||
m_impl->saveSettingValueToSave(key);
|
||||
}
|
||||
// Doing this since `ModSettingsManager` is expected to manage savedata fully
|
||||
json = m_impl->savedata;
|
||||
return m_impl->savedata;
|
||||
}
|
||||
matjson::Value& ModSettingsManager::getSaveData() {
|
||||
return m_impl->savedata;
|
||||
|
|
|
@ -256,7 +256,7 @@ std::optional<ModDownload> ModDownloadManager::startDownload(
|
|||
std::optional<DependencyFor> const& dependencyFor,
|
||||
std::optional<std::string> const& replacesMod
|
||||
) {
|
||||
// If this mod has already been succesfully downloaded or is currently
|
||||
// If this mod has already been successfully downloaded or is currently
|
||||
// being downloaded, return as you can't download multiple versions of the
|
||||
// same mod simultaniously, since that wouldn't make sense. I mean the new
|
||||
// version would just immediately override to the other one
|
||||
|
|
|
@ -51,11 +51,16 @@ protected:
|
|||
}
|
||||
|
||||
void onRequest(Request::Event* event) {
|
||||
if (event->getValue() && event->getValue()->isOk() && event->getValue()->inspect([](auto&& value) { return value.has_value(); })) {
|
||||
m_loading->removeFromParent();
|
||||
m_textarea->setString(event->getValue()->unwrap()->c_str());
|
||||
if (auto* res = event->getValue(); res && res->isOk()) {
|
||||
auto value = std::move(*res).unwrap();
|
||||
if (value) {
|
||||
m_loading->removeFromParent();
|
||||
std::string str = std::move(value).value();
|
||||
m_textarea->setString(str.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!event->getProgress()) {
|
||||
if (!event->getProgress()) {
|
||||
m_loading->removeFromParent();
|
||||
m_textarea->setString(m_noneText.c_str());
|
||||
}
|
||||
|
|
|
@ -10,59 +10,33 @@
|
|||
|
||||
using namespace geode::prelude;
|
||||
|
||||
// class ColorPickPopupEvent::Impl final {
|
||||
// public:
|
||||
// ColorPickPopup* popup;
|
||||
// ccColor4B color;
|
||||
// bool closed = false;
|
||||
// };
|
||||
class ColorPickPopup::Impl final {
|
||||
public:
|
||||
cocos2d::ccColor4B m_color;
|
||||
cocos2d::ccColor4B m_originalColor;
|
||||
cocos2d::extension::CCControlColourPicker* m_picker;
|
||||
Slider* m_opacitySlider = nullptr;
|
||||
TextInput* m_rInput;
|
||||
TextInput* m_gInput;
|
||||
TextInput* m_bInput;
|
||||
TextInput* m_hexInput;
|
||||
TextInput* m_opacityInput = nullptr;
|
||||
ColorPickPopupDelegate* m_delegate = nullptr;
|
||||
cocos2d::CCSprite* m_newColorSpr;
|
||||
CCMenuItemSpriteExtra* m_resetBtn;
|
||||
};
|
||||
|
||||
// ColorPickPopupEvent::ColorPickPopupEvent(ColorPickPopup* popup, ccColor4B const& color)
|
||||
// : m_impl(std::make_shared<Impl>())
|
||||
// {
|
||||
// m_impl->popup = popup;
|
||||
// m_impl->color = color;
|
||||
// }
|
||||
// ColorPickPopupEvent::~ColorPickPopupEvent() = default;
|
||||
ColorPickPopup::ColorPickPopup() {
|
||||
m_impl = std::make_unique<Impl>();
|
||||
}
|
||||
|
||||
// ColorPickPopup* ColorPickPopupEvent::getPopup() const {
|
||||
// return m_impl->popup;
|
||||
// }
|
||||
// ccColor4B ColorPickPopupEvent::getColor() const {
|
||||
// return m_impl->color;
|
||||
// }
|
||||
// bool ColorPickPopupEvent::isPopupClosed() const {
|
||||
// return m_impl->closed;
|
||||
// }
|
||||
ColorPickPopup::~ColorPickPopup() {}
|
||||
|
||||
// class ColorPickPopupEventFilter::Impl final {
|
||||
// public:
|
||||
// ColorPickPopup* popup;
|
||||
// };
|
||||
|
||||
// ListenerResult ColorPickPopupEventFilter::handle(std::function<Callback> fn, ColorPickPopupEvent* event) {
|
||||
// if (event->getPopup() == m_impl->popup) {
|
||||
// if (event->isPopupClosed()) {
|
||||
// m_impl->popup = nullptr;
|
||||
// }
|
||||
// else {
|
||||
// fn(event);
|
||||
// }
|
||||
// }
|
||||
// return ListenerResult::Propagate;
|
||||
// }
|
||||
// ColorPickPopupEventFilter::ColorPickPopupEventFilter() : ColorPickPopupEventFilter(nullptr) {}
|
||||
// ColorPickPopupEventFilter::ColorPickPopupEventFilter(ColorPickPopup* popup)
|
||||
// : m_impl(std::make_shared<Impl>())
|
||||
// {
|
||||
// m_impl->popup = popup;
|
||||
// }
|
||||
// ColorPickPopupEventFilter::~ColorPickPopupEventFilter() = default;
|
||||
|
||||
bool ColorPickPopup::setup(ccColor4B const& color, bool isRGBA) {
|
||||
m_noElasticity = true;
|
||||
m_color = color;
|
||||
m_originalColor = color;
|
||||
m_impl->m_color = color;
|
||||
m_impl->m_originalColor = color;
|
||||
|
||||
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
|
||||
|
@ -115,25 +89,25 @@ bool ColorPickPopup::setup(ccColor4B const& color, bool isRGBA) {
|
|||
|
||||
// picker
|
||||
|
||||
m_picker = CCControlColourPicker::colourPicker();
|
||||
m_picker->setDelegate(this);
|
||||
m_picker->setID("color-picker");
|
||||
m_impl->m_picker = CCControlColourPicker::colourPicker();
|
||||
m_impl->m_picker->setDelegate(this);
|
||||
m_impl->m_picker->setID("color-picker");
|
||||
|
||||
auto pickerWrapper = CCNode::create();
|
||||
pickerWrapper->setContentSize(m_picker->getContentSize());
|
||||
pickerWrapper->setContentSize(m_impl->m_picker->getContentSize());
|
||||
pickerWrapper->setID("picker-wrapper");
|
||||
pickerWrapper->addChildAtPosition(m_picker, Anchor::Center, ccp(0, 0));
|
||||
pickerWrapper->addChildAtPosition(m_impl->m_picker, Anchor::Center, ccp(0, 0));
|
||||
pickerRow->addChild(pickerWrapper);
|
||||
|
||||
auto oldColorSpr = CCSprite::createWithSpriteFrameName("whiteSquare60_001.png");
|
||||
oldColorSpr->setColor(to3B(m_color));
|
||||
oldColorSpr->setColor(to3B(m_impl->m_color));
|
||||
oldColorSpr->setID("old-color-spr");
|
||||
colorMenu->addChild(oldColorSpr);
|
||||
|
||||
m_newColorSpr = CCSprite::createWithSpriteFrameName("whiteSquare60_001.png");
|
||||
m_newColorSpr->setColor(to3B(m_color));
|
||||
m_newColorSpr->setID("new-color-spr");
|
||||
colorMenu->addChild(m_newColorSpr);
|
||||
m_impl->m_newColorSpr = CCSprite::createWithSpriteFrameName("whiteSquare60_001.png");
|
||||
m_impl->m_newColorSpr->setColor(to3B(m_impl->m_color));
|
||||
m_impl->m_newColorSpr->setID("new-color-spr");
|
||||
colorMenu->addChild(m_impl->m_newColorSpr);
|
||||
|
||||
auto resetBtnSpr = ButtonSprite::create(
|
||||
CCSprite::createWithSpriteFrameName("reset-gold.png"_spr), 0x20, true, 0.f,
|
||||
|
@ -141,16 +115,16 @@ bool ColorPickPopup::setup(ccColor4B const& color, bool isRGBA) {
|
|||
);
|
||||
resetBtnSpr->setScale(.6f);
|
||||
|
||||
m_resetBtn =
|
||||
m_impl->m_resetBtn =
|
||||
CCMenuItemSpriteExtra::create(resetBtnSpr, this, menu_selector(ColorPickPopup::onReset));
|
||||
m_resetBtn->setPosition({ -165.f, -50.f });
|
||||
m_resetBtn->setLayoutOptions(
|
||||
m_impl->m_resetBtn->setPosition({ -165.f, -50.f });
|
||||
m_impl->m_resetBtn->setLayoutOptions(
|
||||
AxisLayoutOptions::create()
|
||||
->setPrevGap(10.f)
|
||||
->setNextGap(10.f)
|
||||
);
|
||||
m_resetBtn->setID("reset-btn");
|
||||
colorMenu->addChild(m_resetBtn);
|
||||
m_impl->m_resetBtn->setID("reset-btn");
|
||||
colorMenu->addChild(m_impl->m_resetBtn);
|
||||
|
||||
|
||||
|
||||
|
@ -194,11 +168,11 @@ bool ColorPickPopup::setup(ccColor4B const& color, bool isRGBA) {
|
|||
rText->setID("r-text");
|
||||
rColumn->addChild(rText);
|
||||
|
||||
m_rInput = TextInput::create(50.f, "R");
|
||||
m_rInput->setScale(.7f);
|
||||
m_rInput->setDelegate(this, TAG_R_INPUT);
|
||||
m_rInput->setID("r-input");
|
||||
rColumn->addChild(m_rInput);
|
||||
m_impl->m_rInput = TextInput::create(50.f, "R");
|
||||
m_impl->m_rInput->setScale(.7f);
|
||||
m_impl->m_rInput->setDelegate(this, TAG_R_INPUT);
|
||||
m_impl->m_rInput->setID("r-input");
|
||||
rColumn->addChild(m_impl->m_rInput);
|
||||
|
||||
rColumn->updateLayout();
|
||||
auto rRect = calculateChildCoverage(rColumn);
|
||||
|
@ -223,11 +197,11 @@ bool ColorPickPopup::setup(ccColor4B const& color, bool isRGBA) {
|
|||
gText->setID("g-text");
|
||||
gColumn->addChild(gText);
|
||||
|
||||
m_gInput = TextInput::create(50.f, "G");
|
||||
m_gInput->setScale(.7f);
|
||||
m_gInput->setDelegate(this, TAG_G_INPUT);
|
||||
m_gInput->setID("g-input");
|
||||
gColumn->addChild(m_gInput);
|
||||
m_impl->m_gInput = TextInput::create(50.f, "G");
|
||||
m_impl->m_gInput->setScale(.7f);
|
||||
m_impl->m_gInput->setDelegate(this, TAG_G_INPUT);
|
||||
m_impl->m_gInput->setID("g-input");
|
||||
gColumn->addChild(m_impl->m_gInput);
|
||||
|
||||
gColumn->updateLayout();
|
||||
auto gRect = calculateChildCoverage(gColumn);
|
||||
|
@ -252,11 +226,11 @@ bool ColorPickPopup::setup(ccColor4B const& color, bool isRGBA) {
|
|||
bText->setID("b-text");
|
||||
bColumn->addChild(bText);
|
||||
|
||||
m_bInput = TextInput::create(50.f, "B");
|
||||
m_bInput->setScale(.7f);
|
||||
m_bInput->setDelegate(this, TAG_B_INPUT);
|
||||
m_bInput->setID("b-input");
|
||||
bColumn->addChild(m_bInput);
|
||||
m_impl->m_bInput = TextInput::create(50.f, "B");
|
||||
m_impl->m_bInput->setScale(.7f);
|
||||
m_impl->m_bInput->setDelegate(this, TAG_B_INPUT);
|
||||
m_impl->m_bInput->setID("b-input");
|
||||
bColumn->addChild(m_impl->m_bInput);
|
||||
|
||||
bColumn->updateLayout();
|
||||
auto bRect = calculateChildCoverage(bColumn);
|
||||
|
@ -281,11 +255,11 @@ bool ColorPickPopup::setup(ccColor4B const& color, bool isRGBA) {
|
|||
hexText->setID("hex-text");
|
||||
hexColumn->addChild(hexText);
|
||||
|
||||
m_hexInput = TextInput::create(165.f, "Hex");
|
||||
m_hexInput->setScale(.7f);
|
||||
m_hexInput->setDelegate(this, TAG_HEX_INPUT);
|
||||
m_hexInput->setID("hex-input");
|
||||
hexColumn->addChild(m_hexInput);
|
||||
m_impl->m_hexInput = TextInput::create(165.f, "Hex");
|
||||
m_impl->m_hexInput->setScale(.7f);
|
||||
m_impl->m_hexInput->setDelegate(this, TAG_HEX_INPUT);
|
||||
m_impl->m_hexInput->setID("hex-input");
|
||||
hexColumn->addChild(m_impl->m_hexInput);
|
||||
|
||||
hexColumn->updateLayout();
|
||||
rgbRow->updateLayout();
|
||||
|
@ -324,22 +298,22 @@ bool ColorPickPopup::setup(ccColor4B const& color, bool isRGBA) {
|
|||
opacityText->setID("opacity-text");
|
||||
sliderColumn->addChild(opacityText);
|
||||
|
||||
m_opacitySlider =
|
||||
m_impl->m_opacitySlider =
|
||||
Slider::create(this, menu_selector(ColorPickPopup::onOpacitySlider), .75f);
|
||||
m_opacitySlider->setValue(color.a / 255.f);
|
||||
m_opacitySlider->setID("opacity-slider");
|
||||
m_impl->m_opacitySlider->setValue(color.a / 255.f);
|
||||
m_impl->m_opacitySlider->setID("opacity-slider");
|
||||
|
||||
auto sliderWrapper = CCNode::create();
|
||||
sliderWrapper->setContentSize(ccp(m_opacitySlider->m_width, m_opacitySlider->m_height) * .75f);
|
||||
sliderWrapper->setContentSize(ccp(m_impl->m_opacitySlider->m_width, m_impl->m_opacitySlider->m_height) * .75f);
|
||||
sliderWrapper->setID("slider-wrapper");
|
||||
sliderWrapper->addChildAtPosition(m_opacitySlider, Anchor::Center, ccp(0, 0));
|
||||
sliderWrapper->addChildAtPosition(m_impl->m_opacitySlider, Anchor::Center, ccp(0, 0));
|
||||
sliderColumn->addChild(sliderWrapper);
|
||||
|
||||
m_opacityInput = TextInput::create(60.f, "Opacity");
|
||||
m_opacityInput->setScale(.7f);
|
||||
m_opacityInput->setDelegate(this, TAG_OPACITY_INPUT);
|
||||
m_opacityInput->setID("opacity-input");
|
||||
opacitySection->addChild(m_opacityInput);
|
||||
m_impl->m_opacityInput = TextInput::create(60.f, "Opacity");
|
||||
m_impl->m_opacityInput->setScale(.7f);
|
||||
m_impl->m_opacityInput->setDelegate(this, TAG_OPACITY_INPUT);
|
||||
m_impl->m_opacityInput->setID("opacity-input");
|
||||
opacitySection->addChild(m_impl->m_opacityInput);
|
||||
|
||||
sliderColumn->updateLayout();
|
||||
opacitySection->updateLayout();
|
||||
|
@ -361,75 +335,79 @@ bool ColorPickPopup::setup(ccColor4B const& color, bool isRGBA) {
|
|||
}
|
||||
|
||||
void ColorPickPopup::updateState(CCNode* except) {
|
||||
#define IF_NOT_EXCEPT(inp, value) \
|
||||
if (inp->getInputNode() != except) { \
|
||||
inp->setString(value, false); \
|
||||
}
|
||||
#define IF_NOT_EXCEPT(inp, value) \
|
||||
if (inp->getInputNode() != except) { \
|
||||
inp->setString(value, false); \
|
||||
}
|
||||
|
||||
IF_NOT_EXCEPT(m_rInput, numToString<int>(m_color.r));
|
||||
IF_NOT_EXCEPT(m_gInput, numToString<int>(m_color.g));
|
||||
IF_NOT_EXCEPT(m_bInput, numToString<int>(m_color.b));
|
||||
IF_NOT_EXCEPT(m_hexInput, cc3bToHexString(to3B(m_color)));
|
||||
if (m_opacityInput) {
|
||||
IF_NOT_EXCEPT(m_opacityInput, numToString(m_color.a / 255.f, 2));
|
||||
IF_NOT_EXCEPT(m_impl->m_rInput, numToString<int>(m_impl->m_color.r));
|
||||
IF_NOT_EXCEPT(m_impl->m_gInput, numToString<int>(m_impl->m_color.g));
|
||||
IF_NOT_EXCEPT(m_impl->m_bInput, numToString<int>(m_impl->m_color.b));
|
||||
IF_NOT_EXCEPT(m_impl->m_hexInput, cc3bToHexString(to3B(m_impl->m_color)));
|
||||
if (m_impl->m_opacityInput) {
|
||||
IF_NOT_EXCEPT(m_impl->m_opacityInput, numToString(m_impl->m_color.a / 255.f, 2));
|
||||
}
|
||||
if (m_opacitySlider) {
|
||||
m_opacitySlider->setValue(m_color.a / 255.f);
|
||||
if (m_impl->m_opacitySlider) {
|
||||
m_impl->m_opacitySlider->setValue(m_impl->m_color.a / 255.f);
|
||||
}
|
||||
if (m_picker != except) {
|
||||
m_picker->setDelegate(nullptr);
|
||||
m_picker->setColorValue(to3B(m_color));
|
||||
m_picker->setDelegate(this);
|
||||
}
|
||||
m_resetBtn->setVisible(m_originalColor != m_color);
|
||||
m_newColorSpr->setColor(to3B(m_color));
|
||||
if (m_delegate) {
|
||||
m_delegate->updateColor(m_color);
|
||||
if (m_impl->m_picker != except) {
|
||||
m_impl->m_picker->setDelegate(nullptr);
|
||||
m_impl->m_picker->setColorValue(to3B(m_impl->m_color));
|
||||
m_impl->m_picker->setDelegate(this);
|
||||
}
|
||||
m_impl->m_resetBtn->setVisible(m_impl->m_originalColor != m_impl->m_color);
|
||||
m_impl->m_newColorSpr->setColor(to3B(m_impl->m_color));
|
||||
}
|
||||
|
||||
void ColorPickPopup::onOpacitySlider(CCObject* sender) {
|
||||
m_color.a = static_cast<GLubyte>(static_cast<SliderThumb*>(sender)->getValue() * 255.f);
|
||||
m_impl->m_color.a = static_cast<GLubyte>(static_cast<SliderThumb*>(sender)->getValue() * 255.f);
|
||||
this->updateState();
|
||||
}
|
||||
|
||||
void ColorPickPopup::onReset(CCObject*) {
|
||||
m_color = m_originalColor;
|
||||
m_impl->m_color = m_impl->m_originalColor;
|
||||
this->updateState();
|
||||
}
|
||||
|
||||
void ColorPickPopup::onClose(CCObject* sender) {
|
||||
if (m_impl->m_delegate) {
|
||||
m_impl->m_delegate->updateColor(m_impl->m_color);
|
||||
}
|
||||
Popup::onClose(sender);
|
||||
}
|
||||
|
||||
void ColorPickPopup::textChanged(CCTextInputNode* input) {
|
||||
if (input->getString().size()) {
|
||||
switch (input->getTag()) {
|
||||
case TAG_HEX_INPUT:
|
||||
{
|
||||
if (auto color = cc3bFromHexString(input->getString(), true)) {
|
||||
m_color.r = color.unwrap().r;
|
||||
m_color.g = color.unwrap().g;
|
||||
m_color.b = color.unwrap().b;
|
||||
m_impl->m_color.r = color.unwrap().r;
|
||||
m_impl->m_color.g = color.unwrap().g;
|
||||
m_impl->m_color.b = color.unwrap().b;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TAG_OPACITY_INPUT: {
|
||||
auto res = numFromString<float>(input->getString().c_str());
|
||||
if (res) m_color.a = std::clamp(static_cast<int>(res.unwrap() * 255.f), 0, 255);
|
||||
if (res) m_impl->m_color.a = std::clamp(static_cast<int>(res.unwrap() * 255.f), 0, 255);
|
||||
break;
|
||||
}
|
||||
|
||||
case TAG_R_INPUT: {
|
||||
auto res = numFromString<uint32_t>(input->getString().c_str());
|
||||
if (res) m_color.r = std::clamp(res.unwrap(), 0u, 255u);
|
||||
if (res) m_impl->m_color.r = std::clamp(res.unwrap(), 0u, 255u);
|
||||
break;
|
||||
}
|
||||
case TAG_G_INPUT: {
|
||||
auto res = numFromString<uint32_t>(input->getString().c_str());
|
||||
if (res) m_color.g = std::clamp(res.unwrap(), 0u, 255u);
|
||||
if (res) m_impl->m_color.g = std::clamp(res.unwrap(), 0u, 255u);
|
||||
break;
|
||||
}
|
||||
case TAG_B_INPUT: {
|
||||
auto res = numFromString<uint32_t>(input->getString().c_str());
|
||||
if (res) m_color.b = std::clamp(res.unwrap(), 0u, 255u);
|
||||
if (res) m_impl->m_color.b = std::clamp(res.unwrap(), 0u, 255u);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -440,18 +418,18 @@ void ColorPickPopup::textChanged(CCTextInputNode* input) {
|
|||
}
|
||||
|
||||
void ColorPickPopup::colorValueChanged(ccColor3B color) {
|
||||
m_color.r = color.r;
|
||||
m_color.g = color.g;
|
||||
m_color.b = color.b;
|
||||
this->updateState(m_picker);
|
||||
m_impl->m_color.r = color.r;
|
||||
m_impl->m_color.g = color.g;
|
||||
m_impl->m_color.b = color.b;
|
||||
this->updateState(m_impl->m_picker);
|
||||
}
|
||||
|
||||
void ColorPickPopup::setDelegate(ColorPickPopupDelegate* delegate) {
|
||||
m_delegate = delegate;
|
||||
m_impl->m_delegate = delegate;
|
||||
}
|
||||
|
||||
void ColorPickPopup::setColorTarget(cocos2d::CCSprite* spr) {
|
||||
m_picker->setColorTarget(spr);
|
||||
m_impl->m_picker->setColorTarget(spr);
|
||||
}
|
||||
|
||||
ColorPickPopup* ColorPickPopup::create(ccColor4B const& color, bool isRGBA) {
|
||||
|
|
|
@ -96,7 +96,7 @@ class WebResponse::Impl {
|
|||
public:
|
||||
int m_code;
|
||||
ByteVector m_data;
|
||||
std::unordered_map<std::string, std::string> m_headers;
|
||||
std::unordered_map<std::string, std::vector<std::string>> m_headers;
|
||||
|
||||
Result<> into(std::filesystem::path const& path) const;
|
||||
};
|
||||
|
@ -146,8 +146,14 @@ std::vector<std::string> WebResponse::headers() const {
|
|||
}
|
||||
|
||||
std::optional<std::string> WebResponse::header(std::string_view name) const {
|
||||
auto str = std::string(name);
|
||||
if (m_impl->m_headers.contains(str)) {
|
||||
if (auto str = std::string(name); m_impl->m_headers.contains(str)) {
|
||||
return m_impl->m_headers.at(str).at(0);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::vector<std::string>> WebResponse::getAllHeadersNamed(std::string_view name) const {
|
||||
if (auto str = std::string(name); m_impl->m_headers.contains(str)) {
|
||||
return m_impl->m_headers.at(str);
|
||||
}
|
||||
return std::nullopt;
|
||||
|
@ -189,7 +195,7 @@ public:
|
|||
|
||||
std::string m_method;
|
||||
std::string m_url;
|
||||
std::unordered_map<std::string, std::string> m_headers;
|
||||
std::unordered_map<std::string, std::vector<std::string>> m_headers;
|
||||
std::unordered_map<std::string, std::string> m_urlParameters;
|
||||
std::optional<std::string> m_userAgent;
|
||||
std::optional<std::string> m_acceptEncodingType;
|
||||
|
@ -270,15 +276,17 @@ WebTask WebRequest::send(std::string_view method, std::string_view url) {
|
|||
|
||||
// Set headers
|
||||
curl_slist* headers = nullptr;
|
||||
for (auto& [name, value] : impl->m_headers) {
|
||||
for (auto& [name, values] : impl->m_headers) {
|
||||
// Sanitize header name
|
||||
auto header = name;
|
||||
header.erase(std::remove_if(header.begin(), header.end(), [](char c) {
|
||||
return c == '\r' || c == '\n';
|
||||
}), header.end());
|
||||
// Append value
|
||||
header += ": " + value;
|
||||
headers = curl_slist_append(headers, header.c_str());
|
||||
for (const auto& value: values) {
|
||||
header += ": " + value;
|
||||
headers = curl_slist_append(headers, header.c_str());
|
||||
}
|
||||
}
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
|
||||
|
@ -406,7 +414,12 @@ WebTask WebRequest::send(std::string_view method, std::string_view url) {
|
|||
if (value.ends_with('\r')) {
|
||||
value = value.substr(0, value.size() - 1);
|
||||
}
|
||||
headers.insert_or_assign(key, value);
|
||||
// Create a new vector and add to it or add to an already existing one
|
||||
if (headers.contains(key)) {
|
||||
headers.at(key).push_back(value);
|
||||
} else {
|
||||
headers.insert_or_assign(key, std::vector{value});
|
||||
}
|
||||
}
|
||||
return size * nitems;
|
||||
}));
|
||||
|
@ -508,7 +521,14 @@ WebRequest& WebRequest::header(std::string_view name, std::string_view value) {
|
|||
}
|
||||
}
|
||||
|
||||
m_impl->m_headers.insert_or_assign(std::string(name), std::string(value));
|
||||
// Create a new vector and add to it or add to an already existing one
|
||||
std::string strName = std::string(name);
|
||||
std::string strValue = std::string(value);
|
||||
if (m_impl->m_headers.contains(strName)) {
|
||||
m_impl->m_headers.at(strName).push_back(strValue);
|
||||
} else {
|
||||
m_impl->m_headers.insert_or_assign(strName, std::vector{strValue});
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -609,7 +629,7 @@ std::string WebRequest::getUrl() const {
|
|||
return m_impl->m_url;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> WebRequest::getHeaders() const {
|
||||
std::unordered_map<std::string, std::vector<std::string>> WebRequest::getHeaders() const {
|
||||
return m_impl->m_headers;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue