move color pick popup to its own class so modders can use it :3 also

finish that thing
This commit is contained in:
HJfod 2022-09-23 21:42:52 +03:00
parent 19293e2fdf
commit faa269fe8a
6 changed files with 371 additions and 140 deletions

View file

@ -0,0 +1,55 @@
#include "Popup.hpp"
#include "InputNode.hpp"
namespace geode {
class ColorPickPopupDelegate {
public:
virtual void updateColor(cocos2d::ccColor4B const& color) {}
};
class ColorPickPopup :
public Popup<cocos2d::ccColor4B const&, bool>,
public cocos2d::extension::ColorPickerDelegate,
public TextInputDelegate
{
protected:
cocos2d::ccColor4B m_color;
cocos2d::ccColor4B m_originalColor;
cocos2d::extension::CCControlColourPicker* m_picker;
Slider* m_opacitySlider = nullptr;
InputNode* m_rInput;
InputNode* m_gInput;
InputNode* m_bInput;
InputNode* m_hexInput;
InputNode* m_opacityInput = nullptr;
ColorPickPopupDelegate* m_delegate = nullptr;
cocos2d::CCSprite* m_newColorSpr;
CCMenuItemSpriteExtra* m_resetBtn;
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;
bool setup(cocos2d::ccColor4B const& color, bool isRGBA) override;
void onOpacitySlider(cocos2d::CCObject* sender);
void onReset(cocos2d::CCObject* sender);
void textChanged(CCTextInputNode* input) override;
void colorValueChanged(cocos2d::ccColor3B color) override;
void updateState(cocos2d::CCNode* except = nullptr);
static ColorPickPopup* create(cocos2d::ccColor4B const& color, bool isRGBA);
public:
static ColorPickPopup* create(bool isRGBA);
static ColorPickPopup* create(cocos2d::ccColor3B const& color);
static ColorPickPopup* create(cocos2d::ccColor4B const& color);
void setColorTarget(cocos2d::CCSprite* spr);
void setDelegate(ColorPickPopupDelegate* delegate);
};
}

Binary file not shown.

After

(image error) Size: 5.2 KiB

View file

@ -22,7 +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("rgb"): 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 + "\""

View file

@ -98,6 +98,11 @@ void ColorSettingNode::valueChanged(bool updateText) {
m_colorSpr->setColor(m_uncommittedValue);
}
void ColorSettingNode::updateColor(ccColor4B const& color) {
m_uncommittedValue = to3B(color);
this->valueChanged(true);
}
bool ColorSettingNode::setup(std::shared_ptr<ColorSetting> setting, float width) {
m_colorSpr = ColorChannelSprite::create();
m_colorSpr->setColor(m_uncommittedValue);
@ -105,7 +110,10 @@ bool ColorSettingNode::setup(std::shared_ptr<ColorSetting> setting, float width)
auto button = CCMenuItemSpriteExtra::create(
m_colorSpr, this, makeMenuSelector([this](CCObject*) {
ColorPickPopup<ColorSettingNode>::create(this)->show();
auto popup = ColorPickPopup::create(m_uncommittedValue);
popup->setDelegate(this);
popup->setColorTarget(m_colorSpr);
popup->show();
})
);
button->setPositionX(-10.f);
@ -122,6 +130,11 @@ void ColorAlphaSettingNode::valueChanged(bool updateText) {
m_colorSpr->updateOpacity(m_uncommittedValue.a / 255.f);
}
void ColorAlphaSettingNode::updateColor(ccColor4B const& color) {
m_uncommittedValue = color;
this->valueChanged(true);
}
bool ColorAlphaSettingNode::setup(std::shared_ptr<ColorAlphaSetting> setting, float width) {
m_colorSpr = ColorChannelSprite::create();
m_colorSpr->setColor(to3B(m_uncommittedValue));
@ -130,7 +143,10 @@ bool ColorAlphaSettingNode::setup(std::shared_ptr<ColorAlphaSetting> setting, fl
auto button = CCMenuItemSpriteExtra::create(
m_colorSpr, this, makeMenuSelector([this](CCObject*) {
ColorPickPopup<ColorAlphaSettingNode>::create(this)->show();
auto popup = ColorPickPopup::create(m_uncommittedValue);
popup->setDelegate(this);
popup->setColorTarget(m_colorSpr);
popup->show();
})
);
button->setPositionX(-10.f);

View file

@ -9,12 +9,10 @@
#include <Geode/utils/string.hpp>
#include <Geode/utils/cocos.hpp>
#include <Geode/ui/Popup.hpp>
#include <Geode/ui/ColorPickPopup.hpp>
USE_GEODE_NAMESPACE();
template<class T>
class ColorPickPopup;
namespace {
template<class Num>
Num parseNumForInput(std::string const& str) {
@ -497,155 +495,27 @@ protected:
};
class ColorSettingNode :
public GeodeSettingNode<ColorSettingNode, ColorSetting>
public GeodeSettingNode<ColorSettingNode, ColorSetting>,
public ColorPickPopupDelegate
{
protected:
ColorChannelSprite* m_colorSpr;
friend class ColorPickPopup<ColorSettingNode>;
void valueChanged(bool updateText) override;
void updateColor(ccColor4B const& color) override;
bool setup(std::shared_ptr<ColorSetting> setting, float width) override;
};
class ColorAlphaSettingNode :
public GeodeSettingNode<ColorAlphaSettingNode, ColorAlphaSetting>
public GeodeSettingNode<ColorAlphaSettingNode, ColorAlphaSetting>,
public ColorPickPopupDelegate
{
protected:
ColorChannelSprite* m_colorSpr;
friend class ColorPickPopup<ColorAlphaSettingNode>;
void valueChanged(bool updateText) override;
void updateColor(ccColor4B const& color) 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;
}
};

View file

@ -0,0 +1,289 @@
#include <Geode/ui/ColorPickPopup.hpp>
#include <Geode/utils/operators.hpp>
USE_GEODE_NAMESPACE();
static GLubyte parseInt(const char* str) {
try {
return static_cast<GLubyte>(std::stoi(str));
} catch(...) {
return 255;
}
}
static GLubyte parseFloat(const char* str) {
try {
return static_cast<GLubyte>(std::stof(str) * 255.f);
} catch(...) {
return 255;
}
}
bool ColorPickPopup::setup(ccColor4B const& color, bool isRGBA) {
m_noElasticity = true;
m_color = color;
m_originalColor = color;
auto winSize = CCDirector::sharedDirector()->getWinSize();
this->setTitle("Select Color");
// picker
m_picker = CCControlColourPicker::colourPicker();
m_picker->setPosition(
winSize.width / 2 - 45.f,
winSize.height / 2 + (isRGBA ? 25.f : 0.f)
);
m_picker->setDelegate(this);
m_mainLayer->addChild(m_picker);
// color difference
auto oldColorSpr = CCSprite::createWithSpriteFrameName("whiteSquare60_001.png");
oldColorSpr->setPosition({
winSize.width / 2 - 165.f,
winSize.height / 2 + 15.f
});
oldColorSpr->setColor(to3B(m_color));
m_mainLayer->addChild(oldColorSpr);
m_newColorSpr = CCSprite::createWithSpriteFrameName("whiteSquare60_001.png");
m_newColorSpr->setPosition({
winSize.width / 2 - 165.f,
winSize.height / 2 - 15.f
});
m_newColorSpr->setColor(to3B(m_color));
m_mainLayer->addChild(m_newColorSpr);
auto resetBtnSpr = ButtonSprite::create(
CCSprite::createWithSpriteFrameName("reset-gold.png"_spr),
0x20, true, 0.f, "GJ_button_01.png", 1.25f
);
resetBtnSpr->setScale(.6f);
m_resetBtn = CCMenuItemSpriteExtra::create(
resetBtnSpr, this, menu_selector(ColorPickPopup::onReset)
);
m_resetBtn->setPosition({ -165.f, -50.f });
m_buttonMenu->addChild(m_resetBtn);
// r
auto rText = CCLabelBMFont::create("R", "goldFont.fnt");
rText->setPosition(
winSize.width / 2 + 75.f,
winSize.height / 2 + (isRGBA ? 60.f : 35.f)
);
rText->setScale(.55f);
m_mainLayer->addChild(rText);
m_rInput = InputNode::create(50.f, "R");
m_rInput->setPosition(75.f, (isRGBA ? 40.f : 15.f));
m_rInput->setScale(.7f);
m_rInput->getInput()->setTag(TAG_R_INPUT);
m_rInput->getInput()->setDelegate(this);
m_buttonMenu->addChild(m_rInput);
// g
auto gText = CCLabelBMFont::create("G", "goldFont.fnt");
gText->setPosition(
winSize.width / 2 + 115.f,
winSize.height / 2 + (isRGBA ? 60.f : 35.f)
);
gText->setScale(.55f);
m_mainLayer->addChild(gText);
m_gInput = InputNode::create(50.f, "G");
m_gInput->setPosition(115.f, (isRGBA ? 40.f : 15.f));
m_gInput->setScale(.7f);
m_gInput->getInput()->setTag(TAG_G_INPUT);
m_gInput->getInput()->setDelegate(this);
m_buttonMenu->addChild(m_gInput);
// b
auto bText = CCLabelBMFont::create("B", "goldFont.fnt");
bText->setPosition(
winSize.width / 2 + 155.f,
winSize.height / 2 + (isRGBA ? 60.f : 35.f)
);
bText->setScale(.55f);
m_mainLayer->addChild(bText);
m_bInput = InputNode::create(50.f, "B");
m_bInput->setPosition(155.f, (isRGBA ? 40.f : 15.f));
m_bInput->setScale(.7f);
m_bInput->getInput()->setTag(TAG_B_INPUT);
m_bInput->getInput()->setDelegate(this);
m_buttonMenu->addChild(m_bInput);
// hex
auto hexText = CCLabelBMFont::create("Hex", "goldFont.fnt");
hexText->setPosition(
winSize.width / 2 + 115.f,
winSize.height / 2 + (isRGBA ? 20.f : -5.f)
);
hexText->setScale(.55f);
m_mainLayer->addChild(hexText);
m_hexInput = InputNode::create(165.f, "Hex");
m_hexInput->setPosition(115.f, (isRGBA ? 0.f : -25.f));
m_hexInput->setScale(.7f);
m_hexInput->getInput()->setTag(TAG_HEX_INPUT);
m_hexInput->getInput()->setDelegate(this);
m_buttonMenu->addChild(m_hexInput);
if (isRGBA) {
auto opacityText = CCLabelBMFont::create("Opacity", "goldFont.fnt");
opacityText->setPosition(
winSize.width / 2 - 30.f,
winSize.height / 2 - 70.f
);
opacityText->setScale(.55f);
m_mainLayer->addChild(opacityText);
m_opacitySlider = Slider::create(
this,
menu_selector(ColorPickPopup::onOpacitySlider),
.75f
);
m_opacitySlider->setPosition(
winSize.width / 2 - 30.f,
winSize.height / 2 - 90.f
);
m_opacitySlider->setValue(color.a / 255.f);
m_opacitySlider->updateBar();
m_mainLayer->addChild(m_opacitySlider);
m_opacityInput = InputNode::create(60.f, "0.00");
m_opacityInput->setPosition(85.f, -90.f);
m_opacityInput->setScale(.7f);
m_opacityInput->getInput()->setTag(TAG_OPACITY_INPUT);
m_opacityInput->getInput()->setDelegate(this);
m_buttonMenu->addChild(m_opacityInput);
}
this->updateState();
auto okBtnSpr = ButtonSprite::create("OK");
okBtnSpr->setScale(.7f);
auto okBtn = CCMenuItemSpriteExtra::create(
okBtnSpr, this, menu_selector(ColorPickPopup::onClose)
);
okBtn->setPosition(.0f, -m_size.height / 2 + 25.f);
m_buttonMenu->addChild(okBtn);
return true;
}
void ColorPickPopup::updateState(CCNode* except) {
#define IF_NOT_EXCEPT(inp, value)\
if (inp->getInput() != except) {\
inp->getInput()->setDelegate(nullptr);\
inp->setString(value);\
inp->getInput()->setDelegate(this);\
}
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 (m_opacitySlider) {
m_opacitySlider->setValue(m_color.a / 255.f);
m_opacitySlider->updateBar();
}
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);
}
void ColorPickPopup::onOpacitySlider(CCObject* sender) {
m_color.a = static_cast<GLubyte>(
static_cast<SliderThumb*>(sender)->getValue() * 255.f
);
this->updateState();
}
void ColorPickPopup::onReset(CCObject*) {
m_color = m_originalColor;
this->updateState();
}
void ColorPickPopup::textChanged(CCTextInputNode* input) {
if (input->getString() && strlen(input->getString())) {
switch (input->getTag()) {
case TAG_HEX_INPUT: {
if (auto color = cc3bFromHexString(input->getString())) {
m_color.r = color.value().r;
m_color.g = color.value().g;
m_color.b = color.value().b;
}
} break;
case TAG_OPACITY_INPUT: {
m_color.a = parseFloat(input->getString());
} break;
case TAG_R_INPUT: m_color.r = parseInt(input->getString()); break;
case TAG_G_INPUT: m_color.g = parseInt(input->getString()); break;
case TAG_B_INPUT: m_color.b = parseInt(input->getString()); break;
default: break;
}
}
this->updateState(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);
}
void ColorPickPopup::setDelegate(ColorPickPopupDelegate* delegate) {
m_delegate = delegate;
}
void ColorPickPopup::setColorTarget(cocos2d::CCSprite* spr) {
m_picker->setColorTarget(spr);
}
ColorPickPopup* ColorPickPopup::create(ccColor4B const& color, bool isRGBA) {
auto ret = new ColorPickPopup();
if (ret && ret->init(
380.f, (isRGBA ? 290.f : 240.f), color, isRGBA
)) {
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
ColorPickPopup* ColorPickPopup::create(bool isRGBA) {
return ColorPickPopup::create({ 255, 255, 255, 255 }, isRGBA);
}
ColorPickPopup* ColorPickPopup::create(ccColor3B const& color) {
return ColorPickPopup::create(to4B(color), false);
}
ColorPickPopup* ColorPickPopup::create(ccColor4B const& color) {
return ColorPickPopup::create(color, true);
}