forked from openkylin/kolourpaint
470 lines
13 KiB
C++
470 lines
13 KiB
C++
|
|
||
|
/*
|
||
|
Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
|
||
|
All rights reserved.
|
||
|
|
||
|
Redistribution and use in source and binary forms, with or without
|
||
|
modification, are permitted provided that the following conditions
|
||
|
are met:
|
||
|
|
||
|
1. Redistributions of source code must retain the above copyright
|
||
|
notice, this list of conditions and the following disclaimer.
|
||
|
2. Redistributions in binary form must reproduce the above copyright
|
||
|
notice, this list of conditions and the following disclaimer in the
|
||
|
documentation and/or other materials provided with the distribution.
|
||
|
|
||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*/
|
||
|
|
||
|
|
||
|
#define DEBUG_KP_DUAL_COLOR_BUTTON 0
|
||
|
|
||
|
|
||
|
#include "kpDualColorButton.h"
|
||
|
|
||
|
#include "views/kpView.h"
|
||
|
|
||
|
#include <KColorMimeData>
|
||
|
#include "kpLogCategories.h"
|
||
|
|
||
|
#include <QApplication>
|
||
|
#include <QBitmap>
|
||
|
#include <QColorDialog>
|
||
|
#include <QDrag>
|
||
|
#include <QMouseEvent>
|
||
|
#include <QPainter>
|
||
|
#include <qdrawutil.h>
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
kpDualColorButton::kpDualColorButton (QWidget *parent)
|
||
|
: QFrame (parent),
|
||
|
m_dragStartPoint (KP_INVALID_POINT)
|
||
|
{
|
||
|
setSizePolicy (QSizePolicy::Fixed/*horizontal*/,
|
||
|
QSizePolicy::Fixed/*vertical*/);
|
||
|
setFrameStyle (QFrame::Panel | QFrame::Sunken);
|
||
|
|
||
|
m_color [0] = kpColor (0, 0, 0); // black
|
||
|
m_color [1] = kpColor (255, 255, 255); // white
|
||
|
|
||
|
setAcceptDrops (true);
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
kpColor kpDualColorButton::color (int which) const
|
||
|
{
|
||
|
Q_ASSERT (which == 0 || which == 1);
|
||
|
|
||
|
return m_color [which];
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
kpColor kpDualColorButton::foregroundColor () const
|
||
|
{
|
||
|
return color (0);
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
kpColor kpDualColorButton::backgroundColor () const
|
||
|
{
|
||
|
return color (1);
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
void kpDualColorButton::setColor (int which, const kpColor &color)
|
||
|
{
|
||
|
Q_ASSERT (which == 0 || which == 1);
|
||
|
|
||
|
if (m_color [which] == color) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
m_oldColor [which] = m_color [which];
|
||
|
m_color [which] = color;
|
||
|
update ();
|
||
|
|
||
|
if (which == 0) {
|
||
|
emit foregroundColorChanged (color);
|
||
|
}
|
||
|
else {
|
||
|
emit backgroundColorChanged (color);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
void kpDualColorButton::setForegroundColor (const kpColor &color)
|
||
|
{
|
||
|
setColor (0, color);
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
void kpDualColorButton::setBackgroundColor (const kpColor &color)
|
||
|
{
|
||
|
setColor (1, color);
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
// public
|
||
|
kpColor kpDualColorButton::oldForegroundColor () const
|
||
|
{
|
||
|
return m_oldColor [0];
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
// public
|
||
|
kpColor kpDualColorButton::oldBackgroundColor () const
|
||
|
{
|
||
|
return m_oldColor [1];
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
// public virtual [base QWidget]
|
||
|
QSize kpDualColorButton::sizeHint () const
|
||
|
{
|
||
|
return {52, 52};
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
// protected
|
||
|
QRect kpDualColorButton::swapPixmapRect () const
|
||
|
{
|
||
|
QPixmap swapPixmap = QStringLiteral(":/icons/colorbutton_swap_16x16");
|
||
|
|
||
|
return {contentsRect ().width () - swapPixmap.width (), 0,
|
||
|
swapPixmap.width (), swapPixmap.height ()};
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
// protected
|
||
|
QRect kpDualColorButton::foregroundBackgroundRect () const
|
||
|
{
|
||
|
QRect cr (contentsRect ());
|
||
|
return {cr.width () / 8, cr.height () / 8,
|
||
|
cr.width () * 6 / 8, cr.height () * 6 / 8};
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
// protected
|
||
|
QRect kpDualColorButton::foregroundRect () const
|
||
|
{
|
||
|
QRect fbr (foregroundBackgroundRect ());
|
||
|
return {fbr.x (), fbr.y (),
|
||
|
fbr.width () * 3 / 4, fbr.height () * 3 / 4};
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
// protected
|
||
|
QRect kpDualColorButton::backgroundRect () const
|
||
|
{
|
||
|
QRect fbr (foregroundBackgroundRect ());
|
||
|
return {fbr.x () + fbr.width () / 4, fbr.y () + fbr.height () / 4,
|
||
|
fbr.width () * 3 / 4, fbr.height () * 3 / 4};
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
// protected virtual
|
||
|
void kpDualColorButton::dragEnterEvent (QDragEnterEvent *e)
|
||
|
{
|
||
|
#if DEBUG_KP_DUAL_COLOR_BUTTON
|
||
|
qCDebug(kpLogWidgets) << "kpDualColorButton::dragEnterEvent() canDecode="
|
||
|
<< KColorMimeData::canDecode (e->mimeData ());
|
||
|
#endif
|
||
|
e->accept ();
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
// protected virtual [base QWidget]
|
||
|
void kpDualColorButton::dragMoveEvent (QDragMoveEvent *e)
|
||
|
{
|
||
|
#if DEBUG_KP_DUAL_COLOR_BUTTON
|
||
|
qCDebug(kpLogWidgets) << "kpDualColorButton::dragMoveEvent() canDecode="
|
||
|
<< KColorMimeData::canDecode (e->mimeData ());
|
||
|
#endif
|
||
|
e->setAccepted (
|
||
|
(foregroundRect ().contains (e->pos ()) ||
|
||
|
backgroundRect ().contains (e->pos ())) &&
|
||
|
KColorMimeData::canDecode (e->mimeData ()));
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
// protected virtual [base QWidget]
|
||
|
void kpDualColorButton::dropEvent (QDropEvent *e)
|
||
|
{
|
||
|
QColor col = KColorMimeData::fromMimeData (e->mimeData ());
|
||
|
#if DEBUG_KP_DUAL_COLOR_BUTTON
|
||
|
qCDebug(kpLogWidgets) << "kpDualColorButton::dropEvent() col="
|
||
|
<< (int *) col.rgba()
|
||
|
<< " (with alpha=" << (int *) col.rgba () << ")";
|
||
|
#endif
|
||
|
|
||
|
if (col.isValid ())
|
||
|
{
|
||
|
if (foregroundRect ().contains (e->pos ())) {
|
||
|
setForegroundColor (kpColor (col.rgba()));
|
||
|
}
|
||
|
else if (backgroundRect ().contains (e->pos ())) {
|
||
|
setBackgroundColor (kpColor (col.rgba()));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
// protected virtual [base QWidget]
|
||
|
void kpDualColorButton::mousePressEvent (QMouseEvent *e)
|
||
|
{
|
||
|
#if DEBUG_KP_DUAL_COLOR_BUTTON
|
||
|
qCDebug(kpLogWidgets) << "kpDualColorButton::mousePressEvent() pos=" << e->pos ();
|
||
|
#endif
|
||
|
|
||
|
m_dragStartPoint = KP_INVALID_POINT;
|
||
|
|
||
|
if (e->button () == Qt::LeftButton) {
|
||
|
m_dragStartPoint = e->pos ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
void kpDualColorButton::mouseMoveEvent (QMouseEvent *e)
|
||
|
{
|
||
|
#if DEBUG_KP_DUAL_COLOR_BUTTON
|
||
|
qCDebug(kpLogWidgets) << "kpDualColorButton::mouseMoveEvent() pos=" << e->pos ()
|
||
|
<< " buttons=" << e->buttons ()
|
||
|
<< " dragStartPoint=" << m_dragStartPoint << endl;
|
||
|
#endif
|
||
|
|
||
|
if (m_dragStartPoint == KP_INVALID_POINT) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!(e->buttons () & Qt::LeftButton))
|
||
|
{
|
||
|
m_dragStartPoint = KP_INVALID_POINT;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const int delay = QApplication::startDragDistance ();
|
||
|
if (e->x () < m_dragStartPoint.x () - delay ||
|
||
|
e->x () > m_dragStartPoint.x () + delay ||
|
||
|
e->y () < m_dragStartPoint.y () - delay ||
|
||
|
e->y () > m_dragStartPoint.y () + delay)
|
||
|
{
|
||
|
#if DEBUG_KP_DUAL_COLOR_BUTTON
|
||
|
qCDebug(kpLogWidgets) << "\tstarting drag as long as it's in a rectangle";
|
||
|
#endif
|
||
|
|
||
|
kpColor color;
|
||
|
|
||
|
if (foregroundRect ().contains (m_dragStartPoint)) {
|
||
|
color = foregroundColor ();
|
||
|
}
|
||
|
else if (backgroundRect ().contains (m_dragStartPoint)) {
|
||
|
color = backgroundColor ();
|
||
|
}
|
||
|
|
||
|
#if DEBUG_KP_DUAL_COLOR_BUTTON
|
||
|
qCDebug(kpLogWidgets) << "\tcolor.isValid=" << color.isValid ()
|
||
|
<< " rgb=" << (color.isValid () ? (int *) color.toQRgb () : 0)
|
||
|
<< endl;
|
||
|
#endif
|
||
|
|
||
|
if (color.isValid ())
|
||
|
{
|
||
|
if (!color.isTransparent ()) {
|
||
|
KColorMimeData::createDrag (color.toQColor (), this)->exec ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_dragStartPoint = KP_INVALID_POINT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
// protected virtual [base QWidget]
|
||
|
void kpDualColorButton::mouseReleaseEvent (QMouseEvent *e)
|
||
|
{
|
||
|
m_dragStartPoint = KP_INVALID_POINT;
|
||
|
|
||
|
if (swapPixmapRect ().contains (e->pos ()) &&
|
||
|
m_color [0] != m_color [1])
|
||
|
{
|
||
|
#if DEBUG_KP_DUAL_COLOR_BUTTON && 1
|
||
|
qCDebug(kpLogWidgets) << "kpDualColorButton::mouseReleaseEvent() swap colors:";
|
||
|
#endif
|
||
|
m_oldColor [0] = m_color [0];
|
||
|
m_oldColor [1] = m_color [1];
|
||
|
|
||
|
kpColor temp = m_color [0];
|
||
|
m_color [0] = m_color [1];
|
||
|
m_color [1] = temp;
|
||
|
|
||
|
update ();
|
||
|
|
||
|
emit colorsSwapped (m_color [0], m_color [1]);
|
||
|
emit foregroundColorChanged (m_color [0]);
|
||
|
emit backgroundColorChanged (m_color [1]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
// protected virtual [base QWidget]
|
||
|
void kpDualColorButton::mouseDoubleClickEvent (QMouseEvent *e)
|
||
|
{
|
||
|
int whichColor = -1;
|
||
|
|
||
|
if (foregroundRect ().contains (e->pos ())) {
|
||
|
whichColor = 0;
|
||
|
}
|
||
|
else if (backgroundRect ().contains (e->pos ())) {
|
||
|
whichColor = 1;
|
||
|
}
|
||
|
|
||
|
if (whichColor == 0 || whichColor == 1)
|
||
|
{
|
||
|
QColorDialog dialog(this);
|
||
|
dialog.setCurrentColor(color(whichColor).toQColor());
|
||
|
dialog.setOptions(QColorDialog::ShowAlphaChannel);
|
||
|
if ( dialog.exec() == QDialog::Accepted ) {
|
||
|
setColor(whichColor, kpColor(dialog.currentColor().rgba()));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
// protected virtual [base QWidget]
|
||
|
void kpDualColorButton::paintEvent (QPaintEvent *e)
|
||
|
{
|
||
|
#if DEBUG_KP_DUAL_COLOR_BUTTON && 1
|
||
|
qCDebug(kpLogWidgets) << "kpDualColorButton::draw() rect=" << rect ()
|
||
|
<< " contentsRect=" << contentsRect ()
|
||
|
<< endl;
|
||
|
#endif
|
||
|
|
||
|
// Draw frame first.
|
||
|
QFrame::paintEvent (e);
|
||
|
|
||
|
QPainter painter (this);
|
||
|
|
||
|
// Fill with background.
|
||
|
if (isEnabled ())
|
||
|
{
|
||
|
kpView::drawTransparentBackground (&painter,
|
||
|
contentsRect ().topLeft ()/*checkerboard top-left*/,
|
||
|
contentsRect (),
|
||
|
true/*preview*/);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Use default widget background.
|
||
|
}
|
||
|
|
||
|
|
||
|
painter.translate (contentsRect ().x (), contentsRect ().y ());
|
||
|
|
||
|
|
||
|
// Draw "Swap Colours" button (top-right).
|
||
|
QPixmap swapPixmap = QStringLiteral(":/icons/colorbutton_swap_16x16");
|
||
|
if (!isEnabled ())
|
||
|
{
|
||
|
// Don't let the fill() touch the mask.
|
||
|
QBitmap swapBitmapMask = swapPixmap.mask ();
|
||
|
swapPixmap.setMask (QBitmap ());
|
||
|
|
||
|
// Grey out the opaque parts of "swapPixmap".
|
||
|
swapPixmap.fill (palette ().color (QPalette::Dark));
|
||
|
|
||
|
swapPixmap.setMask (swapBitmapMask);
|
||
|
}
|
||
|
painter.drawPixmap (swapPixmapRect ().topLeft (), swapPixmap);
|
||
|
|
||
|
|
||
|
// Draw background colour patch.
|
||
|
QRect bgRect = backgroundRect ();
|
||
|
QRect bgRectInside = QRect (bgRect.x () + 2, bgRect.y () + 2,
|
||
|
bgRect.width () - 4, bgRect.height () - 4);
|
||
|
if (isEnabled ())
|
||
|
{
|
||
|
#if DEBUG_KP_DUAL_COLOR_BUTTON && 1
|
||
|
qCDebug(kpLogWidgets) << "\tbackgroundColor=" << (int *) m_color [1].toQRgb ()
|
||
|
<< endl;
|
||
|
#endif
|
||
|
if (m_color [1].isTransparent ()) { // only if fully transparent
|
||
|
painter.drawPixmap (bgRectInside, QStringLiteral(":/icons/color_transparent_26x26"));
|
||
|
}
|
||
|
else {
|
||
|
painter.fillRect (bgRectInside, m_color [1].toQColor ());
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
painter.fillRect (bgRectInside, palette().color (QPalette::Button));
|
||
|
}
|
||
|
qDrawShadePanel (&painter, bgRect, palette(),
|
||
|
false/*not sunken*/, 2/*lineWidth*/,
|
||
|
nullptr/*never fill*/);
|
||
|
|
||
|
|
||
|
|
||
|
// Draw foreground colour patch.
|
||
|
// Must be drawn after background patch since we're on top.
|
||
|
QRect fgRect = foregroundRect ();
|
||
|
QRect fgRectInside = QRect (fgRect.x () + 2, fgRect.y () + 2,
|
||
|
fgRect.width () - 4, fgRect.height () - 4);
|
||
|
if (isEnabled ())
|
||
|
{
|
||
|
#if DEBUG_KP_DUAL_COLOR_BUTTON && 1
|
||
|
qCDebug(kpLogWidgets) << "\tforegroundColor=" << (int *) m_color [0].toQRgb ()
|
||
|
<< endl;
|
||
|
#endif
|
||
|
if (m_color [0].isTransparent ()) { // only if fully transparent
|
||
|
painter.drawPixmap (fgRectInside, QStringLiteral(":/icons/color_transparent_26x26"));
|
||
|
}
|
||
|
else {
|
||
|
painter.fillRect (fgRectInside, m_color [0].toQColor ());
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
painter.fillRect (fgRectInside, palette ().color (QPalette::Button));
|
||
|
}
|
||
|
|
||
|
qDrawShadePanel (&painter, fgRect, palette (),
|
||
|
false/*not sunken*/, 2/*lineWidth*/,
|
||
|
nullptr/*never fill*/);
|
||
|
}
|
||
|
|
||
|
|