Skip to content

Commit

Permalink
[FEATURE] Allow dragging and dropping colors from color buttons (also…
Browse files Browse the repository at this point in the history
… works with some other applications, eg dropping colors from GIMP or Gpick). Tweak color button context menu to remove extra options.
  • Loading branch information
nyalldawson committed May 21, 2014
1 parent d6889a4 commit d83ef3f
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 46 deletions.
15 changes: 15 additions & 0 deletions python/gui/qgscolorbutton.sip
Expand Up @@ -116,4 +116,19 @@ class QgsColorButton: QPushButton
* Reimplemented to detect right mouse button clicks on the color button.
*/
void mousePressEvent( QMouseEvent* e );

/**
* Reimplemented to allow dragging colors from button
*/
void mouseMoveEvent( QMouseEvent *e );

/**
* Reimplemented to accept dragged colors
*/
void dragEnterEvent( QDragEnterEvent * e ) ;

/**
* Reimplemented to accept dropped colors
*/
void dropEvent( QDropEvent *e );
};
162 changes: 117 additions & 45 deletions src/gui/qgscolorbutton.cpp
Expand Up @@ -51,6 +51,7 @@ QgsColorButton::QgsColorButton( QWidget *parent, QString cdt, QColorDialog::Colo
, mTempPNG( NULL )
, mColorSet( false )
{
setAcceptDrops( true );
connect( this, SIGNAL( clicked() ), this, SLOT( onButtonClicked() ) );
}

Expand Down Expand Up @@ -96,78 +97,149 @@ void QgsColorButton::mousePressEvent( QMouseEvent *e )
if ( e->button() == Qt::RightButton )
{
showContextMenu( e );
return;
}
else
else if ( e->button() == Qt::LeftButton )
{
QPushButton::mousePressEvent( e );
mDragStartPosition = e->pos();
}
QPushButton::mousePressEvent( e );
}

void QgsColorButton::showContextMenu( QMouseEvent *event )
QMimeData * QgsColorButton::createColorMimeData() const
{
QMenu colorContextMenu;
QMimeData *mimeData = new QMimeData;
mimeData->setColorData( QVariant( mColor ) );
mimeData->setText( mColor.name() );
return mimeData;
}

QAction* copyAsHexAction = new QAction( tr( "Copy color" ), 0 );
colorContextMenu.addAction( copyAsHexAction );
QAction* copyAsRgbAction = new QAction( tr( "Copy as rgb" ), 0 );
colorContextMenu.addAction( copyAsRgbAction );
QAction* copyAsRgbaAction = new QAction( tr( "Copy as rgba" ), 0 );
if ( mColorDialogOptions & QColorDialog::ShowAlphaChannel )
bool QgsColorButton::colorFromMimeData( const QMimeData * mimeData, QColor& resultColor )
{
//attempt to read color data directly from mime
QColor mimeColor = qVariantValue<QColor>( mimeData->colorData() );
if ( mimeColor.isValid() )
{
//alpha enabled, so add rgba action
colorContextMenu.addAction( copyAsRgbaAction );
if ( !( mColorDialogOptions & QColorDialog::ShowAlphaChannel ) )
{
//remove alpha channel
mimeColor.setAlpha( 255 );
}
resultColor = mimeColor;
return true;
}

QString clipboardText = QApplication::clipboard()->text();
QAction* pasteColorAction = new QAction( tr( "Paste color" ), 0 );
pasteColorAction->setEnabled( false );
colorContextMenu.addSeparator();
colorContextMenu.addAction( pasteColorAction );
QColor clipColor;
if ( !( clipboardText.isEmpty() ) )
//attempt to intrepret a color from mime text data
bool hasAlpha = false;
QColor textColor = QgsSymbolLayerV2Utils::parseColorWithAlpha( mimeData->text(), hasAlpha );
if ( textColor.isValid() )
{
bool hasAlpha = false;
clipColor = QgsSymbolLayerV2Utils::parseColorWithAlpha( clipboardText, hasAlpha );

if ( clipColor.isValid() )
if ( !( mColorDialogOptions & QColorDialog::ShowAlphaChannel ) )
{
if ( !hasAlpha )
{
//clipboard color has no explicit alpha component, so keep existing alpha
clipColor.setAlpha( mColor.alpha() );
}
pasteColorAction->setEnabled( true );
//remove alpha channel
textColor.setAlpha( 255 );
}
else if ( !hasAlpha )
{
//mime color has no explicit alpha component, so keep existing alpha
textColor.setAlpha( mColor.alpha() );
}
resultColor = textColor;
return true;
}

QAction* selectedAction = colorContextMenu.exec( event->globalPos( ) );
if ( selectedAction == copyAsHexAction )
//could not get color from mime data
return false;
}

void QgsColorButton::mouseMoveEvent( QMouseEvent *e )
{
if ( !( e->buttons() & Qt::LeftButton ) )
{
QPushButton::mouseMoveEvent( e );
return;
}

if (( e->pos() - mDragStartPosition ).manhattanLength() < QApplication::startDragDistance() )
{
//copy color as hex code
QString colorString = mColor.name();
QApplication::clipboard()->setText( colorString );
QPushButton::mouseMoveEvent( e );
return;
}

QDrag *drag = new QDrag( this );
drag->setMimeData( createColorMimeData() );

//craft a pixmap for the drag icon
QImage colorImage( 50, 50, QImage::Format_RGB32 );
QPainter imagePainter;
imagePainter.begin( &colorImage );
//start with a light gray background
imagePainter.fillRect( QRect( 0, 0, 50, 50 ), QBrush( QColor( 200, 200, 200 ) ) );
//draw rect with white border, filled with current color
QColor pixmapColor = mColor;
pixmapColor.setAlpha( 255 );
imagePainter.setBrush( QBrush( pixmapColor ) );
imagePainter.setPen( QPen( Qt::white ) );
imagePainter.drawRect( QRect( 1, 1, 47, 47 ) );
imagePainter.end();
//set as drag pixmap
drag->setPixmap( QPixmap::fromImage( colorImage ) );

Qt::DropAction dropAction = drag->exec( Qt::CopyAction | Qt::MoveAction );
setDown( false );
}

void QgsColorButton::dragEnterEvent( QDragEnterEvent *e )
{
//is dragged data valid color data?
QColor mimeColor;
if ( colorFromMimeData( e->mimeData(), mimeColor ) )
{
e->acceptProposedAction();
}
else if ( selectedAction == copyAsRgbAction )
}

void QgsColorButton::dropEvent( QDropEvent *e )
{
//is dropped data valid color data?
QColor mimeColor;
if ( colorFromMimeData( e->mimeData(), mimeColor ) )
{
e->acceptProposedAction();
setColor( mimeColor );
}
}

void QgsColorButton::showContextMenu( QMouseEvent *event )
{
QMenu colorContextMenu;

QAction* copyColorAction = new QAction( tr( "Copy color" ), 0 );
colorContextMenu.addAction( copyColorAction );
QAction* pasteColorAction = new QAction( tr( "Paste color" ), 0 );
pasteColorAction->setEnabled( false );
colorContextMenu.addSeparator();
colorContextMenu.addAction( pasteColorAction );

QColor clipColor;
if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor ) )
{
//copy color as rgb
QString colorString = QString( "rgb(%1,%2,%3)" ).arg( mColor.red() ). arg( mColor.green() ).arg( mColor.blue() );
QApplication::clipboard()->setText( colorString );
pasteColorAction->setEnabled( true );
}
else if ( selectedAction == copyAsRgbaAction )

QAction* selectedAction = colorContextMenu.exec( event->globalPos( ) );
if ( selectedAction == copyColorAction )
{
//copy color as rgba
QString colorString = QString( "rgba(%1,%2,%3,%4)" ).arg( mColor.red() ).arg( mColor.green() ).arg( mColor.blue() ).arg( QString::number( mColor.alphaF(), 'f', 2 ) );
QApplication::clipboard()->setText( colorString );
//copy color
QApplication::clipboard()->setMimeData( createColorMimeData() );
}
else if ( selectedAction == pasteColorAction )
{
//paste color
setColor( clipColor );
}

delete copyAsHexAction;
delete copyAsRgbAction;
delete copyAsRgbaAction;
delete copyColorAction;
delete pasteColorAction;
}

Expand Down
40 changes: 39 additions & 1 deletion src/gui/qgscolorbutton.h 100755 → 100644
Expand Up @@ -19,6 +19,7 @@
#include <QPushButton>
#include <QTemporaryFile>

class QMimeData;

/** \ingroup gui
* \class QgsColorButton
Expand Down Expand Up @@ -110,6 +111,7 @@ class GUI_EXPORT QgsColorButton: public QPushButton
*/
void setAcceptLiveUpdates( bool accept ) { mAcceptLiveUpdates = accept; }


public slots:
/**
* Sets the background pixmap for the button based upon set color and transparency.
Expand Down Expand Up @@ -140,10 +142,25 @@ class GUI_EXPORT QgsColorButton: public QPushButton
static const QPixmap& transpBkgrd();

/**
* Reimplemented to detect right mouse button clicks on the color button.
* Reimplemented to detect right mouse button clicks on the color button and allow dragging colors
*/
void mousePressEvent( QMouseEvent* e );

/**
* Reimplemented to allow dragging colors from button
*/
void mouseMoveEvent( QMouseEvent *e );

/**
* Reimplemented to accept dragged colors
*/
void dragEnterEvent( QDragEnterEvent * e ) ;

/**
* Reimplemented to accept dropped colors
*/
void dropEvent( QDropEvent *e );

private:
QString mColorDialogTitle;
QColor mColor;
Expand All @@ -152,11 +169,32 @@ class GUI_EXPORT QgsColorButton: public QPushButton
QTemporaryFile mTempPNG;
bool mColorSet; // added in QGIS 2.1

QPoint mDragStartPosition;

/**
* Shows the color button context menu and handles copying and pasting color values.
*/
void showContextMenu( QMouseEvent* event );

/**
* Creates mime data from the current color. Sets both the mime data's color data, and the
* mime data's text with the color's hex code.
* @note added in 2.3
* @see colorFromMimeData
*/
QMimeData* createColorMimeData() const;

/**
* Attempts to parse mimeData as a color, either via the mime data's color data or by
* parsing a textual representation of a color.
* @returns true if mime data could be intrepreted as a color
* @param mimeData mime data
* @param resultColor QColor to store evaluated color
* @note added in 2.3
* @see createColorMimeData
*/
bool colorFromMimeData( const QMimeData *mimeData, QColor &resultColor );

private slots:
void onButtonClicked();

Expand Down

0 comments on commit d83ef3f

Please sign in to comment.