mirror of
https://github.com/geode-sdk/geode.git
synced 2025-03-23 03:15:58 -04:00
now with color settings
This commit is contained in:
parent
25fb983cb4
commit
19293e2fdf
9 changed files with 525 additions and 10 deletions
loader
include/Geode
src
test/dependency
|
@ -7,6 +7,7 @@
|
|||
#include "../utils/json.hpp"
|
||||
#include "../utils/Result.hpp"
|
||||
#include "../utils/JsonValidation.hpp"
|
||||
#include "../utils/convert.hpp"
|
||||
#include <regex>
|
||||
|
||||
namespace geode {
|
||||
|
@ -394,6 +395,22 @@ namespace geode {
|
|||
SettingNode* createNode(float width) override;
|
||||
};
|
||||
|
||||
class GEODE_DLL ColorSetting :
|
||||
public GeodeSetting<ColorSetting, cocos2d::ccColor3B, SettingType::Color>,
|
||||
public std::enable_shared_from_this<ColorSetting>
|
||||
{
|
||||
public:
|
||||
SettingNode* createNode(float width) override;
|
||||
};
|
||||
|
||||
class GEODE_DLL ColorAlphaSetting :
|
||||
public GeodeSetting<ColorAlphaSetting, cocos2d::ccColor4B, SettingType::ColorAlpha>,
|
||||
public std::enable_shared_from_this<ColorAlphaSetting>
|
||||
{
|
||||
public:
|
||||
SettingNode* createNode(float width) override;
|
||||
};
|
||||
|
||||
// these can't be member functions because C++ is single-pass >:(
|
||||
|
||||
#define GEODE_INT_BUILTIN_SETTING_IF(type, action, ...) \
|
||||
|
|
|
@ -51,6 +51,9 @@ namespace geode {
|
|||
}
|
||||
|
||||
bool jsonConvertibleTo(value_t value, value_t to) {
|
||||
// if we don't know the type we're passing into,
|
||||
// everything's valid
|
||||
if (to == value_t::null) return true;
|
||||
if (
|
||||
value == value_t::number_float ||
|
||||
value == value_t::number_integer ||
|
||||
|
|
|
@ -2,6 +2,15 @@
|
|||
|
||||
#include <cocos2d.h>
|
||||
#include "general.hpp"
|
||||
#include "json.hpp"
|
||||
|
||||
// support converting ccColor3B / ccColor4B to / from json
|
||||
namespace cocos2d {
|
||||
void GEODE_DLL to_json(nlohmann::json& json, cocos2d::ccColor3B const& color);
|
||||
void GEODE_DLL from_json(nlohmann::json const& json, cocos2d::ccColor3B& color);
|
||||
void GEODE_DLL to_json(nlohmann::json& json, cocos2d::ccColor4B const& color);
|
||||
void GEODE_DLL from_json(nlohmann::json const& json, cocos2d::ccColor4B& color);
|
||||
}
|
||||
|
||||
namespace geode::cocos {
|
||||
inline void ccDrawColor4B(cocos2d::ccColor4B const& color) {
|
||||
|
@ -81,6 +90,11 @@ namespace geode::cocos {
|
|||
};
|
||||
}
|
||||
|
||||
GEODE_DLL Result<cocos2d::ccColor3B> cc3bFromHexString(std::string const& hexValue);
|
||||
GEODE_DLL Result<cocos2d::ccColor4B> cc4bFromHexString(std::string const& hexValue);
|
||||
GEODE_DLL std::string cc3bToHexString(cocos2d::ccColor3B const& color);
|
||||
GEODE_DLL std::string cc4bToHexString(cocos2d::ccColor4B const& color);
|
||||
|
||||
template<typename T,
|
||||
typename = std::enable_if_t<std::is_pointer_v<T>> >
|
||||
static cocos2d::CCArray* vectorToCCArray(std::vector<T> const& vec) {
|
||||
|
|
|
@ -60,5 +60,22 @@ namespace geode::utils {
|
|||
return stream.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a number into a string, with support for specifying precision
|
||||
* (unlike std::to_string).
|
||||
* @param num Number to convert to string
|
||||
* @param precision Precision of the converted number
|
||||
* @returns Number as string
|
||||
*/
|
||||
template<class Num>
|
||||
std::string numToString(Num num, size_t precision = 0) {
|
||||
std::stringstream ss;
|
||||
if (precision) {
|
||||
ss << std::fixed << std::setprecision(precision);
|
||||
}
|
||||
ss << num;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
GEODE_DLL std::string timePointAsString(const std::chrono::system_clock::time_point& tp);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ Result<std::shared_ptr<Setting>> Setting::parse(
|
|||
case hash("int"): return IntSetting::parse(key, obj);
|
||||
case hash("float"): return FloatSetting::parse(key, obj);
|
||||
case hash("string"): return StringSetting::parse(key, obj);
|
||||
case hash("color"): return ColorSetting::parse(key, obj);
|
||||
case hash("rgba"): return ColorAlphaSetting::parse(key, obj);
|
||||
default: return Err(
|
||||
"Setting \"" + key + "\" has unknown type \"" + type + "\""
|
||||
);
|
||||
|
@ -64,3 +66,11 @@ SettingNode* FloatSetting::createNode(float width) {
|
|||
SettingNode* StringSetting::createNode(float width) {
|
||||
return StringSettingNode::create(shared_from_this(), width);
|
||||
}
|
||||
|
||||
SettingNode* ColorSetting::createNode(float width) {
|
||||
return ColorSettingNode::create(shared_from_this(), width);
|
||||
}
|
||||
|
||||
SettingNode* ColorAlphaSetting::createNode(float width) {
|
||||
return ColorAlphaSettingNode::create(shared_from_this(), width);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "GeodeSettingNode.hpp"
|
||||
|
||||
// BoolSettingNode
|
||||
|
||||
void BoolSettingNode::valueChanged(bool updateText) {
|
||||
GeodeSettingNode::valueChanged(updateText);
|
||||
m_toggle->toggle(m_uncommittedValue);
|
||||
|
@ -15,13 +17,15 @@ bool BoolSettingNode::setup(std::shared_ptr<BoolSetting> setting, float width) {
|
|||
m_toggle = CCMenuItemToggler::createWithStandardSprites(
|
||||
this, menu_selector(BoolSettingNode::onToggle), .6f
|
||||
);
|
||||
m_toggle->setPosition(-10.f, .0f);
|
||||
m_toggle->toggle(m_uncommittedValue);
|
||||
m_toggle->setPositionX(-10.f);
|
||||
m_menu->addChild(m_toggle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// IntSettingNode
|
||||
|
||||
float IntSettingNode::setupHeight(std::shared_ptr<IntSetting> setting) const {
|
||||
return setting->hasSlider() ? 55.f : 40.f;
|
||||
}
|
||||
|
@ -39,6 +43,8 @@ void IntSettingNode::valueChanged(bool updateText) {
|
|||
this->updateSlider();
|
||||
}
|
||||
|
||||
// FloatSettingNode
|
||||
|
||||
float FloatSettingNode::setupHeight(std::shared_ptr<FloatSetting> setting) const {
|
||||
return setting->hasSlider() ? 55.f : 40.f;
|
||||
}
|
||||
|
@ -56,6 +62,8 @@ void FloatSettingNode::valueChanged(bool updateText) {
|
|||
this->updateSlider();
|
||||
}
|
||||
|
||||
// StringSettingNode
|
||||
|
||||
void StringSettingNode::updateLabel() {
|
||||
// hacky way to make setString not called textChanged
|
||||
m_input->getInput()->setDelegate(nullptr);
|
||||
|
@ -82,3 +90,51 @@ bool StringSettingNode::setup(std::shared_ptr<StringSetting> setting, float widt
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ColorSettingNode
|
||||
|
||||
void ColorSettingNode::valueChanged(bool updateText) {
|
||||
GeodeSettingNode::valueChanged(updateText);
|
||||
m_colorSpr->setColor(m_uncommittedValue);
|
||||
}
|
||||
|
||||
bool ColorSettingNode::setup(std::shared_ptr<ColorSetting> setting, float width) {
|
||||
m_colorSpr = ColorChannelSprite::create();
|
||||
m_colorSpr->setColor(m_uncommittedValue);
|
||||
m_colorSpr->setScale(.65f);
|
||||
|
||||
auto button = CCMenuItemSpriteExtra::create(
|
||||
m_colorSpr, this, makeMenuSelector([this](CCObject*) {
|
||||
ColorPickPopup<ColorSettingNode>::create(this)->show();
|
||||
})
|
||||
);
|
||||
button->setPositionX(-10.f);
|
||||
m_menu->addChild(button);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ColorAlphaSettingNode
|
||||
|
||||
void ColorAlphaSettingNode::valueChanged(bool updateText) {
|
||||
GeodeSettingNode::valueChanged(updateText);
|
||||
m_colorSpr->setColor(to3B(m_uncommittedValue));
|
||||
m_colorSpr->updateOpacity(m_uncommittedValue.a / 255.f);
|
||||
}
|
||||
|
||||
bool ColorAlphaSettingNode::setup(std::shared_ptr<ColorAlphaSetting> setting, float width) {
|
||||
m_colorSpr = ColorChannelSprite::create();
|
||||
m_colorSpr->setColor(to3B(m_uncommittedValue));
|
||||
m_colorSpr->updateOpacity(m_uncommittedValue.a / 255.f);
|
||||
m_colorSpr->setScale(.65f);
|
||||
|
||||
auto button = CCMenuItemSpriteExtra::create(
|
||||
m_colorSpr, this, makeMenuSelector([this](CCObject*) {
|
||||
ColorPickPopup<ColorAlphaSettingNode>::create(this)->show();
|
||||
})
|
||||
);
|
||||
button->setPositionX(-10.f);
|
||||
m_menu->addChild(button);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
template<class T>
|
||||
class ColorPickPopup;
|
||||
|
||||
namespace {
|
||||
template<class Num>
|
||||
Num parseNumForInput(std::string const& str) {
|
||||
|
@ -26,13 +29,6 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
template<class Num>
|
||||
std::string numToStringFixed(Num num) {
|
||||
std::stringstream ss;
|
||||
ss << num;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template<class N, class T>
|
||||
class GeodeSettingNode : public SettingNode {
|
||||
public:
|
||||
|
@ -255,12 +251,12 @@ namespace {
|
|||
// hacky way to make setString not called textChanged
|
||||
m_input->getInput()->setDelegate(nullptr);
|
||||
m_input->setString(
|
||||
numToStringFixed(self()->m_uncommittedValue)
|
||||
numToString(self()->m_uncommittedValue)
|
||||
);
|
||||
m_input->getInput()->setDelegate(this);
|
||||
} else {
|
||||
m_label->setString(
|
||||
numToStringFixed(self()->m_uncommittedValue).c_str()
|
||||
numToString(self()->m_uncommittedValue).c_str()
|
||||
);
|
||||
m_label->limitLabelWidth(self()->m_width / 2 - 70.f, .5f, .1f);
|
||||
}
|
||||
|
@ -499,3 +495,157 @@ protected:
|
|||
|
||||
bool setup(std::shared_ptr<StringSetting> setting, float width) override;
|
||||
};
|
||||
|
||||
class ColorSettingNode :
|
||||
public GeodeSettingNode<ColorSettingNode, ColorSetting>
|
||||
{
|
||||
protected:
|
||||
ColorChannelSprite* m_colorSpr;
|
||||
|
||||
friend class ColorPickPopup<ColorSettingNode>;
|
||||
|
||||
void valueChanged(bool updateText) override;
|
||||
|
||||
bool setup(std::shared_ptr<ColorSetting> setting, float width) override;
|
||||
};
|
||||
|
||||
class ColorAlphaSettingNode :
|
||||
public GeodeSettingNode<ColorAlphaSettingNode, ColorAlphaSetting>
|
||||
{
|
||||
protected:
|
||||
ColorChannelSprite* m_colorSpr;
|
||||
|
||||
friend class ColorPickPopup<ColorAlphaSettingNode>;
|
||||
|
||||
void valueChanged(bool updateText) override;
|
||||
|
||||
bool setup(std::shared_ptr<ColorAlphaSetting> setting, float width) override;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class ColorPickPopup :
|
||||
public Popup<T*>,
|
||||
public ColorPickerDelegate,
|
||||
public TextInputDelegate
|
||||
{
|
||||
protected:
|
||||
T* m_settingNode;
|
||||
Slider* m_opacitySlider = nullptr;
|
||||
InputNode* m_opacityInput = nullptr;
|
||||
|
||||
static constexpr auto TAG_OPACITY_INPUT = 0;
|
||||
static constexpr auto TAG_R_INPUT = 1;
|
||||
static constexpr auto TAG_G_INPUT = 2;
|
||||
static constexpr auto TAG_B_INPUT = 3;
|
||||
static constexpr auto TAG_HEX_INPUT = 4;
|
||||
static constexpr auto IS_RGBA = std::is_same_v<
|
||||
decltype(T::m_uncommittedValue),
|
||||
ccColor4B
|
||||
>;
|
||||
|
||||
FLAlertLayer* asAlert() {
|
||||
return static_cast<FLAlertLayer*>(this);
|
||||
}
|
||||
|
||||
bool setup(T* node) override {
|
||||
asAlert()->m_noElasticity = true;
|
||||
|
||||
m_settingNode = node;
|
||||
|
||||
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
|
||||
auto picker = CCControlColourPicker::colourPicker();
|
||||
if constexpr (IS_RGBA) {
|
||||
picker->setColorValue(to3B(node->m_uncommittedValue));
|
||||
} else {
|
||||
picker->setColorValue(node->m_uncommittedValue);
|
||||
}
|
||||
picker->setColorTarget(node->m_colorSpr);
|
||||
picker->setPosition(
|
||||
winSize.width / 2,
|
||||
winSize.height / 2 + (IS_RGBA ? 20.f : 0.f)
|
||||
);
|
||||
picker->setDelegate(this);
|
||||
asAlert()->m_mainLayer->addChild(picker);
|
||||
|
||||
if constexpr (IS_RGBA) {
|
||||
m_opacitySlider = Slider::create(
|
||||
this,
|
||||
menu_selector(ColorPickPopup::onOpacity),
|
||||
.75f
|
||||
);
|
||||
m_opacitySlider->setPosition(
|
||||
winSize.width / 2 - 30.f,
|
||||
winSize.height / 2 - 90.f
|
||||
);
|
||||
m_opacitySlider->setValue(node->m_uncommittedValue.a / 255.f);
|
||||
m_opacitySlider->updateBar();
|
||||
asAlert()->m_mainLayer->addChild(m_opacitySlider);
|
||||
|
||||
m_opacityInput = InputNode::create(45.f, "0.00");
|
||||
m_opacityInput->setPosition(85.f, -90.f);
|
||||
m_opacityInput->setString(numToString(
|
||||
node->m_uncommittedValue.a / 255.f, 2
|
||||
));
|
||||
m_opacityInput->getInput()->setTag(TAG_OPACITY_INPUT);
|
||||
m_opacityInput->getInput()->setDelegate(this);
|
||||
asAlert()->m_buttonMenu->addChild(m_opacityInput);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void textChanged(CCTextInputNode* input) override {
|
||||
switch (input->getTag()) {
|
||||
case TAG_OPACITY_INPUT: {
|
||||
if constexpr (IS_RGBA) {
|
||||
try {
|
||||
auto value = std::stof(input->getString());
|
||||
m_settingNode->m_uncommittedValue.a = static_cast<GLubyte>(
|
||||
value * 255.f
|
||||
);
|
||||
m_opacitySlider->setValue(value);
|
||||
m_opacitySlider->updateBar();
|
||||
m_settingNode->valueChanged(true);
|
||||
} catch(...) {}
|
||||
}
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void onOpacity(CCObject* sender) {
|
||||
if constexpr (IS_RGBA) {
|
||||
m_settingNode->m_uncommittedValue.a = static_cast<GLubyte>(
|
||||
static_cast<SliderThumb*>(sender)->getValue() * 255.f
|
||||
);
|
||||
m_opacityInput->setString(numToString(
|
||||
m_settingNode->m_uncommittedValue.a / 255.f, 3
|
||||
));
|
||||
m_settingNode->valueChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
void colorValueChanged(ccColor3B color) override {
|
||||
if constexpr (IS_RGBA) {
|
||||
m_settingNode->m_uncommittedValue = to4B(
|
||||
color, m_settingNode->m_uncommittedValue.a
|
||||
);
|
||||
} else {
|
||||
m_settingNode->m_uncommittedValue = color;
|
||||
}
|
||||
m_settingNode->valueChanged(true);
|
||||
}
|
||||
|
||||
public:
|
||||
static ColorPickPopup* create(T* node) {
|
||||
auto ret = new ColorPickPopup();
|
||||
if (ret && ret->init(250.f, (IS_RGBA ? 250.f : 200.f), node)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
|
240
loader/src/utils/convert.cpp
Normal file
240
loader/src/utils/convert.cpp
Normal file
|
@ -0,0 +1,240 @@
|
|||
#include <Geode/utils/convert.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
void cocos2d::to_json(nlohmann::json& json, ccColor3B const& color) {
|
||||
json = nlohmann::json {
|
||||
{ "r", color.r },
|
||||
{ "g", color.g },
|
||||
{ "b", color.b },
|
||||
};
|
||||
}
|
||||
|
||||
void cocos2d::from_json(nlohmann::json const& json, ccColor3B& color) {
|
||||
// array
|
||||
if (json.is_array()) {
|
||||
if (json.size() == 3) {
|
||||
json.at(0).get_to(color.r);
|
||||
json.at(1).get_to(color.g);
|
||||
json.at(2).get_to(color.b);
|
||||
} else {
|
||||
throw nlohmann::json::type_error::create(
|
||||
0, "Expected color array to have 3 items", json
|
||||
);
|
||||
}
|
||||
}
|
||||
// object
|
||||
else if (json.is_object()) {
|
||||
json.at("r").get_to(color.r);
|
||||
json.at("g").get_to(color.g);
|
||||
json.at("b").get_to(color.b);
|
||||
}
|
||||
// hex string
|
||||
else if (json.is_string()) {
|
||||
std::string str = json;
|
||||
if (str[0] == '#') {
|
||||
str.erase(str.begin());
|
||||
}
|
||||
if (str.size() > 6) {
|
||||
throw nlohmann::json::type_error::create(
|
||||
0, "Hex string for color too long", json
|
||||
);
|
||||
}
|
||||
auto c = cc3bFromHexString(str);
|
||||
if (!c) {
|
||||
throw nlohmann::json::type_error::create(
|
||||
0, "Invalid color hex string: " + c.error(), json
|
||||
);
|
||||
}
|
||||
color = c.value();
|
||||
}
|
||||
// bad
|
||||
else {
|
||||
throw nlohmann::json::type_error::create(
|
||||
0, "Expected color to be array, object or hex string", json
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void cocos2d::to_json(nlohmann::json& json, ccColor4B const& color) {
|
||||
json = nlohmann::json {
|
||||
{ "r", color.r },
|
||||
{ "g", color.g },
|
||||
{ "b", color.b },
|
||||
{ "a", color.a },
|
||||
};
|
||||
}
|
||||
|
||||
void cocos2d::from_json(nlohmann::json const& json, ccColor4B& color) {
|
||||
// array
|
||||
if (json.is_array()) {
|
||||
if (json.size() == 4) {
|
||||
json.at(0).get_to(color.r);
|
||||
json.at(1).get_to(color.g);
|
||||
json.at(2).get_to(color.b);
|
||||
json.at(3).get_to(color.a);
|
||||
} else {
|
||||
throw nlohmann::json::type_error::create(
|
||||
0, "Expected color array to have 4 items", json
|
||||
);
|
||||
}
|
||||
}
|
||||
// object
|
||||
else if (json.is_object()) {
|
||||
json.at("r").get_to(color.r);
|
||||
json.at("g").get_to(color.g);
|
||||
json.at("b").get_to(color.b);
|
||||
json.at("a").get_to(color.a);
|
||||
}
|
||||
// hex string
|
||||
else if (json.is_string()) {
|
||||
std::string str = json;
|
||||
if (str[0] == '#') {
|
||||
str.erase(str.begin());
|
||||
}
|
||||
if (str.size() > 8) {
|
||||
throw nlohmann::json::type_error::create(
|
||||
0, "Hex string for color too long", json
|
||||
);
|
||||
}
|
||||
auto c = cc4bFromHexString(str);
|
||||
if (!c) {
|
||||
throw nlohmann::json::type_error::create(
|
||||
0, "Invalid color hex string: " + c.error(), json
|
||||
);
|
||||
}
|
||||
color = c.value();
|
||||
}
|
||||
// bad
|
||||
else {
|
||||
throw nlohmann::json::type_error::create(
|
||||
0, "Expected color to be array, object or hex string", json
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Result<ccColor3B> geode::cocos::cc3bFromHexString(std::string const& hexValue) {
|
||||
if (hexValue.empty()) {
|
||||
return Ok(ccc3(255, 255, 255));
|
||||
}
|
||||
if (hexValue.size() > 6) {
|
||||
return Err("Hex value too large");
|
||||
}
|
||||
int numValue;
|
||||
try {
|
||||
numValue = std::stoi(hexValue, 0, 16);
|
||||
} catch(...) {
|
||||
return Err("Invalid hex value");
|
||||
}
|
||||
switch (hexValue.size()) {
|
||||
case 6: {
|
||||
auto r = static_cast<uint8_t>((numValue & 0xFF0000) >> 16);
|
||||
auto g = static_cast<uint8_t>((numValue & 0x00FF00) >> 8);
|
||||
auto b = static_cast<uint8_t>((numValue & 0x0000FF));
|
||||
return Ok(ccc3(r, g, b));
|
||||
} break;
|
||||
|
||||
case 3: {
|
||||
auto r = static_cast<uint8_t>(((numValue & 0xF00) >> 8) * 17);
|
||||
auto g = static_cast<uint8_t>(((numValue & 0x0F0) >> 4) * 17);
|
||||
auto b = static_cast<uint8_t>(((numValue & 0x00F)) * 17);
|
||||
return Ok(ccc3(r, g, b));
|
||||
} break;
|
||||
|
||||
case 2: {
|
||||
auto num = static_cast<uint8_t>(numValue);
|
||||
return Ok(ccc3(num, num, num));
|
||||
} break;
|
||||
|
||||
case 1: {
|
||||
auto num = static_cast<uint8_t>(numValue) * 17;
|
||||
return Ok(ccc3(num, num, num));
|
||||
} break;
|
||||
|
||||
default: return Err("Invalid hex size, expected 1, 2, 3, or 6");
|
||||
}
|
||||
}
|
||||
|
||||
Result<ccColor4B> geode::cocos::cc4bFromHexString(std::string const& hexValue) {
|
||||
if (hexValue.empty()) {
|
||||
return Ok(ccc4(255, 255, 255, 255));
|
||||
}
|
||||
if (hexValue.size() > 8) {
|
||||
return Err("Hex value too large");
|
||||
}
|
||||
int numValue;
|
||||
try {
|
||||
numValue = std::stoi(hexValue, 0, 16);
|
||||
} catch(...) {
|
||||
return Err("Invalid hex value");
|
||||
}
|
||||
switch (hexValue.size()) {
|
||||
case 8: {
|
||||
auto r = static_cast<uint8_t>((numValue & 0xFF000000) >> 24);
|
||||
auto g = static_cast<uint8_t>((numValue & 0x00FF0000) >> 16);
|
||||
auto b = static_cast<uint8_t>((numValue & 0x0000FF00) >> 8);
|
||||
auto a = static_cast<uint8_t>((numValue & 0x000000FF));
|
||||
return Ok(ccc4(r, g, b, a));
|
||||
} break;
|
||||
|
||||
case 6: {
|
||||
auto r = static_cast<uint8_t>((numValue & 0xFF0000) >> 16);
|
||||
auto g = static_cast<uint8_t>((numValue & 0x00FF00) >> 8);
|
||||
auto b = static_cast<uint8_t>((numValue & 0x0000FF));
|
||||
return Ok(ccc4(r, g, b, 255));
|
||||
} break;
|
||||
|
||||
case 4: {
|
||||
auto r = static_cast<uint8_t>(((numValue & 0xF000) >> 12) * 17);
|
||||
auto g = static_cast<uint8_t>(((numValue & 0x0F00) >> 8) * 17);
|
||||
auto b = static_cast<uint8_t>(((numValue & 0x00F0) >> 4) * 17);
|
||||
auto a = static_cast<uint8_t>(((numValue & 0x000F)) * 17);
|
||||
return Ok(ccc4(r, g, b, a));
|
||||
} break;
|
||||
|
||||
case 3: {
|
||||
auto r = static_cast<uint8_t>(((numValue & 0xF00) >> 8) * 17);
|
||||
auto g = static_cast<uint8_t>(((numValue & 0x0F0) >> 4) * 17);
|
||||
auto b = static_cast<uint8_t>(((numValue & 0x00F)) * 17);
|
||||
return Ok(ccc4(r, g, b, 255));
|
||||
} break;
|
||||
|
||||
case 2: {
|
||||
auto num = static_cast<uint8_t>(numValue);
|
||||
return Ok(ccc4(num, num, num, 255));
|
||||
} break;
|
||||
|
||||
case 1: {
|
||||
auto num = static_cast<uint8_t>(numValue) * 17;
|
||||
return Ok(ccc4(num, num, num, 255));
|
||||
} break;
|
||||
|
||||
default: return Err("Invalid hex size, expected 1, 2, 3, 4, 6, or 8");
|
||||
}
|
||||
}
|
||||
|
||||
std::string geode::cocos::cc3bToHexString(ccColor3B const& color) {
|
||||
static constexpr auto digits = "0123456789ABCDEF";
|
||||
std::string output;
|
||||
output += digits[color.r >> 4 & 0xF];
|
||||
output += digits[color.r & 0xF];
|
||||
output += digits[color.g >> 4 & 0xF];
|
||||
output += digits[color.g & 0xF];
|
||||
output += digits[color.b >> 4 & 0xF];
|
||||
output += digits[color.b & 0xF];
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string geode::cocos::cc4bToHexString(ccColor4B const& color) {
|
||||
static constexpr auto digits = "0123456789ABCDEF";
|
||||
std::string output;
|
||||
output += digits[color.r >> 4 & 0xF];
|
||||
output += digits[color.r & 0xF];
|
||||
output += digits[color.g >> 4 & 0xF];
|
||||
output += digits[color.g & 0xF];
|
||||
output += digits[color.b >> 4 & 0xF];
|
||||
output += digits[color.b & 0xF];
|
||||
output += digits[color.a >> 4 & 0xF];
|
||||
output += digits[color.a & 0xF];
|
||||
return output;
|
||||
}
|
|
@ -52,6 +52,14 @@
|
|||
"mirai toka",
|
||||
"arun darou ka"
|
||||
]
|
||||
},
|
||||
"territory-battle": {
|
||||
"type": "color",
|
||||
"default": "#00f"
|
||||
},
|
||||
"faithful-dog-hachi": {
|
||||
"type": "rgba",
|
||||
"default": [ 255, 150, 55, 180 ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue