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"