Skip to content

Commit d83ef3f

Browse files
committedMay 21, 2014
[FEATURE] Allow dragging and dropping colors from color buttons (also works with some other applications, eg dropping colors from GIMP or Gpick). Tweak color button context menu to remove extra options.
1 parent d6889a4 commit d83ef3f

File tree

3 files changed

+171
-46
lines changed

3 files changed

+171
-46
lines changed
 

‎python/gui/qgscolorbutton.sip

+15
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,19 @@ class QgsColorButton: QPushButton
116116
* Reimplemented to detect right mouse button clicks on the color button.
117117
*/
118118
void mousePressEvent( QMouseEvent* e );
119+
120+
/**
121+
* Reimplemented to allow dragging colors from button
122+
*/
123+
void mouseMoveEvent( QMouseEvent *e );
124+
125+
/**
126+
* Reimplemented to accept dragged colors
127+
*/
128+
void dragEnterEvent( QDragEnterEvent * e ) ;
129+
130+
/**
131+
* Reimplemented to accept dropped colors
132+
*/
133+
void dropEvent( QDropEvent *e );
119134
};

‎src/gui/qgscolorbutton.cpp

+117-45
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ QgsColorButton::QgsColorButton( QWidget *parent, QString cdt, QColorDialog::Colo
5151
, mTempPNG( NULL )
5252
, mColorSet( false )
5353
{
54+
setAcceptDrops( true );
5455
connect( this, SIGNAL( clicked() ), this, SLOT( onButtonClicked() ) );
5556
}
5657

@@ -96,78 +97,149 @@ void QgsColorButton::mousePressEvent( QMouseEvent *e )
9697
if ( e->button() == Qt::RightButton )
9798
{
9899
showContextMenu( e );
100+
return;
99101
}
100-
else
102+
else if ( e->button() == Qt::LeftButton )
101103
{
102-
QPushButton::mousePressEvent( e );
104+
mDragStartPosition = e->pos();
103105
}
106+
QPushButton::mousePressEvent( e );
104107
}
105108

106-
void QgsColorButton::showContextMenu( QMouseEvent *event )
109+
QMimeData * QgsColorButton::createColorMimeData() const
107110
{
108-
QMenu colorContextMenu;
111+
QMimeData *mimeData = new QMimeData;
112+
mimeData->setColorData( QVariant( mColor ) );
113+
mimeData->setText( mColor.name() );
114+
return mimeData;
115+
}
109116

110-
QAction* copyAsHexAction = new QAction( tr( "Copy color" ), 0 );
111-
colorContextMenu.addAction( copyAsHexAction );
112-
QAction* copyAsRgbAction = new QAction( tr( "Copy as rgb" ), 0 );
113-
colorContextMenu.addAction( copyAsRgbAction );
114-
QAction* copyAsRgbaAction = new QAction( tr( "Copy as rgba" ), 0 );
115-
if ( mColorDialogOptions & QColorDialog::ShowAlphaChannel )
117+
bool QgsColorButton::colorFromMimeData( const QMimeData * mimeData, QColor& resultColor )
118+
{
119+
//attempt to read color data directly from mime
120+
QColor mimeColor = qVariantValue<QColor>( mimeData->colorData() );
121+
if ( mimeColor.isValid() )
116122
{
117-
//alpha enabled, so add rgba action
118-
colorContextMenu.addAction( copyAsRgbaAction );
123+
if ( !( mColorDialogOptions & QColorDialog::ShowAlphaChannel ) )
124+
{
125+
//remove alpha channel
126+
mimeColor.setAlpha( 255 );
127+
}
128+
resultColor = mimeColor;
129+
return true;
119130
}
120131

121-
QString clipboardText = QApplication::clipboard()->text();
122-
QAction* pasteColorAction = new QAction( tr( "Paste color" ), 0 );
123-
pasteColorAction->setEnabled( false );
124-
colorContextMenu.addSeparator();
125-
colorContextMenu.addAction( pasteColorAction );
126-
QColor clipColor;
127-
if ( !( clipboardText.isEmpty() ) )
132+
//attempt to intrepret a color from mime text data
133+
bool hasAlpha = false;
134+
QColor textColor = QgsSymbolLayerV2Utils::parseColorWithAlpha( mimeData->text(), hasAlpha );
135+
if ( textColor.isValid() )
128136
{
129-
bool hasAlpha = false;
130-
clipColor = QgsSymbolLayerV2Utils::parseColorWithAlpha( clipboardText, hasAlpha );
131-
132-
if ( clipColor.isValid() )
137+
if ( !( mColorDialogOptions & QColorDialog::ShowAlphaChannel ) )
133138
{
134-
if ( !hasAlpha )
135-
{
136-
//clipboard color has no explicit alpha component, so keep existing alpha
137-
clipColor.setAlpha( mColor.alpha() );
138-
}
139-
pasteColorAction->setEnabled( true );
139+
//remove alpha channel
140+
textColor.setAlpha( 255 );
140141
}
142+
else if ( !hasAlpha )
143+
{
144+
//mime color has no explicit alpha component, so keep existing alpha
145+
textColor.setAlpha( mColor.alpha() );
146+
}
147+
resultColor = textColor;
148+
return true;
141149
}
142150

143-
QAction* selectedAction = colorContextMenu.exec( event->globalPos( ) );
144-
if ( selectedAction == copyAsHexAction )
151+
//could not get color from mime data
152+
return false;
153+
}
154+
155+
void QgsColorButton::mouseMoveEvent( QMouseEvent *e )
156+
{
157+
if ( !( e->buttons() & Qt::LeftButton ) )
158+
{
159+
QPushButton::mouseMoveEvent( e );
160+
return;
161+
}
162+
163+
if (( e->pos() - mDragStartPosition ).manhattanLength() < QApplication::startDragDistance() )
145164
{
146-
//copy color as hex code
147-
QString colorString = mColor.name();
148-
QApplication::clipboard()->setText( colorString );
165+
QPushButton::mouseMoveEvent( e );
166+
return;
167+
}
168+
169+
QDrag *drag = new QDrag( this );
170+
drag->setMimeData( createColorMimeData() );
171+
172+
//craft a pixmap for the drag icon
173+
QImage colorImage( 50, 50, QImage::Format_RGB32 );
174+
QPainter imagePainter;
175+
imagePainter.begin( &colorImage );
176+
//start with a light gray background
177+
imagePainter.fillRect( QRect( 0, 0, 50, 50 ), QBrush( QColor( 200, 200, 200 ) ) );
178+
//draw rect with white border, filled with current color
179+
QColor pixmapColor = mColor;
180+
pixmapColor.setAlpha( 255 );
181+
imagePainter.setBrush( QBrush( pixmapColor ) );
182+
imagePainter.setPen( QPen( Qt::white ) );
183+
imagePainter.drawRect( QRect( 1, 1, 47, 47 ) );
184+
imagePainter.end();
185+
//set as drag pixmap
186+
drag->setPixmap( QPixmap::fromImage( colorImage ) );
187+
188+
Qt::DropAction dropAction = drag->exec( Qt::CopyAction | Qt::MoveAction );
189+
setDown( false );
190+
}
191+
192+
void QgsColorButton::dragEnterEvent( QDragEnterEvent *e )
193+
{
194+
//is dragged data valid color data?
195+
QColor mimeColor;
196+
if ( colorFromMimeData( e->mimeData(), mimeColor ) )
197+
{
198+
e->acceptProposedAction();
149199
}
150-
else if ( selectedAction == copyAsRgbAction )
200+
}
201+
202+
void QgsColorButton::dropEvent( QDropEvent *e )
203+
{
204+
//is dropped data valid color data?
205+
QColor mimeColor;
206+
if ( colorFromMimeData( e->mimeData(), mimeColor ) )
207+
{
208+
e->acceptProposedAction();
209+
setColor( mimeColor );
210+
}
211+
}
212+
213+
void QgsColorButton::showContextMenu( QMouseEvent *event )
214+
{
215+
QMenu colorContextMenu;
216+
217+
QAction* copyColorAction = new QAction( tr( "Copy color" ), 0 );
218+
colorContextMenu.addAction( copyColorAction );
219+
QAction* pasteColorAction = new QAction( tr( "Paste color" ), 0 );
220+
pasteColorAction->setEnabled( false );
221+
colorContextMenu.addSeparator();
222+
colorContextMenu.addAction( pasteColorAction );
223+
224+
QColor clipColor;
225+
if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor ) )
151226
{
152-
//copy color as rgb
153-
QString colorString = QString( "rgb(%1,%2,%3)" ).arg( mColor.red() ). arg( mColor.green() ).arg( mColor.blue() );
154-
QApplication::clipboard()->setText( colorString );
227+
pasteColorAction->setEnabled( true );
155228
}
156-
else if ( selectedAction == copyAsRgbaAction )
229+
230+
QAction* selectedAction = colorContextMenu.exec( event->globalPos( ) );
231+
if ( selectedAction == copyColorAction )
157232
{
158-
//copy color as rgba
159-
QString colorString = QString( "rgba(%1,%2,%3,%4)" ).arg( mColor.red() ).arg( mColor.green() ).arg( mColor.blue() ).arg( QString::number( mColor.alphaF(), 'f', 2 ) );
160-
QApplication::clipboard()->setText( colorString );
233+
//copy color
234+
QApplication::clipboard()->setMimeData( createColorMimeData() );
161235
}
162236
else if ( selectedAction == pasteColorAction )
163237
{
164238
//paste color
165239
setColor( clipColor );
166240
}
167241

168-
delete copyAsHexAction;
169-
delete copyAsRgbAction;
170-
delete copyAsRgbaAction;
242+
delete copyColorAction;
171243
delete pasteColorAction;
172244
}
173245

‎src/gui/qgscolorbutton.h

100755100644
+39-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <QPushButton>
2020
#include <QTemporaryFile>
2121

22+
class QMimeData;
2223

2324
/** \ingroup gui
2425
* \class QgsColorButton
@@ -110,6 +111,7 @@ class GUI_EXPORT QgsColorButton: public QPushButton
110111
*/
111112
void setAcceptLiveUpdates( bool accept ) { mAcceptLiveUpdates = accept; }
112113

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

142144
/**
143-
* Reimplemented to detect right mouse button clicks on the color button.
145+
* Reimplemented to detect right mouse button clicks on the color button and allow dragging colors
144146
*/
145147
void mousePressEvent( QMouseEvent* e );
146148

149+
/**
150+
* Reimplemented to allow dragging colors from button
151+
*/
152+
void mouseMoveEvent( QMouseEvent *e );
153+
154+
/**
155+
* Reimplemented to accept dragged colors
156+
*/
157+
void dragEnterEvent( QDragEnterEvent * e ) ;
158+
159+
/**
160+
* Reimplemented to accept dropped colors
161+
*/
162+
void dropEvent( QDropEvent *e );
163+
147164
private:
148165
QString mColorDialogTitle;
149166
QColor mColor;
@@ -152,11 +169,32 @@ class GUI_EXPORT QgsColorButton: public QPushButton
152169
QTemporaryFile mTempPNG;
153170
bool mColorSet; // added in QGIS 2.1
154171

172+
QPoint mDragStartPosition;
173+
155174
/**
156175
* Shows the color button context menu and handles copying and pasting color values.
157176
*/
158177
void showContextMenu( QMouseEvent* event );
159178

179+
/**
180+
* Creates mime data from the current color. Sets both the mime data's color data, and the
181+
* mime data's text with the color's hex code.
182+
* @note added in 2.3
183+
* @see colorFromMimeData
184+
*/
185+
QMimeData* createColorMimeData() const;
186+
187+
/**
188+
* Attempts to parse mimeData as a color, either via the mime data's color data or by
189+
* parsing a textual representation of a color.
190+
* @returns true if mime data could be intrepreted as a color
191+
* @param mimeData mime data
192+
* @param resultColor QColor to store evaluated color
193+
* @note added in 2.3
194+
* @see createColorMimeData
195+
*/
196+
bool colorFromMimeData( const QMimeData *mimeData, QColor &resultColor );
197+
160198
private slots:
161199
void onButtonClicked();
162200

0 commit comments

Comments
 (0)
Please sign in to comment.