25#include <QStyleOptionFrame>
27#include "moc_qgsgradientstopeditor.cpp"
29using namespace Qt::StringLiterals;
36 mStops = mGradient.
stops();
38 if ( sOuterTriangle.isEmpty() )
41 << QPointF( 0, MARKER_HEIGHT )
42 << QPointF( MARKER_WIDTH, MARKER_HEIGHT )
43 << QPointF( MARKER_WIDTH, MARKER_WIDTH / 2.0 )
44 << QPointF( MARKER_WIDTH / 2.0, 0 )
45 << QPointF( 0, MARKER_WIDTH / 2.0 )
46 << QPointF( 0, MARKER_HEIGHT );
48 if ( sInnerTriangle.isEmpty() )
51 << QPointF( MARKER_GAP, MARKER_HEIGHT - MARKER_GAP )
52 << QPointF( MARKER_WIDTH - MARKER_GAP, MARKER_HEIGHT - MARKER_GAP )
53 << QPointF( MARKER_WIDTH - MARKER_GAP, MARKER_WIDTH / 2.0 + 1 )
54 << QPointF( MARKER_WIDTH / 2.0, MARKER_GAP )
55 << QPointF( MARKER_GAP, MARKER_WIDTH / 2.0 + 1 )
56 << QPointF( MARKER_GAP, MARKER_HEIGHT - MARKER_GAP );
59 setFocusPolicy( Qt::StrongFocus );
60 setAcceptDrops(
true );
66 mStops = mGradient.
stops();
75 return QSize( 200, 80 );
81 QPainter painter(
this );
83 QRect frameRect( rect().x() + MARGIN_X, rect().y(), rect().width() - 2 * MARGIN_X, rect().height() - MARGIN_BOTTOM );
86 QStyleOptionFrame option;
87 option.initFrom(
this );
88 option.state = hasFocus() ? QStyle::State_KeyboardFocusChange : QStyle::State_None;
89 option.rect = frameRect;
90 style()->drawPrimitive( QStyle::PE_Frame, &option, &painter );
95 QStyleOptionFocusRect option;
96 option.initFrom(
this );
97 option.state = QStyle::State_KeyboardFocusChange;
98 option.rect = frameRect;
99 style()->drawPrimitive( QStyle::PE_FrameFocusRect, &option, &painter );
103 QBrush checkBrush = QBrush( transparentBackground() );
104 painter.setBrush( checkBrush );
105 painter.setPen( Qt::NoPen );
107 QRect box( frameRect.x() + FRAME_MARGIN_PX, frameRect.y() + FRAME_MARGIN_PX, frameRect.width() - 2 * FRAME_MARGIN_PX, frameRect.height() - 2 * FRAME_MARGIN_PX );
109 painter.drawRect( box );
112 for (
int i = 0; i < box.width() + 1; ++i )
114 QPen pen( mGradient.color(
static_cast<double>( i ) / box.width() ) );
115 painter.setPen( pen );
116 painter.drawLine( box.left() + i, box.top(), box.left() + i, box.height() + 1 );
120 int markerTop = frameRect.bottom() + 1;
121 drawStopMarker( painter, QPoint( box.left(), markerTop ), mGradient.color1(), mSelectedStop == 0 );
122 drawStopMarker( painter, QPoint( box.right(), markerTop ), mGradient.color2(), mSelectedStop == mGradient.count() - 1 );
124 const auto constMStops = mStops;
127 int x = stop.offset * box.width() + box.left();
128 drawStopMarker( painter, QPoint( x, markerTop ), stop.color, mSelectedStop == i );
137 if ( index > 0 && index < mGradient.count() - 1 )
142 const auto constMStops = mStops;
153 mSelectedStop = index;
160 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
162 return mStops.at( mSelectedStop - 1 );
164 else if ( mSelectedStop == 0 )
179 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
181 mStops[mSelectedStop - 1].color = color;
182 mGradient.setStops( mStops );
184 else if ( mSelectedStop == 0 )
186 mGradient.setColor1( color );
190 mGradient.setColor2( color );
198 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
200 mStops[mSelectedStop - 1].offset = offset;
201 mGradient.setStops( mStops );
209 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
211 mStops[mSelectedStop - 1].setColorSpec( spec );
212 mGradient.setStops( mStops );
216 else if ( mSelectedStop == mGradient.count() - 1 )
218 mGradient.setColorSpec( spec );
226 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
228 mStops[mSelectedStop - 1].setDirection( direction );
229 mGradient.setStops( mStops );
233 else if ( mSelectedStop == mGradient.count() - 1 )
235 mGradient.setDirection( direction );
243 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
245 mStops[mSelectedStop - 1].color = color;
246 mStops[mSelectedStop - 1].offset = offset;
247 mGradient.setStops( mStops );
249 else if ( mSelectedStop == 0 )
251 mGradient.setColor1( color );
255 mGradient.setColor2( color );
264 if ( selectedStopIsMovable() )
267 double stopOffset = mStops.at( mSelectedStop - 1 ).offset;
268 mStops.removeAt( mSelectedStop - 1 );
269 mGradient.setStops( mStops );
271 int closest = findClosestStop( relativePositionToPoint( stopOffset ) );
281 mGradient.setColor1( color );
288 mGradient.setColor2( color );
295 if ( e->buttons() & Qt::LeftButton )
297 if ( selectedStopIsMovable() )
299 double offset = pointToRelativePosition( e->pos().x() );
303 mStops[mSelectedStop - 1].offset = offset;
305 mGradient.setStops( mStops );
313int QgsGradientStopEditor::findClosestStop(
int x,
int threshold )
const
315 int closestStop = -1;
316 int closestDiff = std::numeric_limits<int>::max();
317 int currentDiff = std::numeric_limits<int>::max();
323 const auto constStops = mGradient.
stops();
326 currentDiff = std::abs( relativePositionToPoint( stop.offset ) + 1 - x );
327 if ( ( threshold < 0 || currentDiff < threshold ) && currentDiff < closestDiff )
330 closestDiff = currentDiff;
336 currentDiff = std::abs( relativePositionToPoint( 0.0 ) + 1 - x );
337 if ( ( threshold < 0 || currentDiff < threshold ) && currentDiff < closestDiff )
340 closestDiff = currentDiff;
344 currentDiff = std::abs( relativePositionToPoint( 1.0 ) + 1 - x );
345 if ( ( threshold < 0 || currentDiff < threshold ) && currentDiff < closestDiff )
347 closestStop = mGradient.count() - 1;
355 if ( e->pos().y() >= rect().height() - MARGIN_BOTTOM - 1 )
358 int closestStop = findClosestStop( e->pos().x(), CLICK_THRESHOLD );
359 if ( closestStop >= 0 )
370 if ( e->buttons() & Qt::LeftButton )
373 double offset = pointToRelativePosition( e->pos().x() );
375 mSelectedStop = mStops.length();
376 mGradient.setStops( mStops );
385 if ( ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ) )
391 else if ( e->key() == Qt::Key_Left || e->key() == Qt::Key_Right )
393 if ( selectedStopIsMovable() )
396 double offsetDiff = pointToRelativePosition( rect().x() + MARGIN_X + FRAME_MARGIN_PX + 2 ) - pointToRelativePosition( rect().x() + MARGIN_X + FRAME_MARGIN_PX + 1 );
398 if ( e->modifiers() & Qt::ShiftModifier )
401 if ( e->key() == Qt::Key_Left )
404 mStops[mSelectedStop - 1].offset = std::clamp( mStops[mSelectedStop - 1].offset + offsetDiff, 0.0, 1.0 );
405 mGradient.setStops( mStops );
413 QWidget::keyPressEvent( e );
416QPixmap QgsGradientStopEditor::transparentBackground()
418 static QPixmap sTranspBkgrd;
420 if ( sTranspBkgrd.isNull() )
426void QgsGradientStopEditor::drawStopMarker( QPainter &painter, QPoint topMiddle,
const QColor &color,
bool selected )
428 QgsScopedQPainterState painterState( &painter );
429 painter.setRenderHint( QPainter::Antialiasing );
430 painter.setBrush( selected ? QColor( 150, 150, 150 ) : Qt::white );
431 painter.setPen( selected ? Qt::black : QColor( 150, 150, 150 ) );
433 painter.translate( std::round( topMiddle.x() - MARKER_WIDTH / 2.0 ) + 0.5, topMiddle.y() + 0.5 );
434 painter.drawPolygon( sOuterTriangle );
437 painter.setBrush( QBrush( transparentBackground() ) );
438 painter.setPen( Qt::NoPen );
439 painter.drawPolygon( sInnerTriangle );
442 painter.setBrush( color );
443 painter.drawPolygon( sInnerTriangle );
446double QgsGradientStopEditor::pointToRelativePosition(
int x )
const
448 int left = rect().x() + MARGIN_X + FRAME_MARGIN_PX;
449 int right = left + rect().width() - 2 * MARGIN_X - 2 * FRAME_MARGIN_PX;
453 else if ( x >= right )
456 return static_cast<double>( x - left ) / ( right - left );
459int QgsGradientStopEditor::relativePositionToPoint(
double position )
const
461 int left = rect().x() + MARGIN_X + FRAME_MARGIN_PX;
462 int right = left + rect().width() - 2 * MARGIN_X - 2 * FRAME_MARGIN_PX;
466 else if ( position >= 1.0 )
469 return left + ( right - left ) * position;
472bool QgsGradientStopEditor::selectedStopIsMovable()
const
475 return mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1;
485 if ( mimeColor.isValid() )
488 e->acceptProposedAction();
495 bool hasAlpha =
false;
498 if ( mimeColor.isValid() )
501 e->acceptProposedAction();
504 double offset = pointToRelativePosition( e->pos().x() );
506 mSelectedStop = mStops.length();
507 mGradient.setStops( mStops );
AngularDirection
Angular directions.
static QPixmap getThemePixmap(const QString &name, const QColor &foreColor=QColor(), const QColor &backColor=QColor(), int size=16)
Helper to get a theme icon as a pixmap.
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
QgsGradientStopsList stops() const
Returns the list of intermediate gradient stops for the ramp.
void setSelectedStopOffset(double offset)
Sets the offset for the current selected stop.
void setColor2(const QColor &color)
Sets the color for the last stop.
void setSelectedStopColor(const QColor &color)
Sets the color for the current selected stop.
void changed()
Emitted when the gradient ramp is changed by a user.
void mousePressEvent(QMouseEvent *event) override
void mouseDoubleClickEvent(QMouseEvent *event) override
void setSelectedStopColorSpec(QColor::Spec spec)
Sets the color spec for the current selected stop.
QgsGradientStop selectedStop() const
Returns details about the currently selected stop.
void keyPressEvent(QKeyEvent *event) override
void setSelectedStopDetails(const QColor &color, double offset)
Sets the color and offset for the current selected stop.
void deleteSelectedStop()
Deletes the current selected stop.
void paintEvent(QPaintEvent *event) override
void selectStop(int index)
Sets the currently selected stop.
QSize sizeHint() const override
void setColor1(const QColor &color)
Sets the color for the first stop.
void setSelectedStopDirection(Qgis::AngularDirection direction)
Sets the hue angular direction for the current selected stop.
void selectedStopChanged(const QgsGradientStop &stop)
Emitted when the current selected stop changes.
QgsGradientStopEditor(QWidget *parent=nullptr, QgsGradientColorRamp *ramp=nullptr)
Constructor for QgsGradientStopEditor.
void dropEvent(QDropEvent *e) override
void mouseMoveEvent(QMouseEvent *event) override
void setGradientRamp(const QgsGradientColorRamp &ramp)
Sets the current ramp shown in the editor.
void dragEnterEvent(QDragEnterEvent *e) override
Represents a color stop within a QgsGradientColorRamp color ramp.
void setColorSpec(QColor::Spec spec)
Sets the color specification in which the color component interpolation will occur.
void setDirection(Qgis::AngularDirection direction)
Sets the direction to traverse the color wheel using when interpolating hue-based color specification...
static QColor colorFromMimeData(const QMimeData *data, bool &hasAlpha)
Attempts to parse mime data as a color.