mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 22:54:01 +02:00
Add HSL color picker box for theming.
This commit is contained in:
parent
a3e993253c
commit
56a82600f8
7 changed files with 313 additions and 114 deletions
|
@ -389,6 +389,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_settings_theme_classic" = "Classic";
|
||||
"lng_settings_theme_midnight" = "Midnight";
|
||||
"lng_settings_theme_matrix" = "Matrix";
|
||||
"lng_settings_theme_accent_title" = "Choose accent color";
|
||||
"lng_settings_data_storage" = "Data and storage";
|
||||
"lng_settings_information" = "Edit profile";
|
||||
"lng_settings_passcode_title" = "Local passcode";
|
||||
|
|
|
@ -16,7 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
class EditColorBox::Picker : public TWidget {
|
||||
public:
|
||||
Picker(QWidget *parent, QColor color);
|
||||
Picker(QWidget *parent, Mode mode, QColor color);
|
||||
|
||||
float64 valueX() const {
|
||||
return _x;
|
||||
|
@ -28,7 +28,7 @@ public:
|
|||
base::Observable<void> &changed() {
|
||||
return _changed;
|
||||
}
|
||||
void setHSV(int hue, int saturation, int brightness);
|
||||
void setHSB(HSB hsb);
|
||||
void setRGB(int red, int green, int blue);
|
||||
|
||||
protected:
|
||||
|
@ -43,8 +43,11 @@ private:
|
|||
QCursor generateCursor();
|
||||
|
||||
void preparePalette();
|
||||
void preparePaletteRGBA();
|
||||
void preparePaletteHSL();
|
||||
void updateCurrentPoint(QPoint localPosition);
|
||||
|
||||
Mode _mode;
|
||||
QColor _topleft;
|
||||
QColor _topright;
|
||||
QColor _bottomleft;
|
||||
|
@ -84,7 +87,9 @@ QCursor EditColorBox::Picker::generateCursor() {
|
|||
return QCursor(QPixmap::fromImage(cursor));
|
||||
}
|
||||
|
||||
EditColorBox::Picker::Picker(QWidget *parent, QColor color) : TWidget(parent) {
|
||||
EditColorBox::Picker::Picker(QWidget *parent, Mode mode, QColor color)
|
||||
: TWidget(parent)
|
||||
, _mode(mode) {
|
||||
setCursor(generateCursor());
|
||||
|
||||
auto size = QSize(st::colorPickerSize, st::colorPickerSize);
|
||||
|
@ -137,18 +142,26 @@ void EditColorBox::Picker::preparePalette() {
|
|||
if (!_paletteInvalidated) return;
|
||||
_paletteInvalidated = false;
|
||||
|
||||
auto size = _palette.width();
|
||||
if (_mode == Mode::RGBA) {
|
||||
preparePaletteRGBA();
|
||||
} else {
|
||||
preparePaletteHSL();
|
||||
}
|
||||
}
|
||||
|
||||
void EditColorBox::Picker::preparePaletteRGBA() {
|
||||
const auto size = _palette.width();
|
||||
auto ints = reinterpret_cast<uint32*>(_palette.bits());
|
||||
auto intsAddPerLine = (_palette.bytesPerLine() - size * sizeof(uint32)) / sizeof(uint32);
|
||||
const auto intsAddPerLine = (_palette.bytesPerLine() - size * sizeof(uint32)) / sizeof(uint32);
|
||||
|
||||
constexpr auto Large = 1024 * 1024;
|
||||
constexpr auto LargeBit = 20; // n / Large == (n >> LargeBit)
|
||||
auto part = Large / size;
|
||||
const auto part = Large / size;
|
||||
|
||||
auto topleft = anim::shifted(_topleft);
|
||||
auto topright = anim::shifted(_topright);
|
||||
auto bottomleft = anim::shifted(_bottomleft);
|
||||
auto bottomright = anim::shifted(_bottomright);
|
||||
const auto topleft = anim::shifted(_topleft);
|
||||
const auto topright = anim::shifted(_topright);
|
||||
const auto bottomleft = anim::shifted(_bottomleft);
|
||||
const auto bottomright = anim::shifted(_bottomright);
|
||||
|
||||
auto y_accumulated = 0;
|
||||
for (auto y = 0; y != size; ++y, y_accumulated += part) {
|
||||
|
@ -156,11 +169,11 @@ void EditColorBox::Picker::preparePalette() {
|
|||
// 0 <= y_accumulated < Large
|
||||
// 0 <= y_ratio < 256
|
||||
|
||||
auto top_ratio = 255 - y_ratio;
|
||||
auto bottom_ratio = y_ratio;
|
||||
const auto top_ratio = 255 - y_ratio;
|
||||
const auto bottom_ratio = y_ratio;
|
||||
|
||||
auto left = anim::reshifted(bottomleft * bottom_ratio + topleft * top_ratio);
|
||||
auto right = anim::reshifted(bottomright * bottom_ratio + topright * top_ratio);
|
||||
const auto left = anim::reshifted(bottomleft * bottom_ratio + topleft * top_ratio);
|
||||
const auto right = anim::reshifted(bottomright * bottom_ratio + topright * top_ratio);
|
||||
|
||||
auto x_accumulated = 0;
|
||||
for (auto x = 0; x != size; ++x, x_accumulated += part) {
|
||||
|
@ -177,6 +190,41 @@ void EditColorBox::Picker::preparePalette() {
|
|||
}
|
||||
}
|
||||
|
||||
void EditColorBox::Picker::preparePaletteHSL() {
|
||||
const auto size = _palette.width();
|
||||
const auto intsAddPerLine = (_palette.bytesPerLine() - size * sizeof(uint32)) / sizeof(uint32);
|
||||
auto ints = reinterpret_cast<uint32*>(_palette.bits());
|
||||
|
||||
constexpr auto Large = 1024 * 1024;
|
||||
constexpr auto LargeBit = 20; // n / Large == (n >> LargeBit)
|
||||
const auto part = Large / size;
|
||||
|
||||
const auto lightness = _topleft.lightness();
|
||||
const auto right = anim::shifted(_bottomright);
|
||||
|
||||
for (auto y = 0; y != size; ++y) {
|
||||
const auto hue = y * 360 / size;
|
||||
const auto color = QColor::fromHsl(hue, 255, lightness).toRgb();
|
||||
const auto left = anim::shifted(anim::getPremultiplied(color));
|
||||
|
||||
auto x_accumulated = 0;
|
||||
for (auto x = 0; x != size; ++x, x_accumulated += part) {
|
||||
auto x_ratio = x_accumulated >> (LargeBit - 8); // (x_accumulated * 256) / Large;
|
||||
// 0 <= x_accumulated < Large
|
||||
// 0 <= x_ratio < 256
|
||||
|
||||
auto left_ratio = 255 - x_ratio;
|
||||
auto right_ratio = x_ratio;
|
||||
|
||||
*ints++ = anim::unshifted(left * left_ratio + right * right_ratio);
|
||||
}
|
||||
ints += intsAddPerLine;
|
||||
}
|
||||
|
||||
_palette = std::move(_palette).transformed(
|
||||
QTransform(0, 1, 1, 0, 0, 0));
|
||||
}
|
||||
|
||||
void EditColorBox::Picker::updateCurrentPoint(QPoint localPosition) {
|
||||
auto x = snap(localPosition.x(), 0, width()) / float64(width());
|
||||
auto y = snap(localPosition.y(), 0, height()) / float64(height());
|
||||
|
@ -188,17 +236,25 @@ void EditColorBox::Picker::updateCurrentPoint(QPoint localPosition) {
|
|||
}
|
||||
}
|
||||
|
||||
void EditColorBox::Picker::setHSV(int hue, int saturation, int brightness) {
|
||||
_topleft = QColor(255, 255, 255);
|
||||
_topright.setHsv(qMax(0, hue), 255, 255);
|
||||
_topright = _topright.toRgb();
|
||||
_bottomleft = _bottomright = QColor(0, 0, 0);
|
||||
void EditColorBox::Picker::setHSB(HSB hsb) {
|
||||
if (_mode == Mode::RGBA) {
|
||||
_topleft = QColor(255, 255, 255);
|
||||
_topright.setHsv(qMax(0, hsb.hue), 255, 255);
|
||||
_topright = _topright.toRgb();
|
||||
_bottomleft = _bottomright = QColor(0, 0, 0);
|
||||
|
||||
_x = snap(hsb.saturation / 255., 0., 1.);
|
||||
_y = 1. - snap(hsb.brightness / 255., 0., 1.);
|
||||
} else {
|
||||
_topleft = _topright = QColor::fromHsl(0, 255, hsb.brightness);
|
||||
_bottomleft = _bottomright = QColor::fromHsl(0, 0, hsb.brightness);
|
||||
|
||||
_x = snap(hsb.hue / 360., 0., 1.);
|
||||
_y = 1. - snap(hsb.saturation / 255., 0., 1.);
|
||||
}
|
||||
|
||||
_paletteInvalidated = true;
|
||||
update();
|
||||
|
||||
_x = snap(saturation / 255., 0., 1.);
|
||||
_y = 1. - snap(brightness / 255., 0., 1.);
|
||||
}
|
||||
|
||||
void EditColorBox::Picker::setRGB(int red, int green, int blue) {
|
||||
|
@ -206,7 +262,11 @@ void EditColorBox::Picker::setRGB(int red, int green, int blue) {
|
|||
}
|
||||
|
||||
void EditColorBox::Picker::setFromColor(QColor color) {
|
||||
setHSV(color.hsvHue(), color.hsvSaturation(), color.value());
|
||||
if (_mode == Mode::RGBA) {
|
||||
setHSB({ color.hsvHue(), color.hsvSaturation(), color.value() });
|
||||
} else {
|
||||
setHSB({ color.hslHue(), color.hslSaturation(), color.lightness() });
|
||||
}
|
||||
}
|
||||
|
||||
class EditColorBox::Slider : public TWidget {
|
||||
|
@ -218,6 +278,7 @@ public:
|
|||
enum class Type {
|
||||
Hue,
|
||||
Opacity,
|
||||
Lightness
|
||||
};
|
||||
Slider(QWidget *parent, Direction direction, Type type, QColor color);
|
||||
|
||||
|
@ -231,7 +292,7 @@ public:
|
|||
_value = snap(value, 0., 1.);
|
||||
update();
|
||||
}
|
||||
void setHSV(int hue, int saturation, int brightness);
|
||||
void setHSB(HSB hsb);
|
||||
void setRGB(int red, int green, int blue);
|
||||
void setAlpha(int alpha);
|
||||
|
||||
|
@ -275,7 +336,7 @@ EditColorBox::Slider::Slider(QWidget *parent, Direction direction, Type type, QC
|
|||
, _type(type)
|
||||
, _color(color.red(), color.green(), color.blue())
|
||||
, _value(valueFromColor(color))
|
||||
, _transparent((_type == Type::Hue) ? QBrush() : style::transparentPlaceholderBrush()) {
|
||||
, _transparent((_type == Type::Opacity) ? style::transparentPlaceholderBrush() : QBrush()) {
|
||||
prepareMinSize();
|
||||
}
|
||||
|
||||
|
@ -336,10 +397,9 @@ void EditColorBox::Slider::generatePixmap() {
|
|||
auto part = Large / size;
|
||||
|
||||
if (_type == Type::Hue) {
|
||||
QColor color;
|
||||
for (auto x = 0; x != size; ++x) {
|
||||
color.setHsv(x * 360 / size, 255, 255);
|
||||
auto value = anim::getPremultiplied(color.toRgb());
|
||||
const auto color = QColor::fromHsv(x * 360 / size, 255, 255);
|
||||
const auto value = anim::getPremultiplied(color.toRgb());
|
||||
for (auto y = 0; y != cIntRetinaFactor(); ++y) {
|
||||
ints[y * intsPerLine] = value;
|
||||
}
|
||||
|
@ -349,7 +409,7 @@ void EditColorBox::Slider::generatePixmap() {
|
|||
image = std::move(image).transformed(QTransform(0, -1, 1, 0, 0, 0));
|
||||
}
|
||||
_pixmap = App::pixmapFromImageInPlace(std::move(image));
|
||||
} else {
|
||||
} else if (_type == Type::Opacity) {
|
||||
auto color = anim::shifted(QColor(255, 255, 255, 255));
|
||||
auto transparent = anim::shifted(QColor(255, 255, 255, 0));
|
||||
for (auto y = 0; y != cIntRetinaFactor(); ++y) {
|
||||
|
@ -368,16 +428,33 @@ void EditColorBox::Slider::generatePixmap() {
|
|||
}
|
||||
_mask = std::move(image);
|
||||
updatePixmapFromMask();
|
||||
} else {
|
||||
QColor color;
|
||||
for (auto x = 0; x != size; ++x) {
|
||||
color.setHsl(_color.hslHue(), _color.hslSaturation(), x * 255 / size);
|
||||
auto value = anim::getPremultiplied(color.toRgb());
|
||||
for (auto y = 0; y != cIntRetinaFactor(); ++y) {
|
||||
ints[y * intsPerLine] = value;
|
||||
}
|
||||
++ints;
|
||||
}
|
||||
if (!isHorizontal()) {
|
||||
image = std::move(image).transformed(QTransform(0, -1, 1, 0, 0, 0));
|
||||
}
|
||||
_pixmap = App::pixmapFromImageInPlace(std::move(image));
|
||||
}
|
||||
}
|
||||
|
||||
void EditColorBox::Slider::setHSV(int hue, int saturation, int brightness) {
|
||||
void EditColorBox::Slider::setHSB(HSB hsb) {
|
||||
if (_type == Type::Hue) {
|
||||
// hue == 360 converts to 0 if done in general way
|
||||
_value = valueFromHue(hue);
|
||||
_value = valueFromHue(hsb.hue);
|
||||
update();
|
||||
} else if (_type == Type::Opacity) {
|
||||
_color.setHsv(hsb.hue, hsb.saturation, hsb.brightness);
|
||||
colorUpdated();
|
||||
} else {
|
||||
_color.setHsv(hue, saturation, brightness);
|
||||
_color.setHsl(hsb.hue, hsb.saturation, hsb.brightness);
|
||||
colorUpdated();
|
||||
}
|
||||
}
|
||||
|
@ -392,12 +469,18 @@ void EditColorBox::Slider::colorUpdated() {
|
|||
_value = valueFromColor(_color);
|
||||
} else if (!_mask.isNull()) {
|
||||
updatePixmapFromMask();
|
||||
} else {
|
||||
generatePixmap();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
float64 EditColorBox::Slider::valueFromColor(QColor color) const {
|
||||
return (_type == Type::Hue) ? valueFromHue(color.hsvHue()) : color.alphaF();
|
||||
return (_type == Type::Hue)
|
||||
? valueFromHue(color.hsvHue())
|
||||
: (_type == Type::Opacity)
|
||||
? color.alphaF()
|
||||
: color.lightnessF();
|
||||
}
|
||||
|
||||
float64 EditColorBox::Slider::valueFromHue(int hue) const {
|
||||
|
@ -613,14 +696,18 @@ void EditColorBox::ResultField::paintAdditionalPlaceholder(Painter &p) {
|
|||
p.drawText(QRect(_st.textMargins.right(), _st.textMargins.top(), width(), height() - _st.textMargins.top() - _st.textMargins.bottom()), "#", style::al_topleft);
|
||||
}
|
||||
|
||||
EditColorBox::EditColorBox(QWidget*, const QString &title, QColor current) : BoxContent()
|
||||
EditColorBox::EditColorBox(
|
||||
QWidget*,
|
||||
const QString &title,
|
||||
Mode mode,
|
||||
QColor current)
|
||||
: BoxContent()
|
||||
, _title(title)
|
||||
, _picker(this, current)
|
||||
, _hueSlider(this, Slider::Direction::Vertical, Slider::Type::Hue, current)
|
||||
, _opacitySlider(this, Slider::Direction::Horizontal, Slider::Type::Opacity, current)
|
||||
, _mode(mode)
|
||||
, _picker(this, mode, current)
|
||||
, _hueField(this, st::colorValueInput, "H", 360, QString() + QChar(176)) // degree character
|
||||
, _saturationField(this, st::colorValueInput, "S", 100, "%")
|
||||
, _brightnessField(this, st::colorValueInput, "B", 100, "%")
|
||||
, _brightnessField(this, st::colorValueInput, (mode == Mode::RGBA) ? "B" : "L", 100, "%")
|
||||
, _redField(this, st::colorValueInput, "R", 255)
|
||||
, _greenField(this, st::colorValueInput, "G", 255)
|
||||
, _blueField(this, st::colorValueInput, "B", 255)
|
||||
|
@ -628,16 +715,38 @@ EditColorBox::EditColorBox(QWidget*, const QString &title, QColor current) : Box
|
|||
, _transparent(style::transparentPlaceholderBrush())
|
||||
, _current(current)
|
||||
, _new(current) {
|
||||
if (_mode == Mode::RGBA) {
|
||||
_hueSlider.create(
|
||||
this,
|
||||
Slider::Direction::Vertical,
|
||||
Slider::Type::Hue,
|
||||
current);
|
||||
_opacitySlider.create(
|
||||
this,
|
||||
Slider::Direction::Horizontal,
|
||||
Slider::Type::Opacity,
|
||||
current);
|
||||
} else if (_mode == Mode::HSL) {
|
||||
_lightnessSlider.create(
|
||||
this,
|
||||
Slider::Direction::Horizontal,
|
||||
Slider::Type::Lightness,
|
||||
current);
|
||||
}
|
||||
}
|
||||
|
||||
void EditColorBox::setLightnessLimits(int min, int max) {
|
||||
|
||||
}
|
||||
|
||||
void EditColorBox::prepare() {
|
||||
setTitle(rpl::single(_title));
|
||||
|
||||
const auto hsvChanged = [=] { updateFromHSVFields(); };
|
||||
const auto hsbChanged = [=] { updateFromHSBFields(); };
|
||||
const auto rgbChanged = [=] { updateFromRGBFields(); };
|
||||
connect(_hueField, &Ui::MaskedInputField::changed, hsvChanged);
|
||||
connect(_saturationField, &Ui::MaskedInputField::changed, hsvChanged);
|
||||
connect(_brightnessField, &Ui::MaskedInputField::changed, hsvChanged);
|
||||
connect(_hueField, &Ui::MaskedInputField::changed, hsbChanged);
|
||||
connect(_saturationField, &Ui::MaskedInputField::changed, hsbChanged);
|
||||
connect(_brightnessField, &Ui::MaskedInputField::changed, hsbChanged);
|
||||
connect(_redField, &Ui::MaskedInputField::changed, rgbChanged);
|
||||
connect(_greenField, &Ui::MaskedInputField::changed, rgbChanged);
|
||||
connect(_blueField, &Ui::MaskedInputField::changed, rgbChanged);
|
||||
|
@ -661,8 +770,15 @@ void EditColorBox::prepare() {
|
|||
setDimensions(st::colorEditWidth, height);
|
||||
|
||||
subscribe(_picker->changed(), [=] { updateFromControls(); });
|
||||
subscribe(_hueSlider->changed(), [=] { updateFromControls(); });
|
||||
subscribe(_opacitySlider->changed(), [=] { updateFromControls(); });
|
||||
if (_hueSlider) {
|
||||
subscribe(_hueSlider->changed(), [=] { updateFromControls(); });
|
||||
}
|
||||
if (_opacitySlider) {
|
||||
subscribe(_opacitySlider->changed(), [=] { updateFromControls(); });
|
||||
}
|
||||
if (_lightnessSlider) {
|
||||
subscribe(_lightnessSlider->changed(), [=] { updateFromControls(); });
|
||||
}
|
||||
|
||||
boxClosing() | rpl::start_with_next([=] {
|
||||
if (_cancelCallback) {
|
||||
|
@ -671,7 +787,7 @@ void EditColorBox::prepare() {
|
|||
}, lifetime());
|
||||
|
||||
updateRGBFields();
|
||||
updateHSVFields();
|
||||
updateHSBFields();
|
||||
updateResultField();
|
||||
update();
|
||||
}
|
||||
|
@ -714,14 +830,11 @@ void EditColorBox::saveColor() {
|
|||
}
|
||||
}
|
||||
|
||||
void EditColorBox::updateHSVFields() {
|
||||
auto hue = qRound((1. - _hueSlider->value()) * 360);
|
||||
auto saturation = qRound(_picker->valueX() * 255);
|
||||
auto brightness = qRound((1. - _picker->valueY()) * 255);
|
||||
auto alpha = qRound(_opacitySlider->value() * 255);
|
||||
_hueField->setTextWithFocus(QString::number(hue));
|
||||
_saturationField->setTextWithFocus(QString::number(percentFromByte(saturation)));
|
||||
_brightnessField->setTextWithFocus(QString::number(percentFromByte(brightness)));
|
||||
void EditColorBox::updateHSBFields() {
|
||||
const auto hsb = hsbFromControls();
|
||||
_hueField->setTextWithFocus(QString::number(hsb.hue));
|
||||
_saturationField->setTextWithFocus(QString::number(percentFromByte(hsb.saturation)));
|
||||
_brightnessField->setTextWithFocus(QString::number(percentFromByte(hsb.brightness)));
|
||||
}
|
||||
|
||||
void EditColorBox::updateRGBFields() {
|
||||
|
@ -753,14 +866,28 @@ void EditColorBox::updateResultField() {
|
|||
}
|
||||
|
||||
void EditColorBox::resizeEvent(QResizeEvent *e) {
|
||||
auto fullwidth = _picker->width() + 2 * (st::colorEditSkip - st::colorSliderSkip) + _hueSlider->width() + st::colorSampleSize.width();
|
||||
const auto fullwidth = _picker->width()
|
||||
+ ((_mode == Mode::RGBA)
|
||||
? (2 * (st::colorEditSkip - st::colorSliderSkip) + _hueSlider->width())
|
||||
: (2 * st::colorEditSkip))
|
||||
+ st::colorSampleSize.width();
|
||||
auto left = (width() - fullwidth) / 2;
|
||||
_picker->moveToLeft(left, st::colorEditSkip);
|
||||
_hueSlider->setGeometryToLeft(_picker->x() + _picker->width() + st::colorEditSkip - st::colorSliderSkip, st::colorEditSkip - st::colorSliderSkip, _hueSlider->width(), st::colorPickerSize + 2 * st::colorSliderSkip);
|
||||
_opacitySlider->setGeometryToLeft(_picker->x() - st::colorSliderSkip, _picker->y() + _picker->height() + st::colorEditSkip - st::colorSliderSkip, _picker->width() + 2 * st::colorSliderSkip, _opacitySlider->height());
|
||||
auto fieldLeft = _hueSlider->x() + _hueSlider->width() - st::colorSliderSkip + st::colorEditSkip;
|
||||
auto fieldWidth = st::colorSampleSize.width();
|
||||
auto fieldHeight = _hueField->height();
|
||||
if (_hueSlider) {
|
||||
_hueSlider->setGeometryToLeft(_picker->x() + _picker->width() + st::colorEditSkip - st::colorSliderSkip, st::colorEditSkip - st::colorSliderSkip, _hueSlider->width(), st::colorPickerSize + 2 * st::colorSliderSkip);
|
||||
}
|
||||
if (_opacitySlider) {
|
||||
_opacitySlider->setGeometryToLeft(_picker->x() - st::colorSliderSkip, _picker->y() + _picker->height() + st::colorEditSkip - st::colorSliderSkip, _picker->width() + 2 * st::colorSliderSkip, _opacitySlider->height());
|
||||
}
|
||||
if (_lightnessSlider) {
|
||||
_lightnessSlider->setGeometryToLeft(_picker->x() - st::colorSliderSkip, _picker->y() + _picker->height() + st::colorEditSkip - st::colorSliderSkip, _picker->width() + 2 * st::colorSliderSkip, _lightnessSlider->height());
|
||||
}
|
||||
const auto fieldLeft = (_mode == Mode::RGBA)
|
||||
? (_hueSlider->x() + _hueSlider->width() + st::colorEditSkip - st::colorSliderSkip)
|
||||
: (_picker->x() + _picker->width() + st::colorEditSkip);
|
||||
const auto addWidth = (_mode == Mode::RGBA) ? 0 : st::colorEditSkip;
|
||||
const auto fieldWidth = st::colorSampleSize.width() + addWidth;
|
||||
const auto fieldHeight = _hueField->height();
|
||||
_newRect = QRect(fieldLeft, st::colorEditSkip, fieldWidth, st::colorSampleSize.height());
|
||||
_currentRect = _newRect.translated(0, st::colorSampleSize.height());
|
||||
_hueField->setGeometryToLeft(fieldLeft, _currentRect.y() + _currentRect.height() + st::colorFieldSkip, fieldWidth, fieldHeight);
|
||||
|
@ -769,7 +896,13 @@ void EditColorBox::resizeEvent(QResizeEvent *e) {
|
|||
_redField->setGeometryToLeft(fieldLeft, _brightnessField->y() + _brightnessField->height() + st::colorFieldSkip, fieldWidth, fieldHeight);
|
||||
_greenField->setGeometryToLeft(fieldLeft, _redField->y() + _redField->height(), fieldWidth, fieldHeight);
|
||||
_blueField->setGeometryToLeft(fieldLeft, _greenField->y() + _greenField->height(), fieldWidth, fieldHeight);
|
||||
_result->setGeometryToLeft(fieldLeft - (st::colorEditSkip + st::colorSliderWidth), _opacitySlider->y() + _opacitySlider->height() - st::colorSliderSkip - _result->height(), fieldWidth + (st::colorEditSkip + st::colorSliderWidth), fieldHeight);
|
||||
const auto resultDelta = (_mode == Mode::RGBA)
|
||||
? (st::colorEditSkip + st::colorSliderWidth)
|
||||
: 0;
|
||||
const auto resultBottom = (_mode == Mode::RGBA)
|
||||
? (_opacitySlider->y() + _opacitySlider->height())
|
||||
: (_lightnessSlider->y() + _lightnessSlider->height());
|
||||
_result->setGeometryToLeft(fieldLeft - resultDelta, resultBottom - st::colorSliderSkip - _result->height(), fieldWidth + resultDelta, fieldHeight);
|
||||
}
|
||||
|
||||
void EditColorBox::paintEvent(QPaintEvent *e) {
|
||||
|
@ -795,39 +928,56 @@ void EditColorBox::mousePressEvent(QMouseEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
EditColorBox::HSB EditColorBox::hsbFromControls() const {
|
||||
const auto hue = (_mode == Mode::RGBA)
|
||||
? qRound((1. - _hueSlider->value()) * 360)
|
||||
: qRound(_picker->valueX() * 360);
|
||||
const auto saturation = (_mode == Mode::RGBA)
|
||||
? qRound(_picker->valueX() * 255)
|
||||
: qRound((1. - _picker->valueY()) * 255);
|
||||
const auto brightness = (_mode == Mode::RGBA)
|
||||
? qRound((1. - _picker->valueY()) * 255)
|
||||
: qRound(_lightnessSlider->value() * 255);
|
||||
return { hue, saturation, brightness };
|
||||
}
|
||||
|
||||
void EditColorBox::updateFromColor(QColor color) {
|
||||
_new = color;
|
||||
updateControlsFromColor();
|
||||
updateRGBFields();
|
||||
updateHSVFields();
|
||||
updateHSBFields();
|
||||
updateResultField();
|
||||
update();
|
||||
}
|
||||
|
||||
void EditColorBox::updateFromControls() {
|
||||
auto hue = qRound((1. - _hueSlider->value()) * 360);
|
||||
auto saturation = qRound(_picker->valueX() * 255);
|
||||
auto brightness = qRound((1. - _picker->valueY()) * 255);
|
||||
auto alpha = qRound(_opacitySlider->value() * 255);
|
||||
setHSV(hue, saturation, brightness, alpha);
|
||||
updateHSVFields();
|
||||
updateControlsFromHSV(hue, saturation, brightness);
|
||||
const auto hsb = hsbFromControls();
|
||||
const auto alpha = _opacitySlider
|
||||
? qRound(_opacitySlider->value() * 255)
|
||||
: 255;
|
||||
setHSB(hsb, alpha);
|
||||
updateHSBFields();
|
||||
updateControlsFromHSB(hsb);
|
||||
}
|
||||
|
||||
void EditColorBox::updateFromHSVFields() {
|
||||
void EditColorBox::updateFromHSBFields() {
|
||||
auto hue = _hueField->value();
|
||||
auto saturation = percentToByte(_saturationField->value());
|
||||
auto brightness = percentToByte(_brightnessField->value());
|
||||
auto alpha = qRound(_opacitySlider->value() * 255);
|
||||
setHSV(hue, saturation, brightness, alpha);
|
||||
updateControlsFromHSV(hue, saturation, brightness);
|
||||
auto alpha = _opacitySlider
|
||||
? qRound(_opacitySlider->value() * 255)
|
||||
: 255;
|
||||
setHSB({ hue, saturation, brightness }, alpha);
|
||||
updateControlsFromHSB({ hue, saturation, brightness });
|
||||
}
|
||||
|
||||
void EditColorBox::updateFromRGBFields() {
|
||||
auto red = _redField->value();
|
||||
auto blue = _blueField->value();
|
||||
auto green = _greenField->value();
|
||||
auto alpha = qRound(_opacitySlider->value() * 255);
|
||||
auto alpha = _opacitySlider
|
||||
? qRound(_opacitySlider->value() * 255)
|
||||
: 255;
|
||||
setRGB(red, green, blue, alpha);
|
||||
updateResultField();
|
||||
}
|
||||
|
@ -858,10 +1008,17 @@ void EditColorBox::updateFromResultField() {
|
|||
updateRGBFields();
|
||||
}
|
||||
|
||||
void EditColorBox::updateControlsFromHSV(int hue, int saturation, int brightness) {
|
||||
_picker->setHSV(hue, saturation, brightness);
|
||||
_hueSlider->setHSV(hue, saturation, brightness);
|
||||
_opacitySlider->setHSV(hue, saturation, brightness);
|
||||
void EditColorBox::updateControlsFromHSB(HSB hsb) {
|
||||
_picker->setHSB(hsb);
|
||||
if (_hueSlider) {
|
||||
_hueSlider->setHSB(hsb);
|
||||
}
|
||||
if (_opacitySlider) {
|
||||
_opacitySlider->setHSB(hsb);
|
||||
}
|
||||
if (_lightnessSlider) {
|
||||
_lightnessSlider->setHSB(hsb);
|
||||
}
|
||||
}
|
||||
|
||||
void EditColorBox::updateControlsFromColor() {
|
||||
|
@ -870,13 +1027,24 @@ void EditColorBox::updateControlsFromColor() {
|
|||
auto blue = _new.blue();
|
||||
auto alpha = _new.alpha();
|
||||
_picker->setRGB(red, green, blue);
|
||||
_hueSlider->setRGB(red, green, blue);
|
||||
_opacitySlider->setRGB(red, green, blue);
|
||||
_opacitySlider->setAlpha(alpha);
|
||||
if (_hueSlider) {
|
||||
_hueSlider->setRGB(red, green, blue);
|
||||
}
|
||||
if (_opacitySlider) {
|
||||
_opacitySlider->setRGB(red, green, blue);
|
||||
_opacitySlider->setAlpha(alpha);
|
||||
}
|
||||
if (_lightnessSlider) {
|
||||
_lightnessSlider->setRGB(red, green, blue);
|
||||
}
|
||||
}
|
||||
|
||||
void EditColorBox::setHSV(int hue, int saturation, int value, int alpha) {
|
||||
_new.setHsv(hue, saturation, value, alpha);
|
||||
void EditColorBox::setHSB(HSB hsb, int alpha) {
|
||||
if (_mode == Mode::RGBA) {
|
||||
_new.setHsv(hsb.hue, hsb.saturation, hsb.brightness, alpha);
|
||||
} else {
|
||||
_new.setHsl(hsb.hue, hsb.saturation, hsb.brightness, alpha);
|
||||
}
|
||||
updateRGBFields();
|
||||
updateResultField();
|
||||
update();
|
||||
|
@ -885,6 +1053,6 @@ void EditColorBox::setHSV(int hue, int saturation, int value, int alpha) {
|
|||
void EditColorBox::setRGB(int red, int green, int blue, int alpha) {
|
||||
_new.setRgb(red, green, blue, alpha);
|
||||
updateControlsFromColor();
|
||||
updateHSVFields();
|
||||
updateHSBFields();
|
||||
update();
|
||||
}
|
|
@ -11,7 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
class EditColorBox : public BoxContent {
|
||||
public:
|
||||
EditColorBox(QWidget*, const QString &title, QColor current = QColor(255, 255, 255));
|
||||
enum class Mode {
|
||||
RGBA,
|
||||
HSL,
|
||||
};
|
||||
EditColorBox(QWidget*, const QString &title, Mode mode, QColor current);
|
||||
|
||||
void setLightnessLimits(int min, int max);
|
||||
|
||||
void setSaveCallback(Fn<void(QColor)> callback) {
|
||||
_saveCallback = std::move(callback);
|
||||
|
@ -36,20 +42,26 @@ protected:
|
|||
void setInnerFocus() override;
|
||||
|
||||
private:
|
||||
struct HSB { // HSV or HSL depending on Mode.
|
||||
int hue = 0;
|
||||
int saturation = 0;
|
||||
int brightness = 0;
|
||||
};
|
||||
void saveColor();
|
||||
void fieldSubmitted();
|
||||
|
||||
[[nodiscard]] HSB hsbFromControls() const;
|
||||
void updateFromColor(QColor color);
|
||||
void updateControlsFromColor();
|
||||
void updateControlsFromHSV(int hue, int saturation, int brightness);
|
||||
void updateHSVFields();
|
||||
void updateControlsFromHSB(HSB hsb);
|
||||
void updateHSBFields();
|
||||
void updateRGBFields();
|
||||
void updateResultField();
|
||||
void updateFromControls();
|
||||
void updateFromHSVFields();
|
||||
void updateFromHSBFields();
|
||||
void updateFromRGBFields();
|
||||
void updateFromResultField();
|
||||
void setHSV(int hue, int saturation, int brightness, int alpha);
|
||||
void setHSB(HSB hsb, int alpha);
|
||||
void setRGB(int red, int green, int blue, int alpha);
|
||||
|
||||
int percentFromByte(int byte) {
|
||||
|
@ -65,10 +77,12 @@ private:
|
|||
class ResultField;
|
||||
|
||||
QString _title;
|
||||
Mode _mode = Mode();
|
||||
|
||||
object_ptr<Picker> _picker;
|
||||
object_ptr<Slider> _hueSlider;
|
||||
object_ptr<Slider> _opacitySlider;
|
||||
object_ptr<Slider> _hueSlider = { nullptr };
|
||||
object_ptr<Slider> _opacitySlider = { nullptr };
|
||||
object_ptr<Slider> _lightnessSlider = { nullptr };
|
||||
|
||||
object_ptr<Field> _hueField;
|
||||
object_ptr<Field> _saturationField;
|
||||
|
|
|
@ -183,7 +183,7 @@ void ColorsPalette::show(Type type) {
|
|||
const auto inner = _outer->entity();
|
||||
const auto size = st::settingsAccentColorSize;
|
||||
for (const auto &color : list) {
|
||||
const auto selected = color == current;
|
||||
const auto selected = (color == current);
|
||||
const auto button = CreateColorButton(inner, color, selected);
|
||||
button->clicks(
|
||||
) | rpl::map([=] {
|
||||
|
@ -196,9 +196,16 @@ void ColorsPalette::show(Type type) {
|
|||
const auto custom = CreateCustomButton(inner, std::move(list));
|
||||
custom->clicks(
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto colorizer = Window::Theme::ColorizerFrom(
|
||||
*scheme,
|
||||
scheme->accentColor);
|
||||
const auto box = Ui::show(Box<EditColorBox>(
|
||||
"Choose accent color",
|
||||
tr::lng_settings_theme_accent_title(tr::now),
|
||||
EditColorBox::Mode::HSL,
|
||||
current));
|
||||
box->setLightnessLimits(
|
||||
colorizer.lightnessMin,
|
||||
colorizer.lightnessMax);
|
||||
box->setSaveCallback(crl::guard(custom, [=](QColor result) {
|
||||
_selected.fire_copy(result);
|
||||
}));
|
||||
|
@ -1006,28 +1013,14 @@ void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container) {
|
|||
const auto colorizer = Window::Theme::ColorizerFrom(scheme, color);
|
||||
apply(scheme, &colorizer);
|
||||
};
|
||||
const auto applyWithColorize = [=](const Scheme &scheme) {
|
||||
const auto &colors = Core::App().settings().themesAccentColors();
|
||||
const auto color = colors.get(scheme.type);
|
||||
const auto box = Ui::show(Box<EditColorBox>(
|
||||
"Choose accent color",
|
||||
color.value_or(scheme.accentColor)));
|
||||
box->setSaveCallback([=](QColor result) {
|
||||
applyWithColor(scheme, result);
|
||||
});
|
||||
};
|
||||
const auto schemeClicked = [=](
|
||||
const Scheme &scheme,
|
||||
Qt::KeyboardModifiers modifiers) {
|
||||
if (scheme.accentColor.hue() && (modifiers & Qt::ControlModifier)) {
|
||||
applyWithColorize(scheme);
|
||||
const auto &colors = Core::App().settings().themesAccentColors();
|
||||
if (const auto color = colors.get(scheme.type)) {
|
||||
applyWithColor(scheme, *color);
|
||||
} else {
|
||||
const auto &colors = Core::App().settings().themesAccentColors();
|
||||
if (const auto color = colors.get(scheme.type)) {
|
||||
applyWithColor(scheme, *color);
|
||||
} else {
|
||||
apply(scheme);
|
||||
}
|
||||
apply(scheme);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -293,7 +293,7 @@ void EditorBlock::activateRow(const Row &row) {
|
|||
}
|
||||
} else {
|
||||
_editing = findRowIndex(&row);
|
||||
if (auto box = Ui::show(Box<EditColorBox>(row.name(), row.value()))) {
|
||||
if (auto box = Ui::show(Box<EditColorBox>(row.name(), EditColorBox::Mode::RGBA, row.value()))) {
|
||||
box->setSaveCallback(crl::guard(this, [this](QColor value) {
|
||||
saveEditing(value);
|
||||
}));
|
||||
|
|
|
@ -114,11 +114,32 @@ Colorizer ColorizerFrom(const EmbeddedScheme &scheme, const QColor &color) {
|
|||
&result.now.lightness);
|
||||
switch (scheme.type) {
|
||||
case EmbeddedType::DayBlue:
|
||||
//result.keepContrast = base::flat_map<QLatin1String, Color>{ {
|
||||
// { qstr("test"), cColor("aaaaaa") },
|
||||
//} };
|
||||
result.lightnessMax = 191;
|
||||
break;
|
||||
case EmbeddedType::Night:
|
||||
result.keepContrast = base::flat_map<QLatin1String, Color>{ {
|
||||
{ qstr("windowFgActive"), cColor("5288c1") }, // windowBgActive
|
||||
{ qstr("activeButtonFg"), cColor("2f6ea5") }, // activeButtonBg
|
||||
{ qstr("profileVerifiedCheckFg"), cColor("5288c1") }, // profileVerifiedCheckBg
|
||||
{ qstr("overviewCheckFgActive"), cColor("5288c1") }, // overviewCheckBgActive
|
||||
} };
|
||||
result.lightnessMin = 64;
|
||||
break;
|
||||
case EmbeddedType::NightGreen:
|
||||
result.keepContrast = base::flat_map<QLatin1String, Color>{ {
|
||||
{ qstr("windowFgActive"), cColor("3fc1b0") }, // windowBgActive
|
||||
{ qstr("activeButtonFg"), cColor("2da192") }, // activeButtonBg
|
||||
{ qstr("profileVerifiedCheckFg"), cColor("3fc1b0") }, // profileVerifiedCheckBg
|
||||
{ qstr("overviewCheckFgActive"), cColor("3fc1b0") }, // overviewCheckBgActive
|
||||
{ qstr("callIconFg"), cColor("5ad1c1") }, // callAnswerBg
|
||||
} };
|
||||
result.lightnessMin = 64;
|
||||
break;
|
||||
}
|
||||
result.now.lightness = std::clamp(
|
||||
result.now.lightness,
|
||||
result.lightnessMin,
|
||||
result.lightnessMax);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,8 @@ struct Colorizer {
|
|||
int lightness = 0;
|
||||
};
|
||||
int hueThreshold = 0;
|
||||
int lightnessMin = 0;
|
||||
int lightnessMax = 255;
|
||||
Color was;
|
||||
Color now;
|
||||
base::flat_set<QLatin1String> ignoreKeys;
|
||||
|
|
Loading…
Add table
Reference in a new issue