diff --git a/app/app.pro b/app/app.pro index e1cf3eb823..80ca129b61 100644 --- a/app/app.pro +++ b/app/app.pro @@ -79,6 +79,7 @@ HEADERS += \ src/basewidget.h \ src/appearance.h \ src/buttonappearancewatcher.h \ + src/colorpreviewwidget.h \ src/importlayersdialog.h \ src/importpositiondialog.h \ src/layeropacitydialog.h \ @@ -136,6 +137,7 @@ SOURCES += \ src/addtransparencytopaperdialog.cpp \ src/basewidget.cpp \ src/buttonappearancewatcher.cpp \ + src/colorpreviewwidget.cpp \ src/importlayersdialog.cpp \ src/importpositiondialog.cpp \ src/layeropacitydialog.cpp \ diff --git a/app/src/colorinspector.cpp b/app/src/colorinspector.cpp index 6b8c72cdfe..37cb34caf5 100644 --- a/app/src/colorinspector.cpp +++ b/app/src/colorinspector.cpp @@ -56,23 +56,15 @@ void ColorInspector::initUI() } onColorSpecChanged(); - ui->redSlider->init(ColorSlider::ColorSpecType::RGB, ColorSlider::ColorType::RED, mCurrentColor, 0.0, 255.0); - ui->greenSlider->init(ColorSlider::ColorSpecType::RGB, ColorSlider::ColorType::GREEN, mCurrentColor, 0.0, 255.0); - ui->blueSlider->init(ColorSlider::ColorSpecType::RGB, ColorSlider::ColorType::BLUE, mCurrentColor, 0.0, 255.0); - ui->rgbAlphaSlider->init(ColorSlider::ColorSpecType::RGB, ColorSlider::ColorType::ALPHA, mCurrentColor, 0.0, 255.0); + ui->redSlider->init(ColorSlider::ColorSpecType::RGB, ColorSlider::ColorType::RED, mCurrentColor); + ui->greenSlider->init(ColorSlider::ColorSpecType::RGB, ColorSlider::ColorType::GREEN, mCurrentColor); + ui->blueSlider->init(ColorSlider::ColorSpecType::RGB, ColorSlider::ColorType::BLUE, mCurrentColor); + ui->rgbAlphaSlider->init(ColorSlider::ColorSpecType::RGB, ColorSlider::ColorType::ALPHA, mCurrentColor); - ui->hueSlider->init(ColorSlider::ColorSpecType::HSV, ColorSlider::ColorType::HUE, mCurrentColor, 0.0, 359.0); - ui->saturationSlider->init(ColorSlider::ColorSpecType::HSV, ColorSlider::ColorType::SAT, mCurrentColor, 0.0, 255.0); - ui->valueSlider->init(ColorSlider::ColorSpecType::HSV, ColorSlider::ColorType::VAL, mCurrentColor, 0.0, 255.0); - ui->hsvAlphaSlider->init(ColorSlider::ColorSpecType::HSV, ColorSlider::ColorType::ALPHA, mCurrentColor, 0.0, 255.0); - - QPalette p1 = ui->colorWrapper->palette(); - p1.setBrush(QPalette::Window, QBrush(QImage(":/background/checkerboard.png"))); - ui->colorWrapper->setPalette(p1); - - QPalette p2 = ui->color->palette(); - p2.setColor(QPalette::Window, mCurrentColor); - ui->color->setPalette(p2); + ui->hueSlider->init(ColorSlider::ColorSpecType::HSV, ColorSlider::ColorType::HUE, mCurrentColor); + ui->saturationSlider->init(ColorSlider::ColorSpecType::HSV, ColorSlider::ColorType::SAT, mCurrentColor); + ui->valueSlider->init(ColorSlider::ColorSpecType::HSV, ColorSlider::ColorType::VAL, mCurrentColor); + ui->hsvAlphaSlider->init(ColorSlider::ColorSpecType::HSV, ColorSlider::ColorType::ALPHA, mCurrentColor); connect(ui->colorSpecTabWidget, &QTabWidget::currentChanged, this, &ColorInspector::onColorSpecChanged); @@ -179,9 +171,8 @@ void ColorInspector::updateControls() ui->valueSpinBox->setValue(qRound(mCurrentColor.value() / 2.55)); ui->hsvAlphaSpinBox->setValue(qRound(mCurrentColor.alpha() / 2.55)); - QPalette p = ui->color->palette(); - p.setColor(QPalette::Window, mCurrentColor); - ui->color->setPalette(p); + + ui->colorPreview->setColor(mCurrentColor); update(); } @@ -200,7 +191,9 @@ void ColorInspector::onColorSpecChanged() } else { - mCurrentColor = mCurrentColor.toHsv(); + if (mCurrentColor.hue() != -1) { + mCurrentColor = mCurrentColor.toHsv(); + } } updateControls(); diff --git a/app/src/colorpreviewwidget.cpp b/app/src/colorpreviewwidget.cpp new file mode 100644 index 0000000000..5ebd0e31c7 --- /dev/null +++ b/app/src/colorpreviewwidget.cpp @@ -0,0 +1,43 @@ +/* + +Pencil2D - Traditional Animation Software +Copyright (C) 2026 Oliver Stevns Larsen + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +*/ +#include "colorpreviewwidget.h" + +#include +#include + +ColorPreviewWidget::ColorPreviewWidget(QWidget*) +{ + +} + +void ColorPreviewWidget::setColor(const QColor& color) +{ + if (color == mColor) { return; } + + mColor = color; + update(); +} + +void ColorPreviewWidget::paintEvent(QPaintEvent* event) +{ + QPainter painter(this); + + painter.setPen(Qt::NoPen); + painter.setBrush(QBrush(mCheckerboard)); + painter.drawRect(event->rect()); + + painter.fillRect(event->rect(), mColor); +} diff --git a/app/src/colorpreviewwidget.h b/app/src/colorpreviewwidget.h new file mode 100644 index 0000000000..e479d4f06e --- /dev/null +++ b/app/src/colorpreviewwidget.h @@ -0,0 +1,41 @@ +/* + +Pencil2D - Traditional Animation Software +Copyright (C) 2026 Oliver Stevns Larsen + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +*/ +#ifndef COLORPREVIEWWIDGET_H +#define COLORPREVIEWWIDGET_H + +#include +#include + +class ColorPreviewWidget: public QWidget +{ + Q_OBJECT +public: + explicit ColorPreviewWidget(QWidget* = nullptr); + + void setColor(const QColor& color); + +protected: + void paintEvent(QPaintEvent* event) override; + +private: + + QPixmap mColorPreviewPixmap; + QPixmap mCheckerboard = QPixmap(":/background/checkerboard.png"); + + QColor mColor; +}; + +#endif // COLORPREVIEWWIDGET_H diff --git a/app/src/colorslider.cpp b/app/src/colorslider.cpp index 1f67e05853..3e6975775b 100644 --- a/app/src/colorslider.cpp +++ b/app/src/colorslider.cpp @@ -21,7 +21,6 @@ GNU General Public License for more details. #include #include - ColorSlider::ColorSlider(QWidget* parent) : QWidget(parent) { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); @@ -32,10 +31,8 @@ ColorSlider::~ColorSlider() } -void ColorSlider::init(ColorSpecType specType, ColorType type, const QColor &color, qreal min, qreal max) +void ColorSlider::init(ColorSpecType specType, ColorType type, const QColor &color) { - mMin = min; - mMax = max; mColor = color; mColorType = type; mSpecType = specType; @@ -43,9 +40,15 @@ void ColorSlider::init(ColorSpecType specType, ColorType type, const QColor &col update(); } -void ColorSlider::paintEvent(QPaintEvent *) +void ColorSlider::setupPicker() +{ + QRectF sliderRect = SliderGeometry::contentsRect(contentsRect(), mSliderStyle.borderWidth); + mPickerSize = QSizeF(10, sliderRect.bottom() - sliderRect.top() - mSliderStyle.borderWidth); +} + +void ColorSlider::paintEvent(QPaintEvent* event) { - drawColorBox(mColor, size()); + drawColorBox(mColor, event->rect().size()); QPainter painter(this); painter.drawPixmap(0, 0, mBoxPixmapSource); @@ -54,6 +57,26 @@ void ColorSlider::paintEvent(QPaintEvent *) drawPicker(mColor); } +int ColorSlider::colorTypeMax() const +{ + switch (mColorType) + { + case HUE: return 359; + case RED: + case GREEN: + case BLUE: + case SAT: + case VAL: + case ALPHA: return 255; + default: Q_UNREACHABLE(); + } +} + +int ColorSlider::colorSteps() const +{ + return colorTypeMax() + 1; +} + QLinearGradient ColorSlider::setColorSpec(const QColor &color) { switch (mSpecType) @@ -70,39 +93,40 @@ QLinearGradient ColorSlider::setColorSpec(const QColor &color) QLinearGradient ColorSlider::rgbGradient(const QColor &color) { int val = 0; + int max = colorSteps(); switch (mColorType) { case RED: - for (; val < mMax; val += 1) + for (; val < max; val += 1) { - mGradient.setColorAt(val / mMax, QColor::fromRgb(val, + mGradient.setColorAt(static_cast(val) / max, QColor::fromRgb(val, 255, 255, color.alpha())); } break; case GREEN: - for (; val < mMax; val += 1) + for (; val < max; val += 1) { - mGradient.setColorAt(val / mMax, QColor::fromRgb(color.red(), + mGradient.setColorAt(static_cast(val) / max, QColor::fromRgb(color.red(), val, color.blue(), color.alpha())); } break; case BLUE: - for (; val < mMax; val += 1) + for (; val < max; val += 1) { - mGradient.setColorAt(val / mMax, QColor::fromRgb(color.red(), + mGradient.setColorAt(static_cast(val) / max, QColor::fromRgb(color.red(), color.green(), val, color.alpha())); } break; case ALPHA: - for (; val < mMax; val += 1) + for (; val < max; val += 1) { - mGradient.setColorAt(val / mMax, QColor::fromRgb(0, + mGradient.setColorAt(static_cast(val) / max, QColor::fromRgb(0, 0, 0, val)); @@ -117,39 +141,40 @@ QLinearGradient ColorSlider::rgbGradient(const QColor &color) QLinearGradient ColorSlider::hsvGradient(const QColor &color) { int val = 0; + int max = colorSteps(); switch (mColorType) { case HUE: - for (; val < mMax; val += 1) + for (; val < max; val += 1) { - mGradient.setColorAt(val / mMax, QColor::fromHsv(val, + mGradient.setColorAt(static_cast(val) / max, QColor::fromHsv(val, 255, 255, color.alpha())); } break; case SAT: - for (; val < mMax; val += 1) + for (; val < max; val += 1) { - mGradient.setColorAt(val / mMax, QColor::fromHsv(color.hsvHue(), + mGradient.setColorAt(static_cast(val) / max, QColor::fromHsv(color.hsvHue(), val, color.value(), color.alpha())); } break; case VAL: - for (; val < mMax; val += 1) + for (; val < max; val += 1) { - mGradient.setColorAt(val / mMax, QColor::fromHsv(color.hsvHue(), + mGradient.setColorAt(static_cast(val) / max, QColor::fromHsv(color.hsvHue(), color.hsvSaturation(), val, color.alpha())); } break; case ALPHA: - for (; val < mMax; val += 1) + for (; val < max; val += 1) { - mGradient.setColorAt(val / mMax, QColor::fromHsv(0, + mGradient.setColorAt(static_cast(val) / max, QColor::fromHsv(0, 0, 0, val)); @@ -161,6 +186,32 @@ QLinearGradient ColorSlider::hsvGradient(const QColor &color) return mGradient; } +void ColorSlider::setRgb(const QColor &rgb) +{ + mColor.setRgb(rgb.red(), + rgb.green(), + rgb.blue(), + rgb.alpha()); + + mPixmapCacheInvalid = true; +} + +void ColorSlider::setHsv(const QColor &hsv) +{ + mColor.setHsv(hsv.hsvHue(), + hsv.hsvSaturation(), + hsv.value(), + hsv.alpha()); + + mPixmapCacheInvalid = true; +} + +void ColorSlider::resizeEvent(QResizeEvent*) +{ + mPixmapCacheInvalid = true; + update(); +} + void ColorSlider::drawColorBox(const QColor &color, QSize size) { QStyleOption option; @@ -168,58 +219,27 @@ void ColorSlider::drawColorBox(const QColor &color, QSize size) QBrush backgroundBrush = option.palette.window(); - mBoxPixmapSource = QPixmap(size); - - QPainter painter(&mBoxPixmapSource); - painter.setRenderHint(QPainter::Antialiasing); + if (mPixmapCacheInvalid) { + setupPicker(); - painter.fillRect(mBoxPixmapSource.rect(), backgroundBrush); - - mGradient = QLinearGradient(0,0,mBoxPixmapSource.width(),0); - mGradient = setColorSpec(color); - - painter.end(); + QRectF sliderRect = SliderGeometry::contentsRect(contentsRect(), mSliderStyle.borderWidth); + mBoxPixmapSource = QPixmap(size * devicePixelRatio()); + mBoxPixmapSource.setDevicePixelRatio(devicePixelRatioF()); + mBoxPixmapSource.fill(Qt::transparent); + mPixmapCacheInvalid = false; - // draw checkerboard background - painter.begin(&mBoxPixmapSource); - QBrush brush2(QBrush(QPixmap(":icons/general/checkerboard_smaller.png"))); - - painter.setBrush(brush2); - QPen pen2; - pen2.setWidthF(0); - pen2.setColor(Qt::gray); - pen2.setCosmetic(false); - painter.setPen(pen2); - painter.drawRoundedRect(0, - 0, - mBoxPixmapSource.width(), - mBoxPixmapSource.height(), - 4, - mBoxPixmapSource.width(), - Qt::SizeMode::AbsoluteSize); + mGradient = QLinearGradient(0,0,sliderRect.width(),0); + mGradient = setColorSpec(color); - painter.end(); + QPainter painter(&mBoxPixmapSource); - painter.begin(&mBoxPixmapSource); - painter.setRenderHint(QPainter::Antialiasing); + mSliderStyle.customFill = QBrush(mCheckerboardPixmap); + SliderPainter::drawSliderStyle(painter, sliderRect, mSliderStyle, option.palette); - QBrush brush(mGradient); - QPen pen; - pen.setWidthF(0); - pen.setColor(Qt::gray); - pen.setCosmetic(false); - painter.setPen(pen); - - painter.setBrush(brush); - - painter.drawRoundedRect(0, - 0, - mBoxPixmapSource.width(), - mBoxPixmapSource.height(), - 4, - mBoxPixmapSource.width(), - Qt::SizeMode::AbsoluteSize); - painter.end(); + QBrush brush(mGradient); + mSliderStyle.customFill = brush; + SliderPainter::drawSliderStyle(painter, sliderRect, mSliderStyle, option.palette); + } } QSize ColorSlider::sizeHint() const @@ -241,11 +261,11 @@ void ColorSlider::drawPicker(const QColor &color) { QPainter painter(this); qreal val = 0; - QSize mPickerSize = QSize(10, this->height() - 1); - QPen pen; - pen.setWidth(0); - pen.setColor(QColor(0, 0, 0, 255)); + const qreal borderWidth = mSliderStyle.borderWidth; + const qreal inset = SliderGeometry::penStrokeInset(borderWidth); + const QRectF innerSliderRect = SliderGeometry::contentsRect(contentsRect(), borderWidth) + .adjusted(borderWidth, borderWidth, -borderWidth, -borderWidth); switch (mSpecType) { @@ -253,21 +273,13 @@ void ColorSlider::drawPicker(const QColor &color) switch (mColorType) { case HUE: - val = color.hsvHueF() * (mBoxPixmapSource.width() - mPickerSize.width()); + val = color.hsvHueF(); break; case SAT: - if ((color.hsvSaturation() > 127 || color.value() < 127) && color.alpha() > 127) - { - pen.setColor(Qt::white); - } - val = color.hsvSaturationF() * (mBoxPixmapSource.width() - mPickerSize.width()); + val = color.hsvSaturationF(); break; case VAL: - if (color.value() < 127 && color.alpha() > 127) - { - pen.setColor(Qt::white); - } - val = color.valueF() * (mBoxPixmapSource.width() - mPickerSize.width()); + val = color.valueF(); break; case ALPHA: break; @@ -279,21 +291,13 @@ void ColorSlider::drawPicker(const QColor &color) switch (mColorType) { case RED: - val = color.redF() * (mBoxPixmapSource.width() - mPickerSize.width()); + val = color.redF(); break; case GREEN: - if (color.alpha() > 127) - { - pen.setColor(Qt::white); - } - val = color.greenF() * (mBoxPixmapSource.width() - mPickerSize.width()); + val = color.greenF(); break; case BLUE: - if (color.alpha() > 127) - { - pen.setColor(Qt::white); - } - val = color.blueF() * (mBoxPixmapSource.width() - mPickerSize.width()); + val = color.blueF(); break; case ALPHA: break; @@ -306,27 +310,61 @@ void ColorSlider::drawPicker(const QColor &color) } if (mColorType == ALPHA) { - if (color.alpha() > 127) - { - pen.setColor(Qt::white); - } - val = color.alphaF() * (mBoxPixmapSource.width() - mPickerSize.width()); + val = color.alphaF(); } - painter.setPen(pen); - painter.drawRect(static_cast(val), 0, mPickerSize.width(), mPickerSize.height()); - painter.end(); + const qreal maxDistance = SliderGeometry::pickerMaxDistance(innerSliderRect.width(), mPickerSize.width()); + val = static_cast(innerSliderRect.left() + qMax(static_cast(mMin), (val * maxDistance))) + inset; + + QPen ounterPen; + ounterPen.setJoinStyle(Qt::MiterJoin); + ounterPen.setWidthF(mSliderStyle.borderWidth); + ounterPen.setColor(QColor(0, 0, 0, 255)); + + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(ounterPen); + + QRectF pickerOuterRect = QRectF(val, + innerSliderRect.top(), + mPickerSize.width(), + innerSliderRect.height()); + + painter.drawRoundedRect(pickerOuterRect, + mSliderStyle.cachedCornerRadiusX, + mSliderStyle.cachedCornerRadiusY, + Qt::AbsoluteSize); + + QPen innerPen; + innerPen.setJoinStyle(Qt::MiterJoin); + innerPen.setWidthF(mSliderStyle.borderWidth); + innerPen.setColor(palette().dark().color()); + painter.setPen(innerPen); + + // Draw inner picker + painter.drawRoundedRect(pickerOuterRect.adjusted( + mSliderStyle.borderWidth, + mSliderStyle.borderWidth, + -mSliderStyle.borderWidth, + -mSliderStyle.borderWidth), + SliderGeometry::innerCornerRadius(mSliderStyle.cachedCornerRadiusX, mSliderStyle.borderWidth), + SliderGeometry::innerCornerRadius(mSliderStyle.cachedCornerRadiusY, mSliderStyle.borderWidth), + Qt::AbsoluteSize); } void ColorSlider::colorPicked(QPoint point) { + qreal borderWidth = mSliderStyle.borderWidth; + QRectF innerSliderRect = SliderGeometry::contentsRect(contentsRect(), borderWidth) + .adjusted(borderWidth, + borderWidth, + -borderWidth, + -borderWidth); QColor colorPicked = mColor; - int colorMax = static_cast(mMax); + int colorMax = colorTypeMax(); - int colorVal = point.x() * colorMax / mBoxPixmapSource.width(); - - colorVal = (colorVal > colorMax) ? colorMax : colorVal; - colorVal = (colorVal < 0) ? 0 : colorVal; + qreal pickerCenter = mPickerSize.width() * 0.5; + int colorVal = (point.x() - pickerCenter) * colorSteps() / SliderGeometry::pickerMaxDistance(innerSliderRect.width(), mPickerSize.width()); + colorVal = qBound(mMin, colorVal, colorMax); switch (mSpecType) { @@ -415,6 +453,9 @@ void ColorSlider::colorPicked(QPoint point) default: Q_UNREACHABLE(); } + mColor = colorPicked; + mPixmapCacheInvalid = true; + emit valueChanged(mColor); } diff --git a/app/src/colorslider.h b/app/src/colorslider.h index 037130e8a3..1a487b4c0a 100644 --- a/app/src/colorslider.h +++ b/app/src/colorslider.h @@ -19,6 +19,8 @@ GNU General Public License for more details. #include +#include "drawsliderstyle.h" +#include "slidergeometry.h" class ColorSlider : public QWidget { @@ -44,34 +46,24 @@ class ColorSlider : public QWidget explicit ColorSlider(QWidget* parent); ~ColorSlider() override; - void init(ColorSpecType specType, ColorType type, const QColor &color, qreal min, qreal max); + void init(ColorSpecType specType, ColorType type, const QColor &color); QLinearGradient setColorSpec(const QColor &color); QColor color() { return mColor; } - void setHsv(const QColor& hsv) { mColor.setHsv(hsv.hsvHue(), - hsv.hsvSaturation(), - hsv.value(), - hsv.alpha()); - } + void setHsv(const QColor& hsv); - void setRgb(const QColor& rgb) { mColor.setRgb(rgb.red(), - rgb.green(), - rgb.blue(), - rgb.alpha()); - } + void setRgb(const QColor& rgb); void setColorSpecType(ColorSpecType newType) { this->mSpecType = newType; } void setColorType(ColorType newType) { this->mColorType = newType; } - void setMin(qreal min) { mMin = min; } - void setMax(qreal max) { mMax = max; } - QSize sizeHint() const override; protected: void paintEvent(QPaintEvent* event) override; + void resizeEvent(QResizeEvent *event) override; void mouseMoveEvent(QMouseEvent* event) override; void mousePressEvent(QMouseEvent* event) override; @@ -80,6 +72,10 @@ class ColorSlider : public QWidget private: + int colorSteps() const; + int colorTypeMax() const; + + void setupPicker(); void drawColorBox(const QColor &color, QSize size); void drawPicker(const QColor &color); QLinearGradient hsvGradient(const QColor &color); @@ -87,16 +83,26 @@ class ColorSlider : public QWidget void colorPicked(QPoint point); + bool mPixmapCacheInvalid = true; QPixmap mBoxPixmapSource; QColor mColor; - qreal mMin = 0.0; - qreal mMax = 0.0; + int mMin = 0; + + QSizeF mPickerSize = QSize(-1, -1); ColorType mColorType = ColorType::HUE; ColorSpecType mSpecType = ColorSpecType::RGB; QLinearGradient mGradient; + + SliderPainterStyle mSliderStyle = SliderPainterStyle( + QPalette::Dark, + true, + QBrush(QPixmap(":icons/general/checkerboard_smaller.png")) + ); + + QPixmap mCheckerboardPixmap = QPixmap(":icons/general/checkerboard_smaller.png"); }; #endif // COLORSLIDER_H diff --git a/app/ui/colorinspector.ui b/app/ui/colorinspector.ui index 2140a289c6..9d0a9d03df 100644 --- a/app/ui/colorinspector.ui +++ b/app/ui/colorinspector.ui @@ -8,7 +8,7 @@ 0 0 120 - 263 + 220 @@ -24,6 +24,9 @@ + + 3 + 3 @@ -45,7 +48,7 @@ - 0 + 1 @@ -64,36 +67,8 @@ 3 - - - - H - - - - - - - S - - - - - - - V - - - - - - - A - - - - - + + 0 @@ -102,13 +77,13 @@ - - - - - 0 - 0 - + + + + % + + + 100 @@ -122,8 +97,32 @@ - - + + + + V + + + + + + + % + + + 100 + + + + + + + H + + + + + 0 @@ -142,8 +141,8 @@ - - + + % @@ -152,26 +151,46 @@ - - - - % - - - 100 + + + + + 0 + 0 + - - - - % + + + + S - - 100 + + + + + + A + + + + Qt::Orientation::Vertical + + + QSizePolicy::Policy::MinimumExpanding + + + + 0 + 0 + + + + @@ -191,22 +210,22 @@ 3 - - + + - A + B - - - - G + + + + 255 - - + + 0 @@ -215,20 +234,38 @@ - - - - - 0 - 0 - + + + + 255 - - + + - B + G + + + + + + + 255 + + + + + + + A + + + + + + + 255 @@ -242,8 +279,8 @@ - - + + 0 @@ -259,33 +296,31 @@ - - - - 255 + + + + + 0 + 0 + - - - - 255 + + + + Qt::Orientation::Vertical - - - - - - 255 + + QSizePolicy::Policy::MinimumExpanding - - - - - - 255 + + + 0 + 0 + - + @@ -297,10 +332,10 @@ true - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -316,15 +351,18 @@ 0 - - - true - - - QFrame::Box + + + + 0 + 0 + - - QFrame::Raised + + + 50 + 50 + @@ -340,6 +378,12 @@
colorslider.h
1 + + ColorPreviewWidget + QWidget +
colorpreviewwidget.h
+ 1 +
diff --git a/core_lib/core_lib.pro b/core_lib/core_lib.pro index 1968998c1b..863ce3e3af 100644 --- a/core_lib/core_lib.pro +++ b/core_lib/core_lib.pro @@ -96,6 +96,7 @@ HEADERS += \ src/util/cameraeasingtype.h \ src/util/camerafieldoption.h \ src/util/colordictionary.h \ + src/util/drawsliderstyle.h \ src/util/fileformat.h \ src/util/filetype.h \ src/util/importimageconfig.h \ @@ -107,6 +108,7 @@ HEADERS += \ src/util/pencilerror.h \ src/util/pencilsettings.h \ src/util/preferencesdef.h \ + src/util/slidergeometry.h \ src/util/transform.h \ src/util/util.h \ src/util/log.h \ @@ -185,10 +187,12 @@ SOURCES += src/graphics/bitmap/bitmapimage.cpp \ src/tool/transformtool.cpp \ src/util/blitrect.cpp \ src/util/cameraeasingtype.cpp \ + src/util/drawsliderstyle.cpp \ src/util/fileformat.cpp \ src/util/pencilerror.cpp \ src/util/pencilsettings.cpp \ src/util/log.cpp \ + src/util/slidergeometry.cpp \ src/util/transform.cpp \ src/util/util.cpp \ src/util/pointerevent.cpp \ diff --git a/core_lib/src/util/drawsliderstyle.cpp b/core_lib/src/util/drawsliderstyle.cpp new file mode 100644 index 0000000000..194b6c48ec --- /dev/null +++ b/core_lib/src/util/drawsliderstyle.cpp @@ -0,0 +1,78 @@ +/* + +Pencil2D - Traditional Animation Software +Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon +Copyright (C) 2012-2020 Matthew Chiawen Chang + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +*/ +#include "drawsliderstyle.h" + +QColor resolveColorRole(const QPalette& palette, QPalette::ColorRole role) +{ + if (role == QPalette::NoRole) { + return Qt::transparent; + } + return palette.color(role); +} + +QBrush resolveFill(const SliderPainterStyle& style, const QPalette& palette) +{ + if (style.hasCustomFill) { + return style.customFill; + } else { + return resolveColorRole(palette, style.fillRole); + } +} + +void SliderPainter::drawSliderStyle(QPainter& painter, const QRectF& rect, SliderPainterStyle& style, const QPalette& palette) +{ + updateSliderStyleCache(style, rect.size()); + + painter.save(); + painter.setRenderHint(QPainter::Antialiasing); + + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + + QPen pen = resolveColorRole(palette, style.strokeRole); + pen.setWidth(style.borderWidth); + painter.setPen(pen); + + painter.setBrush(resolveFill(style, palette)); + painter.drawRoundedRect(rect, + style.cachedCornerRadiusX, + style.cachedCornerRadiusY, + Qt::SizeMode::AbsoluteSize); + + painter.restore(); +} + +void SliderPainter::updateSliderStyleCache(SliderPainterStyle& style, const QSizeF& newSize) +{ + if (style.cachedSize == newSize) { + return; + } + + const qreal minRad = qMin(newSize.width(), newSize.height()); + const qreal maxRad = qMax(newSize.width(), newSize.height()); + + qreal radiusRatio = style.cornerRadiusRatio; + qreal absolutePercentage = maxRad * radiusRatio; + + if (minRad * radiusRatio < absolutePercentage) { + style.cachedCornerRadiusX = minRad * radiusRatio; + style.cachedCornerRadiusY = style.cachedCornerRadiusX; + } else { + style.cachedCornerRadiusX = absolutePercentage; + style.cachedCornerRadiusY = style.cachedCornerRadiusX; + } + style.cachedSize = newSize; +} diff --git a/core_lib/src/util/drawsliderstyle.h b/core_lib/src/util/drawsliderstyle.h new file mode 100644 index 0000000000..b2a1ff36b3 --- /dev/null +++ b/core_lib/src/util/drawsliderstyle.h @@ -0,0 +1,73 @@ +/* + +Pencil2D - Traditional Animation Software +Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon +Copyright (C) 2012-2020 Matthew Chiawen Chang + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +*/ +#ifndef DRAWSLIDERSTYLE_H +#define DRAWSLIDERSTYLE_H + +#include +#include + +struct SliderPainterStyle { + + SliderPainterStyle(QPalette::ColorRole fillRole, + QPalette::ColorRole strokeRole, + bool hasCustomFill, + QBrush customFill, + float borderWidth, + float cornerRadiusRatio) + { + this->fillRole = fillRole; + this->strokeRole = strokeRole; + this->hasCustomFill = hasCustomFill; + this->customFill = customFill; + this->borderWidth = borderWidth; + this->cornerRadiusRatio = cornerRadiusRatio; + } + + SliderPainterStyle(QPalette::ColorRole strokeRole, + bool hasCustomFill, + QBrush customFill) + { + this->strokeRole = strokeRole; + this->hasCustomFill = hasCustomFill; + this->customFill = customFill; + } + + + // The filled part of the slider + QPalette::ColorRole fillRole = QPalette::Window; + + // The border of the slider, by default there is none + QPalette::ColorRole strokeRole = QPalette::NoRole; + + bool hasCustomFill = false; + QBrush customFill = QBrush(); + + float borderWidth = 1.0f; + float cornerRadiusRatio = 0.2; + + QSizeF cachedSize = {}; + + float cachedCornerRadiusX = 0; + float cachedCornerRadiusY = 0; +}; + +namespace SliderPainter { + void drawSliderStyle(QPainter& painter, const QRectF& rect, SliderPainterStyle& style, const QPalette& palette); + void updateSliderStyleCache(SliderPainterStyle& style, const QSizeF& newSize); +} + +#endif // DRAWSLIDERSTYLE_H diff --git a/core_lib/src/util/slidergeometry.cpp b/core_lib/src/util/slidergeometry.cpp new file mode 100644 index 0000000000..39c786510b --- /dev/null +++ b/core_lib/src/util/slidergeometry.cpp @@ -0,0 +1,43 @@ +/* + +Pencil2D - Traditional Animation Software +Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon +Copyright (C) 2012-2020 Matthew Chiawen Chang + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +*/ +#include "slidergeometry.h" + +QRectF SliderGeometry::contentsRect(const QRectF& rect, qreal borderWidth) +{ + qreal inset = SliderGeometry::penStrokeInset(borderWidth); + + return QRectF(rect.left() + inset, + rect.top() + inset, + rect.width() - borderWidth, + rect.height() - borderWidth + ); +} + +qreal SliderGeometry::innerCornerRadius(qreal outerRadius, qreal borderWidth) +{ + return outerRadius - borderWidth; +} + +qreal SliderGeometry::penStrokeInset(qreal borderWidth) +{ + return borderWidth * 0.5; +} + +qreal SliderGeometry::pickerMaxDistance(qreal sliderWidth, qreal pickerWidth) +{ + return sliderWidth - pickerWidth; +} diff --git a/core_lib/src/util/slidergeometry.h b/core_lib/src/util/slidergeometry.h new file mode 100644 index 0000000000..62ed10b0bb --- /dev/null +++ b/core_lib/src/util/slidergeometry.h @@ -0,0 +1,29 @@ +/* + +Pencil2D - Traditional Animation Software +Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon +Copyright (C) 2012-2020 Matthew Chiawen Chang + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +*/ +#ifndef SLIDERGEOMETRY_H +#define SLIDERGEOMETRY_H + +#include + +namespace SliderGeometry { + QRectF contentsRect(const QRectF& rect, qreal borderWidth); + qreal penStrokeInset(qreal borderWidth); + qreal innerCornerRadius(qreal outerRadius, qreal borderWidth); + qreal pickerMaxDistance(qreal sliderWidth, qreal pickerWidth); +} + +#endif // SLIDERGEOMETRY_H