File indexing completed on 2024-05-05 04:21:24

0001 
0002 /*
0003    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
0004    All rights reserved.
0005 
0006    Redistribution and use in source and binary forms, with or without
0007    modification, are permitted provided that the following conditions
0008    are met:
0009 
0010    1. Redistributions of source code must retain the above copyright
0011       notice, this list of conditions and the following disclaimer.
0012    2. Redistributions in binary form must reproduce the above copyright
0013       notice, this list of conditions and the following disclaimer in the
0014       documentation and/or other materials provided with the distribution.
0015 
0016    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0017    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0018    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0019    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0020    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0021    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0022    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0023    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0024    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0025    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0026 */
0027 
0028 
0029 #define DEBUG_KP_DUAL_COLOR_BUTTON 0
0030 
0031 
0032 #include "kpDualColorButton.h"
0033 
0034 #include "views/kpView.h"
0035 
0036 #include <KColorMimeData>
0037 #include "kpLogCategories.h"
0038 
0039 #include <QApplication>
0040 #include <QBitmap>
0041 #include <QColorDialog>
0042 #include <QDrag>
0043 #include <QMouseEvent>
0044 #include <QPainter>
0045 #include <qdrawutil.h>
0046 
0047 //---------------------------------------------------------------------
0048 
0049 kpDualColorButton::kpDualColorButton (QWidget *parent)
0050     : QFrame (parent),
0051       m_dragStartPoint (KP_INVALID_POINT)
0052 {
0053     setSizePolicy (QSizePolicy::Fixed/*horizontal*/,
0054                    QSizePolicy::Fixed/*vertical*/);
0055     setFrameStyle (QFrame::Panel | QFrame::Sunken);
0056 
0057     m_color [0] = kpColor (0, 0, 0);  // black
0058     m_color [1] = kpColor (255, 255, 255);  // white
0059 
0060     setAcceptDrops (true);
0061 }
0062 
0063 //---------------------------------------------------------------------
0064 
0065 kpColor kpDualColorButton::color (int which) const
0066 {
0067     Q_ASSERT (which == 0 || which == 1);
0068 
0069     return m_color [which];
0070 }
0071 
0072 //---------------------------------------------------------------------
0073 
0074 kpColor kpDualColorButton::foregroundColor () const
0075 {
0076     return color (0);
0077 }
0078 
0079 //---------------------------------------------------------------------
0080 
0081 kpColor kpDualColorButton::backgroundColor () const
0082 {
0083     return color (1);
0084 }
0085 
0086 //---------------------------------------------------------------------
0087 
0088 void kpDualColorButton::setColor (int which, const kpColor &color)
0089 {
0090     Q_ASSERT (which == 0 || which == 1);
0091 
0092     if (m_color [which] == color) {
0093         return;
0094     }
0095 
0096     m_oldColor [which] = m_color [which];
0097     m_color [which] = color;
0098     update ();
0099 
0100     if (which == 0) {
0101         Q_EMIT foregroundColorChanged (color);
0102     }
0103     else {
0104         Q_EMIT backgroundColorChanged (color);
0105     }
0106 }
0107 
0108 //---------------------------------------------------------------------
0109 
0110 void kpDualColorButton::setForegroundColor (const kpColor &color)
0111 {
0112     setColor (0, color);
0113 }
0114 
0115 //---------------------------------------------------------------------
0116 
0117 void kpDualColorButton::setBackgroundColor (const kpColor &color)
0118 {
0119     setColor (1, color);
0120 }
0121 
0122 //---------------------------------------------------------------------
0123 
0124 
0125 // public
0126 kpColor kpDualColorButton::oldForegroundColor () const
0127 {
0128     return m_oldColor [0];
0129 }
0130 
0131 //---------------------------------------------------------------------
0132 
0133 // public
0134 kpColor kpDualColorButton::oldBackgroundColor () const
0135 {
0136     return m_oldColor [1];
0137 }
0138 
0139 //---------------------------------------------------------------------
0140 
0141 
0142 // public virtual [base QWidget]
0143 QSize kpDualColorButton::sizeHint () const
0144 {
0145     return  {52, 52};
0146 }
0147 
0148 //---------------------------------------------------------------------
0149 
0150 
0151 // protected
0152 QRect kpDualColorButton::swapPixmapRect () const
0153 {
0154     QPixmap swapPixmap = QStringLiteral(":/icons/colorbutton_swap_16x16");
0155 
0156     return  {contentsRect ().width () - swapPixmap.width (), 0,
0157                 swapPixmap.width (), swapPixmap.height ()};
0158 }
0159 
0160 //---------------------------------------------------------------------
0161 
0162 // protected
0163 QRect kpDualColorButton::foregroundBackgroundRect () const
0164 {
0165     QRect cr (contentsRect ());
0166     return  {cr.width () / 8, cr.height () / 8,
0167                 cr.width () * 6 / 8, cr.height () * 6 / 8};
0168 }
0169 
0170 //---------------------------------------------------------------------
0171 
0172 // protected
0173 QRect kpDualColorButton::foregroundRect () const
0174 {
0175     QRect fbr (foregroundBackgroundRect ());
0176     return  {fbr.x (), fbr.y (),
0177                 fbr.width () * 3 / 4, fbr.height () * 3 / 4};
0178 }
0179 
0180 //---------------------------------------------------------------------
0181 
0182 // protected
0183 QRect kpDualColorButton::backgroundRect () const
0184 {
0185     QRect fbr (foregroundBackgroundRect ());
0186     return  {fbr.x () + fbr.width () / 4, fbr.y () + fbr.height () / 4,
0187                 fbr.width () * 3 / 4, fbr.height () * 3 / 4};
0188 }
0189 
0190 //---------------------------------------------------------------------
0191 
0192 
0193 // protected virtual
0194 void kpDualColorButton::dragEnterEvent (QDragEnterEvent *e)
0195 {
0196 #if DEBUG_KP_DUAL_COLOR_BUTTON
0197     qCDebug(kpLogWidgets) << "kpDualColorButton::dragEnterEvent() canDecode="
0198               << KColorMimeData::canDecode (e->mimeData ());
0199 #endif
0200     e->accept ();
0201 }
0202 
0203 //---------------------------------------------------------------------
0204 
0205 // protected virtual [base QWidget]
0206 void kpDualColorButton::dragMoveEvent (QDragMoveEvent *e)
0207 {
0208 #if DEBUG_KP_DUAL_COLOR_BUTTON
0209     qCDebug(kpLogWidgets) << "kpDualColorButton::dragMoveEvent() canDecode="
0210               << KColorMimeData::canDecode (e->mimeData ());
0211 #endif
0212     e->setAccepted (
0213         (foregroundRect ().contains (e->pos ()) ||
0214             backgroundRect ().contains (e->pos ())) &&
0215         KColorMimeData::canDecode (e->mimeData ()));
0216 }
0217 
0218 //---------------------------------------------------------------------
0219 
0220 // protected virtual [base QWidget]
0221 void kpDualColorButton::dropEvent (QDropEvent *e)
0222 {
0223     QColor col = KColorMimeData::fromMimeData (e->mimeData ());
0224 #if DEBUG_KP_DUAL_COLOR_BUTTON
0225     qCDebug(kpLogWidgets) << "kpDualColorButton::dropEvent() col="
0226               << (int *) col.rgba()
0227               << " (with alpha=" << (int *) col.rgba () << ")";
0228 #endif
0229 
0230     if (col.isValid ())
0231     {
0232         if (foregroundRect ().contains (e->pos ())) {
0233             setForegroundColor (kpColor (col.rgba()));
0234         }
0235         else if (backgroundRect ().contains (e->pos ())) {
0236             setBackgroundColor (kpColor (col.rgba()));
0237         }
0238     }
0239 }
0240 
0241 //---------------------------------------------------------------------
0242 
0243 
0244 // protected virtual [base QWidget]
0245 void kpDualColorButton::mousePressEvent (QMouseEvent *e)
0246 {
0247 #if DEBUG_KP_DUAL_COLOR_BUTTON
0248     qCDebug(kpLogWidgets) << "kpDualColorButton::mousePressEvent() pos=" << e->pos ();
0249 #endif
0250 
0251     m_dragStartPoint = KP_INVALID_POINT;
0252 
0253     if (e->button () == Qt::LeftButton) {
0254         m_dragStartPoint = e->pos ();
0255     }
0256 }
0257 
0258 //---------------------------------------------------------------------
0259 
0260 void kpDualColorButton::mouseMoveEvent (QMouseEvent *e)
0261 {
0262 #if DEBUG_KP_DUAL_COLOR_BUTTON
0263     qCDebug(kpLogWidgets) << "kpDualColorButton::mouseMoveEvent() pos=" << e->pos ()
0264               << " buttons=" << e->buttons ()
0265               << " dragStartPoint=" << m_dragStartPoint << endl;
0266 #endif
0267 
0268     if (m_dragStartPoint == KP_INVALID_POINT) {
0269         return;
0270     }
0271 
0272     if (!(e->buttons () & Qt::LeftButton))
0273     {
0274         m_dragStartPoint = KP_INVALID_POINT;
0275         return;
0276     }
0277 
0278     const int delay = QApplication::startDragDistance ();
0279     if (e->x () < m_dragStartPoint.x () - delay ||
0280         e->x () > m_dragStartPoint.x () + delay ||
0281         e->y () < m_dragStartPoint.y () - delay ||
0282         e->y () > m_dragStartPoint.y () + delay)
0283     {
0284     #if DEBUG_KP_DUAL_COLOR_BUTTON
0285         qCDebug(kpLogWidgets) << "\tstarting drag as long as it's in a rectangle";
0286     #endif
0287 
0288         kpColor color;
0289 
0290         if (foregroundRect ().contains (m_dragStartPoint)) {
0291             color = foregroundColor ();
0292         }
0293         else if (backgroundRect ().contains (m_dragStartPoint)) {
0294             color = backgroundColor ();
0295         }
0296 
0297     #if DEBUG_KP_DUAL_COLOR_BUTTON
0298         qCDebug(kpLogWidgets) << "\tcolor.isValid=" << color.isValid ()
0299                   << " rgb=" << (color.isValid () ? (int *) color.toQRgb () : 0)
0300                   << endl;
0301     #endif
0302 
0303         if (color.isValid ())
0304         {
0305             if (!color.isTransparent ()) {
0306                 KColorMimeData::createDrag (color.toQColor (), this)->exec ();
0307             }
0308         }
0309 
0310         m_dragStartPoint = KP_INVALID_POINT;
0311     }
0312 }
0313 
0314 //---------------------------------------------------------------------
0315 
0316 // protected virtual [base QWidget]
0317 void kpDualColorButton::mouseReleaseEvent (QMouseEvent *e)
0318 {
0319     m_dragStartPoint = KP_INVALID_POINT;
0320 
0321     if (swapPixmapRect ().contains (e->pos ()) &&
0322         m_color [0] != m_color [1])
0323     {
0324     #if DEBUG_KP_DUAL_COLOR_BUTTON && 1
0325         qCDebug(kpLogWidgets) << "kpDualColorButton::mouseReleaseEvent() swap colors:";
0326     #endif
0327         m_oldColor [0] = m_color [0];
0328         m_oldColor [1] = m_color [1];
0329 
0330         kpColor temp = m_color [0];
0331         m_color [0] = m_color [1];
0332         m_color [1] = temp;
0333 
0334         update ();
0335 
0336         Q_EMIT colorsSwapped (m_color [0], m_color [1]);
0337         Q_EMIT foregroundColorChanged (m_color [0]);
0338         Q_EMIT backgroundColorChanged (m_color [1]);
0339     }
0340 }
0341 
0342 //---------------------------------------------------------------------
0343 
0344 // protected virtual [base QWidget]
0345 void kpDualColorButton::mouseDoubleClickEvent (QMouseEvent *e)
0346 {
0347     int whichColor = -1;
0348 
0349     if (foregroundRect ().contains (e->pos ())) {
0350         whichColor = 0;
0351     }
0352     else if (backgroundRect ().contains (e->pos ())) {
0353         whichColor = 1;
0354     }
0355 
0356     if (whichColor == 0 || whichColor == 1)
0357     {
0358         QColorDialog dialog(this);
0359         dialog.setCurrentColor(color(whichColor).toQColor());
0360         dialog.setOptions(QColorDialog::ShowAlphaChannel);
0361         if ( dialog.exec() == QDialog::Accepted ) {
0362           setColor(whichColor, kpColor(dialog.currentColor().rgba()));
0363         }
0364     }
0365 }
0366 
0367 //---------------------------------------------------------------------
0368 
0369 // protected virtual [base QWidget]
0370 void kpDualColorButton::paintEvent (QPaintEvent *e)
0371 {
0372 #if DEBUG_KP_DUAL_COLOR_BUTTON && 1
0373     qCDebug(kpLogWidgets) << "kpDualColorButton::draw() rect=" << rect ()
0374                << " contentsRect=" << contentsRect ()
0375                << endl;
0376 #endif
0377 
0378     // Draw frame first.
0379     QFrame::paintEvent (e);
0380 
0381     QPainter painter (this);
0382 
0383     // Fill with background.
0384     if (isEnabled ())
0385     {
0386         kpView::drawTransparentBackground (&painter,
0387             contentsRect ().topLeft ()/*checkerboard top-left*/,
0388             contentsRect (),
0389             true/*preview*/);
0390     }
0391     else
0392     {
0393         // Use default widget background.
0394     }
0395 
0396 
0397     painter.translate (contentsRect ().x (), contentsRect ().y ());
0398 
0399 
0400     // Draw "Swap Colours" button (top-right).
0401     QPixmap swapPixmap = QStringLiteral(":/icons/colorbutton_swap_16x16");
0402     if (!isEnabled ())
0403     {
0404         // Don't let the fill() touch the mask.
0405         QBitmap swapBitmapMask = swapPixmap.mask ();
0406         swapPixmap.setMask (QBitmap ());
0407 
0408         // Grey out the opaque parts of "swapPixmap".
0409         swapPixmap.fill (palette ().color (QPalette::Dark));
0410 
0411         swapPixmap.setMask (swapBitmapMask);
0412     }
0413     painter.drawPixmap (swapPixmapRect ().topLeft (), swapPixmap);
0414 
0415 
0416     // Draw background colour patch.
0417     QRect bgRect = backgroundRect ();
0418     QRect bgRectInside = QRect (bgRect.x () + 2, bgRect.y () + 2,
0419                                 bgRect.width () - 4, bgRect.height () - 4);
0420     if (isEnabled ())
0421     {
0422     #if DEBUG_KP_DUAL_COLOR_BUTTON && 1
0423         qCDebug(kpLogWidgets) << "\tbackgroundColor=" << (int *) m_color [1].toQRgb ()
0424                    << endl;
0425     #endif
0426         if (m_color [1].isTransparent ()) { // only if fully transparent
0427             painter.drawPixmap (bgRectInside, QStringLiteral(":/icons/color_transparent_26x26"));
0428         }
0429         else {
0430             painter.fillRect (bgRectInside, m_color [1].toQColor ());
0431         }
0432     }
0433     else {
0434         painter.fillRect (bgRectInside, palette().color (QPalette::Button));
0435     }
0436     qDrawShadePanel (&painter, bgRect, palette(),
0437                      false/*not sunken*/, 2/*lineWidth*/,
0438                      nullptr/*never fill*/);
0439 
0440 
0441 
0442     // Draw foreground colour patch.
0443     // Must be drawn after background patch since we're on top.
0444     QRect fgRect = foregroundRect ();
0445     QRect fgRectInside = QRect (fgRect.x () + 2, fgRect.y () + 2,
0446                                 fgRect.width () - 4, fgRect.height () - 4);
0447     if (isEnabled ())
0448     {
0449     #if DEBUG_KP_DUAL_COLOR_BUTTON && 1
0450         qCDebug(kpLogWidgets) << "\tforegroundColor=" << (int *) m_color [0].toQRgb ()
0451                    << endl;
0452     #endif
0453         if (m_color [0].isTransparent ()) { // only if fully transparent
0454             painter.drawPixmap (fgRectInside, QStringLiteral(":/icons/color_transparent_26x26"));
0455         }
0456         else {
0457             painter.fillRect (fgRectInside, m_color [0].toQColor ());
0458         }
0459     }
0460     else {
0461         painter.fillRect (fgRectInside, palette ().color (QPalette::Button));
0462     }
0463 
0464     qDrawShadePanel (&painter, fgRect, palette (),
0465                      false/*not sunken*/, 2/*lineWidth*/,
0466                      nullptr/*never fill*/);
0467 }
0468 
0469 #include "moc_kpDualColorButton.cpp"