File indexing completed on 2024-12-22 04:13:17
0001 /* This file is part of the KDE libraries 0002 SPDX-FileCopyrightText: 1999 Daniel M. Duley <mosfet@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only 0005 */ 0006 0007 #include "KoDualColorButton.h" 0008 #include "KoColor.h" 0009 #include "KoColorDisplayRendererInterface.h" 0010 #include <kcolormimedata.h> 0011 #include <kconfiggroup.h> 0012 #include <ksharedconfig.h> 0013 0014 #include "dcolorarrow.xbm" 0015 #include "dcolorreset.xpm" 0016 0017 #include <QColorDialog> 0018 #include "KisDlgInternalColorSelector.h" 0019 0020 #include "kis_signals_blocker.h" 0021 0022 #include <QBrush> 0023 #include <QDrag> 0024 #include <QDragEnterEvent> 0025 #include <QPainter> 0026 #include <QPointer> 0027 #include <qdrawutil.h> 0028 #include <QApplication> 0029 0030 class Q_DECL_HIDDEN KoDualColorButton::Private 0031 { 0032 public: 0033 Private(const KoColor &fgColor, const KoColor &bgColor, 0034 QWidget *_dialogParent, 0035 const KoColorDisplayRendererInterface *_displayRenderer) 0036 : dialogParent(_dialogParent) 0037 , dragFlag( false ) 0038 , miniCtlFlag( false ) 0039 , foregroundColor(fgColor) 0040 , backgroundColor(bgColor) 0041 0042 , displayRenderer(_displayRenderer) 0043 { 0044 updateArrows(); 0045 resetPixmap = QPixmap( (const char **)dcolorreset_xpm ); 0046 0047 popDialog = true; 0048 } 0049 0050 void updateArrows() { 0051 arrowBitmap = QPixmap(12,12); 0052 arrowBitmap.fill(Qt::transparent); 0053 0054 QPainter p(&arrowBitmap); 0055 p.setPen(dialogParent->palette().windowText().color()); 0056 0057 // arrow pointing left 0058 p.drawLine(0, 3, 7, 3); 0059 p.drawLine(1, 2, 1, 4); 0060 p.drawLine(2, 1, 2, 5); 0061 p.drawLine(3, 0, 3, 6); 0062 0063 // arrow pointing down 0064 p.drawLine(8, 4, 8, 11); 0065 p.drawLine(5, 8, 11, 8); 0066 p.drawLine(6, 9, 10, 9); 0067 p.drawLine(7, 10, 9, 10); 0068 } 0069 0070 QWidget* dialogParent; 0071 0072 QPixmap arrowBitmap; 0073 QPixmap resetPixmap; 0074 bool dragFlag, miniCtlFlag; 0075 KoColor foregroundColor; 0076 KoColor backgroundColor; 0077 KisDlgInternalColorSelector *colorSelectorDialog; 0078 QPoint dragPosition; 0079 Selection tmpSelection; 0080 bool popDialog; 0081 QPointer<const KoColorDisplayRendererInterface> displayRenderer; 0082 0083 void init(KoDualColorButton *q); 0084 }; 0085 0086 void KoDualColorButton::Private::init(KoDualColorButton *q) 0087 { 0088 if ( q->sizeHint().isValid() ) 0089 q->setMinimumSize( q->sizeHint() ); 0090 0091 q->setAcceptDrops( true ); 0092 QString caption = i18n("Select a Color"); 0093 KisDlgInternalColorSelector::Config config = KisDlgInternalColorSelector::Config(); 0094 config.modal = false; 0095 colorSelectorDialog = new KisDlgInternalColorSelector(q, foregroundColor, config, caption, displayRenderer); 0096 connect(colorSelectorDialog, SIGNAL(signalForegroundColorChosen(KoColor)), q, SLOT(slotSetForeGroundColorFromDialog(KoColor))); 0097 connect(q, SIGNAL(foregroundColorChanged(KoColor)), colorSelectorDialog, SLOT(slotColorUpdated(KoColor))); 0098 } 0099 0100 KoDualColorButton::KoDualColorButton(const KoColor &foregroundColor, const KoColor &backgroundColor, QWidget *parent, QWidget* dialogParent ) 0101 : QWidget( parent ), 0102 d( new Private(foregroundColor, backgroundColor, 0103 dialogParent, 0104 KoDumbColorDisplayRenderer::instance()) ) 0105 { 0106 d->init(this); 0107 } 0108 0109 KoDualColorButton::KoDualColorButton(const KoColor &foregroundColor, const KoColor &backgroundColor, 0110 const KoColorDisplayRendererInterface *displayRenderer, 0111 QWidget *parent, QWidget* dialogParent) 0112 : QWidget( parent ), 0113 d( new Private(foregroundColor, backgroundColor, 0114 dialogParent, 0115 displayRenderer) ) 0116 { 0117 d->init(this); 0118 } 0119 0120 KoDualColorButton::~KoDualColorButton() 0121 { 0122 delete d; 0123 } 0124 0125 KoColor KoDualColorButton::foregroundColor() const 0126 { 0127 return d->foregroundColor; 0128 } 0129 0130 KoColor KoDualColorButton::backgroundColor() const 0131 { 0132 return d->backgroundColor; 0133 } 0134 0135 bool KoDualColorButton::popDialog() const 0136 { 0137 return d->popDialog; 0138 } 0139 0140 QSize KoDualColorButton::sizeHint() const 0141 { 0142 return QSize(34, 34); 0143 } 0144 0145 void KoDualColorButton::setForegroundColor(const KoColor &color) 0146 { 0147 d->foregroundColor = color; 0148 { 0149 /** 0150 * The internal color selector might emit the color of a different profile, so 0151 * we should break this cycling dependency somehow. 0152 */ 0153 KisSignalsBlocker b(d->colorSelectorDialog); 0154 d->colorSelectorDialog->slotColorUpdated(color); 0155 } 0156 update(); 0157 } 0158 0159 void KoDualColorButton::setBackgroundColor( const KoColor &color ) 0160 { 0161 d->backgroundColor = color; 0162 update(); 0163 } 0164 0165 void KoDualColorButton::setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer) 0166 { 0167 if (d->displayRenderer && d->displayRenderer != KoDumbColorDisplayRenderer::instance()) { 0168 d->displayRenderer->disconnect(this); 0169 } 0170 if (displayRenderer) { 0171 d->displayRenderer = displayRenderer; 0172 d->colorSelectorDialog->setDisplayRenderer(displayRenderer); 0173 connect(d->displayRenderer, SIGNAL(destroyed()), this, SLOT(setDisplayRenderer()), Qt::UniqueConnection); 0174 connect(d->displayRenderer, SIGNAL(displayConfigurationChanged()), this, SLOT(update())); 0175 } else { 0176 d->displayRenderer = KoDumbColorDisplayRenderer::instance(); 0177 } 0178 } 0179 0180 void KoDualColorButton::setColorSpace(const KoColorSpace *cs) 0181 { 0182 d->colorSelectorDialog->lockUsedColorSpace(cs); 0183 } 0184 0185 QColor KoDualColorButton::getColorFromDisplayRenderer(KoColor c) 0186 { 0187 QColor col; 0188 if (d->displayRenderer) { 0189 c.convertTo(d->displayRenderer->getPaintingColorSpace()); 0190 col = d->displayRenderer->toQColor(c); 0191 } else { 0192 col = c.toQColor(); 0193 } 0194 return col; 0195 } 0196 0197 void KoDualColorButton::setPopDialog( bool popDialog ) 0198 { 0199 d->popDialog = popDialog; 0200 } 0201 0202 void KoDualColorButton::metrics( QRect &foregroundRect, QRect &backgroundRect ) 0203 { 0204 foregroundRect = QRect( 0, 0, width() - 14, height() - 14 ); 0205 backgroundRect = QRect( 14, 14, width() - 14, height() - 14 ); 0206 } 0207 0208 void KoDualColorButton::paintEvent(QPaintEvent *) 0209 { 0210 QRect foregroundRect; 0211 QRect backgroundRect; 0212 0213 QPainter painter( this ); 0214 0215 metrics( foregroundRect, backgroundRect ); 0216 0217 QBrush defBrush = palette().brush( QPalette::Button ); 0218 QBrush foregroundBrush( getColorFromDisplayRenderer(d->foregroundColor), Qt::SolidPattern ); 0219 QBrush backgroundBrush( getColorFromDisplayRenderer(d->backgroundColor), Qt::SolidPattern ); 0220 0221 qDrawShadeRect( &painter, backgroundRect, palette(), false, 1, 0, 0222 isEnabled() ? &backgroundBrush : &defBrush ); 0223 0224 qDrawShadeRect( &painter, foregroundRect, palette(), false, 1, 0, 0225 isEnabled() ? &foregroundBrush : &defBrush ); 0226 0227 painter.setPen( palette().color( QPalette::Shadow ) ); 0228 0229 painter.drawPixmap( foregroundRect.right() + 2, 1, d->arrowBitmap ); 0230 painter.drawPixmap( 1, foregroundRect.bottom() + 2, d->resetPixmap ); 0231 } 0232 0233 void KoDualColorButton::dragEnterEvent( QDragEnterEvent *event ) 0234 { 0235 event->setAccepted( isEnabled() && KColorMimeData::canDecode( event->mimeData() ) ); 0236 } 0237 0238 void KoDualColorButton::dropEvent( QDropEvent *event ) 0239 { 0240 Q_UNUSED(event); 0241 /* QColor color = KColorMimeData::fromMimeData( event->mimeData() ); 0242 0243 if ( color.isValid() ) { 0244 if ( d->selection == Foreground ) { 0245 d->foregroundColor = color; 0246 emit foregroundColorChanged( color ); 0247 } else { 0248 d->backgroundColor = color; 0249 emit backgroundColorChanged( color ); 0250 } 0251 0252 update(); 0253 } 0254 */ 0255 } 0256 0257 void KoDualColorButton::slotSetForeGroundColorFromDialog(const KoColor color) 0258 { 0259 d->foregroundColor = color; 0260 update(); 0261 emit foregroundColorChanged(d->foregroundColor); 0262 } 0263 0264 0265 void KoDualColorButton::openForegroundDialog(){ 0266 d->colorSelectorDialog->setPreviousColor(d->foregroundColor); 0267 d->colorSelectorDialog->show(); 0268 update(); 0269 } 0270 0271 void KoDualColorButton::openBackgroundDialog(){ 0272 KoColor c = d->backgroundColor; 0273 c = KisDlgInternalColorSelector::getModalColorDialog(c, this, d->colorSelectorDialog->windowTitle()); 0274 d->backgroundColor = c; 0275 emit backgroundColorChanged(d->backgroundColor); 0276 } 0277 0278 void KoDualColorButton::mousePressEvent( QMouseEvent *event ) 0279 { 0280 QRect foregroundRect; 0281 QRect backgroundRect; 0282 0283 metrics( foregroundRect, backgroundRect ); 0284 0285 d->dragPosition = event->pos(); 0286 0287 d->dragFlag = false; 0288 0289 if ( foregroundRect.contains( d->dragPosition ) ) { 0290 d->tmpSelection = Foreground; 0291 d->miniCtlFlag = false; 0292 } 0293 else if( backgroundRect.contains( d->dragPosition ) ) { 0294 d->tmpSelection = Background; 0295 d->miniCtlFlag = false; 0296 } 0297 else if ( event->pos().x() > foregroundRect.width() ) { 0298 // We handle the swap and reset controls as soon as the mouse is 0299 // is pressed and ignore further events on this click (mosfet). 0300 0301 KoColor tmp = d->foregroundColor; 0302 d->foregroundColor = d->backgroundColor; 0303 d->backgroundColor = tmp; 0304 0305 emit backgroundColorChanged( d->backgroundColor ); 0306 emit foregroundColorChanged( d->foregroundColor ); 0307 0308 d->miniCtlFlag = true; 0309 } 0310 else if ( event->pos().x() < backgroundRect.x() ) { 0311 d->foregroundColor = d->displayRenderer->approximateFromRenderedQColor(Qt::black); 0312 d->backgroundColor = d->displayRenderer->approximateFromRenderedQColor(Qt::white); 0313 0314 emit backgroundColorChanged( d->backgroundColor ); 0315 emit foregroundColorChanged( d->foregroundColor ); 0316 0317 d->miniCtlFlag = true; 0318 } 0319 update(); 0320 } 0321 0322 0323 void KoDualColorButton::mouseMoveEvent( QMouseEvent *event ) 0324 { 0325 if ( !d->miniCtlFlag ) { 0326 int delay = QApplication::startDragDistance(); 0327 0328 if ( event->x() >= d->dragPosition.x() + delay || event->x() <= d->dragPosition.x() - delay || 0329 event->y() >= d->dragPosition.y() + delay || event->y() <= d->dragPosition.y() - delay ) { 0330 KColorMimeData::createDrag( d->tmpSelection == Foreground ? 0331 getColorFromDisplayRenderer(d->foregroundColor) : 0332 getColorFromDisplayRenderer(d->backgroundColor), 0333 this )->exec(); 0334 d->dragFlag = true; 0335 } 0336 } 0337 } 0338 0339 void KoDualColorButton::mouseReleaseEvent( QMouseEvent *event ) 0340 { 0341 d->dragFlag = false; 0342 0343 if ( d->miniCtlFlag ) 0344 return; 0345 0346 d->miniCtlFlag = false; 0347 0348 QRect foregroundRect; 0349 QRect backgroundRect; 0350 metrics( foregroundRect, backgroundRect ); 0351 0352 KConfigGroup cfg = KSharedConfig::openConfig()->group("colorselector"); 0353 bool usePlatformDialog = cfg.readEntry("UsePlatformColorDialog", false); 0354 0355 if (foregroundRect.contains( event->pos())) { 0356 if (d->tmpSelection == Foreground) { 0357 if (d->popDialog) { 0358 if (usePlatformDialog) { 0359 QColor c = d->foregroundColor.toQColor(); 0360 c = QColorDialog::getColor(c, this); 0361 if (c.isValid()) { 0362 d->foregroundColor = d->displayRenderer->approximateFromRenderedQColor(c); 0363 emit foregroundColorChanged(d->foregroundColor); 0364 } 0365 } 0366 else { 0367 d->colorSelectorDialog->setPreviousColor(d->foregroundColor); 0368 d->colorSelectorDialog->show(); 0369 } 0370 } 0371 } 0372 else { 0373 d->foregroundColor = d->backgroundColor; 0374 emit foregroundColorChanged( d->foregroundColor ); 0375 } 0376 } 0377 else if (backgroundRect.contains( event->pos())) { 0378 if(d->tmpSelection == Background ) { 0379 if( d->popDialog) { 0380 if (usePlatformDialog) { 0381 QColor c = d->backgroundColor.toQColor(); 0382 c = QColorDialog::getColor(c, this); 0383 if (c.isValid()) { 0384 d->backgroundColor = d->displayRenderer->approximateFromRenderedQColor(c); 0385 emit backgroundColorChanged(d->backgroundColor); 0386 } 0387 } 0388 else { 0389 KoColor c = d->backgroundColor; 0390 c = KisDlgInternalColorSelector::getModalColorDialog(c, this, d->colorSelectorDialog->windowTitle()); 0391 d->backgroundColor = c; 0392 emit backgroundColorChanged(d->backgroundColor); 0393 } 0394 } 0395 } else { 0396 d->backgroundColor = d->foregroundColor; 0397 emit backgroundColorChanged( d->backgroundColor ); 0398 } 0399 } 0400 0401 update(); 0402 } 0403 0404 void KoDualColorButton::changeEvent(QEvent *event) 0405 { 0406 QWidget::changeEvent(event); 0407 0408 switch (event->type()) { 0409 case QEvent::StyleChange: 0410 case QEvent::PaletteChange: 0411 d->updateArrows(); 0412 default: 0413 break; 0414 } 0415 } 0416 0417 bool KoDualColorButton::event(QEvent *event) 0418 { 0419 if (event->type() == QEvent::ToolTip) { 0420 QRect foregroundRect; 0421 QRect backgroundRect; 0422 metrics( foregroundRect, backgroundRect ); 0423 0424 if (this->mapFromGlobal(QCursor::pos()).x() < backgroundRect.x() ) { 0425 if (this->mapFromGlobal(QCursor::pos()).y() < backgroundRect.y()){ 0426 this->setToolTip(i18n("Foreground color selector")); 0427 } 0428 else{ 0429 this->setToolTip(i18n("Set foreground and background colors to black and white")); 0430 } 0431 } 0432 else { 0433 if (this->mapFromGlobal(QCursor::pos()).y() < backgroundRect.y() ) { 0434 this->setToolTip(i18n("Swap foreground and background colors")); 0435 } 0436 else{ 0437 this->setToolTip(i18n("Background color selector")); 0438 } 0439 } 0440 } 0441 return QWidget::event(event); 0442 0443 }