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 }