File indexing completed on 2024-05-12 16:02:00
0001 /* This file is part of the KDE libraries 0002 SPDX-FileCopyrightText: 1997 Martin Jones (mjones@kde.org) 0003 SPDX-FileCopyrightText: 1999 Cristian Tibirna (ctibirna@kde.org) 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kis_color_button.h" 0009 0010 #include <QPointer> 0011 #include <QPainter> 0012 #include <qdrawutil.h> 0013 #include <QApplication> 0014 #include <QColorDialog> 0015 #include <QClipboard> 0016 #include <QMimeData> 0017 #include <QDrag> 0018 #include <QStyle> 0019 #include <QMouseEvent> 0020 #include <QStyleOptionButton> 0021 0022 #include <KoColor.h> 0023 #include <KisDlgInternalColorSelector.h> 0024 #include <kconfiggroup.h> 0025 #include <ksharedconfig.h> 0026 0027 class KisColorButton::KisColorButtonPrivate 0028 { 0029 public: 0030 KisColorButtonPrivate(KisColorButton *q); 0031 ~KisColorButtonPrivate() { 0032 if(m_dialog) { 0033 m_dialog->close(); 0034 } 0035 } 0036 0037 void _k_chooseColor(); 0038 0039 KisColorButton *q; 0040 KoColor m_defaultColor; 0041 bool m_bdefaultColor : 1; 0042 bool m_alphaChannel : 1; 0043 bool m_palette : 1; 0044 0045 KoColor col; 0046 QPoint mPos; 0047 QPointer<QDialog> m_dialog = nullptr; 0048 0049 void initStyleOption(QStyleOptionButton *opt) const; 0050 }; 0051 0052 ///////////////////////////////////////////////////////////////////// 0053 // Functions duplicated from KColorMimeData 0054 // Should be kept in sync 0055 void _k_populateMimeData(QMimeData *mimeData, const KoColor &color) 0056 { 0057 mimeData->setColorData(color.toQColor()); 0058 mimeData->setText(color.toQColor().name()); 0059 } 0060 0061 bool _k_canDecode(const QMimeData *mimeData) 0062 { 0063 if (mimeData->hasColor()) { 0064 return true; 0065 } 0066 if (mimeData->hasText()) { 0067 const QString colorName = mimeData->text(); 0068 if ((colorName.length() >= 4) && (colorName[0] == QLatin1Char('#'))) { 0069 return true; 0070 } 0071 } 0072 return false; 0073 } 0074 0075 QColor _k_fromMimeData(const QMimeData *mimeData) 0076 { 0077 if (mimeData->hasColor()) { 0078 return mimeData->colorData().value<QColor>(); 0079 } 0080 if (_k_canDecode(mimeData)) { 0081 return QColor(mimeData->text()); 0082 } 0083 return QColor(); 0084 } 0085 0086 QDrag *_k_createDrag(const KoColor &color, QObject *dragsource) 0087 { 0088 QDrag *drag = new QDrag(dragsource); 0089 QMimeData *mime = new QMimeData; 0090 _k_populateMimeData(mime, color); 0091 drag->setMimeData(mime); 0092 QPixmap colorpix(25, 20); 0093 colorpix.fill(color.toQColor()); 0094 QPainter p(&colorpix); 0095 p.setPen(Qt::black); 0096 p.drawRect(0, 0, 24, 19); 0097 p.end(); 0098 drag->setPixmap(colorpix); 0099 drag->setHotSpot(QPoint(-5, -7)); 0100 return drag; 0101 } 0102 ///////////////////////////////////////////////////////////////////// 0103 0104 KisColorButton::KisColorButtonPrivate::KisColorButtonPrivate(KisColorButton *q) 0105 : q(q) 0106 { 0107 m_bdefaultColor = false; 0108 m_alphaChannel = false; 0109 m_palette = true; 0110 q->setAcceptDrops(true); 0111 0112 connect(q, SIGNAL(clicked()), q, SLOT(_k_chooseColor())); 0113 } 0114 0115 KisColorButton::KisColorButton(QWidget *parent) 0116 : QPushButton(parent) 0117 , d(new KisColorButtonPrivate(this)) 0118 { 0119 } 0120 0121 KisColorButton::KisColorButton(const KoColor &c, QWidget *parent) 0122 : QPushButton(parent) 0123 , d(new KisColorButtonPrivate(this)) 0124 { 0125 d->col = c; 0126 } 0127 0128 KisColorButton::KisColorButton(const KoColor &c, const KoColor &defaultColor, QWidget *parent) 0129 : QPushButton(parent) 0130 , d(new KisColorButtonPrivate(this)) 0131 { 0132 d->col = c; 0133 setDefaultColor(defaultColor); 0134 } 0135 0136 KisColorButton::~KisColorButton() 0137 { 0138 delete d; 0139 } 0140 0141 KoColor KisColorButton::color() const 0142 { 0143 return d->col; 0144 } 0145 0146 void KisColorButton::setColor(const KoColor &c) 0147 { 0148 d->col = c; 0149 update(); 0150 emit changed(d->col); 0151 } 0152 0153 void KisColorButton::setAlphaChannelEnabled(bool alpha) 0154 { 0155 d->m_alphaChannel = alpha; 0156 } 0157 0158 bool KisColorButton::isAlphaChannelEnabled() const 0159 { 0160 return d->m_alphaChannel; 0161 } 0162 0163 void KisColorButton::setPaletteViewEnabled(bool enable) 0164 { 0165 d->m_palette = enable; 0166 } 0167 0168 bool KisColorButton::paletteViewEnabled() const 0169 { 0170 return d->m_palette; 0171 } 0172 0173 KoColor KisColorButton::defaultColor() const 0174 { 0175 return d->m_defaultColor; 0176 } 0177 0178 void KisColorButton::setDefaultColor(const KoColor &c) 0179 { 0180 d->m_bdefaultColor = true; 0181 d->m_defaultColor = c; 0182 } 0183 0184 void KisColorButton::KisColorButtonPrivate::initStyleOption(QStyleOptionButton *opt) const 0185 { 0186 opt->initFrom(q); 0187 opt->state |= q->isDown() ? QStyle::State_Sunken : QStyle::State_Raised; 0188 opt->features = QStyleOptionButton::None; 0189 if (q->isDefault()) { 0190 opt->features |= QStyleOptionButton::DefaultButton; 0191 } 0192 opt->text.clear(); 0193 opt->icon = QIcon(); 0194 } 0195 0196 void KisColorButton::paintEvent(QPaintEvent *) 0197 { 0198 QPainter painter(this); 0199 QStyle *style = QWidget::style(); 0200 0201 //First, we need to draw the bevel. 0202 QStyleOptionButton butOpt; 0203 d->initStyleOption(&butOpt); 0204 style->drawControl(QStyle::CE_PushButtonBevel, &butOpt, &painter, this); 0205 0206 //OK, now we can muck around with drawing out pretty little color box 0207 //First, sort out where it goes 0208 QRect labelRect = style->subElementRect(QStyle::SE_PushButtonContents, 0209 &butOpt, this); 0210 int shift = style->pixelMetric(QStyle::PM_ButtonMargin, &butOpt, this) / 2; 0211 labelRect.adjust(shift, shift, -shift, -shift); 0212 int x, y, w, h; 0213 labelRect.getRect(&x, &y, &w, &h); 0214 0215 if (isChecked() || isDown()) { 0216 x += style->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &butOpt, this); 0217 y += style->pixelMetric(QStyle::PM_ButtonShiftVertical, &butOpt, this); 0218 } 0219 0220 QColor fillCol = isEnabled() ? d->col.toQColor() : palette().color(backgroundRole()); 0221 qDrawShadePanel(&painter, x, y, w, h, palette(), true, 1, NULL); 0222 if (fillCol.isValid()) { 0223 const QRect rect(x + 1, y + 1, w - 2, h - 2); 0224 if (fillCol.alpha() < 255) { 0225 QPixmap chessboardPattern(16, 16); 0226 QPainter patternPainter(&chessboardPattern); 0227 patternPainter.fillRect(0, 0, 8, 8, Qt::black); 0228 patternPainter.fillRect(8, 8, 8, 8, Qt::black); 0229 patternPainter.fillRect(0, 8, 8, 8, Qt::white); 0230 patternPainter.fillRect(8, 0, 8, 8, Qt::white); 0231 patternPainter.end(); 0232 painter.fillRect(rect, QBrush(chessboardPattern)); 0233 } 0234 painter.fillRect(rect, fillCol); 0235 } 0236 0237 if (hasFocus()) { 0238 QRect focusRect = style->subElementRect(QStyle::SE_PushButtonFocusRect, &butOpt, this); 0239 QStyleOptionFocusRect focusOpt; 0240 focusOpt.init(this); 0241 focusOpt.rect = focusRect; 0242 focusOpt.backgroundColor = palette().window().color(); 0243 style->drawPrimitive(QStyle::PE_FrameFocusRect, &focusOpt, &painter, this); 0244 } 0245 } 0246 0247 QSize KisColorButton::sizeHint() const 0248 { 0249 QStyleOptionButton opt; 0250 d->initStyleOption(&opt); 0251 return style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(40, 15), this); 0252 } 0253 0254 QSize KisColorButton::minimumSizeHint() const 0255 { 0256 QStyleOptionButton opt; 0257 d->initStyleOption(&opt); 0258 return style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(3, 3), this); 0259 } 0260 0261 void KisColorButton::dragEnterEvent(QDragEnterEvent *event) 0262 { 0263 event->setAccepted(_k_canDecode(event->mimeData()) && isEnabled()); 0264 } 0265 0266 void KisColorButton::dropEvent(QDropEvent *event) 0267 { 0268 QColor c = _k_fromMimeData(event->mimeData()); 0269 if (c.isValid()) { 0270 KoColor col; 0271 col.fromQColor(c); 0272 setColor(col); 0273 } 0274 } 0275 0276 void KisColorButton::keyPressEvent(QKeyEvent *e) 0277 { 0278 int key = e->key() | e->modifiers(); 0279 0280 if (QKeySequence::keyBindings(QKeySequence::Copy).contains(key)) { 0281 QMimeData *mime = new QMimeData; 0282 _k_populateMimeData(mime, color()); 0283 QApplication::clipboard()->setMimeData(mime, QClipboard::Clipboard); 0284 } else if (QKeySequence::keyBindings(QKeySequence::Paste).contains(key)) { 0285 QColor color = _k_fromMimeData(QApplication::clipboard()->mimeData(QClipboard::Clipboard)); 0286 KoColor col; 0287 col.fromQColor(color); 0288 setColor(col); 0289 } else { 0290 QPushButton::keyPressEvent(e); 0291 } 0292 } 0293 0294 void KisColorButton::mousePressEvent(QMouseEvent *e) 0295 { 0296 d->mPos = e->pos(); 0297 QPushButton::mousePressEvent(e); 0298 } 0299 0300 void KisColorButton::mouseMoveEvent(QMouseEvent *e) 0301 { 0302 if ((e->buttons() & Qt::LeftButton) && 0303 (e->pos() - d->mPos).manhattanLength() > QApplication::startDragDistance()) { 0304 _k_createDrag(color(), this)->exec(); 0305 setDown(false); 0306 } 0307 } 0308 0309 void KisColorButton::KisColorButtonPrivate::_k_chooseColor() 0310 { 0311 KConfigGroup cfg = KSharedConfig::openConfig()->group("colorselector"); 0312 bool usePlatformDialog = cfg.readEntry("UsePlatformColorDialog", false); 0313 0314 if (!usePlatformDialog) { 0315 KisDlgInternalColorSelector::Config cfg; 0316 cfg.paletteBox = q->paletteViewEnabled(); 0317 KisDlgInternalColorSelector *dialog = new KisDlgInternalColorSelector(q, q->color(), cfg, i18n("Choose a color")); 0318 dialog->setPreviousColor(q->color()); 0319 auto setColorFn = [this, dialog]() { q->setColor(dialog->getCurrentColor()); }; 0320 connect(dialog, &KisDlgInternalColorSelector::signalForegroundColorChosen, setColorFn); 0321 connect(dialog, &QDialog::accepted, setColorFn); 0322 m_dialog = dialog; 0323 } else{ 0324 QColorDialog *dialog = new QColorDialog(q); 0325 dialog->setOption(QColorDialog::ShowAlphaChannel, m_alphaChannel); 0326 dialog->setCurrentColor(q->color().toQColor()); 0327 auto setColorFn = [this, dialog]() 0328 { 0329 KoColor c; 0330 c.fromQColor(dialog->currentColor()); 0331 q->setColor(c); 0332 }; 0333 connect(dialog, &QColorDialog::currentColorChanged, setColorFn); 0334 connect(dialog, &QDialog::accepted, setColorFn); 0335 m_dialog = dialog; 0336 } 0337 // common functionality 0338 KoColor colorBeforeColorDialogChanges = col; 0339 connect(m_dialog, &QDialog::rejected, [colorBeforeColorDialogChanges, this](){ q->setColor(colorBeforeColorDialogChanges); }); 0340 m_dialog->setAttribute(Qt::WA_DeleteOnClose); 0341 m_dialog->show(); 0342 m_dialog->raise(); 0343 m_dialog->activateWindow(); 0344 } 0345 0346 #include "moc_kis_color_button.cpp"