24#include <QStyleOptionFrame>
26#include "moc_qgsgradientstopeditor.cpp"
28using namespace Qt::StringLiterals;
35 mStops = mGradient.
stops();
37 if ( sOuterTriangle.isEmpty() )
39 sOuterTriangle << QPointF( 0, MARKER_HEIGHT ) << QPointF( MARKER_WIDTH, MARKER_HEIGHT )
40 << QPointF( MARKER_WIDTH, MARKER_WIDTH / 2.0 )
41 << QPointF( MARKER_WIDTH / 2.0, 0 )
42 << QPointF( 0, MARKER_WIDTH / 2.0 )
43 << QPointF( 0, MARKER_HEIGHT );
45 if ( sInnerTriangle.isEmpty() )
47 sInnerTriangle << QPointF( MARKER_GAP, MARKER_HEIGHT - MARKER_GAP ) << QPointF( MARKER_WIDTH - MARKER_GAP, MARKER_HEIGHT - MARKER_GAP )
48 << QPointF( MARKER_WIDTH - MARKER_GAP, MARKER_WIDTH / 2.0 + 1 )
49 << QPointF( MARKER_WIDTH / 2.0, MARKER_GAP )
50 << QPointF( MARKER_GAP, MARKER_WIDTH / 2.0 + 1 )
51 << QPointF( MARKER_GAP, MARKER_HEIGHT - MARKER_GAP );
54 setFocusPolicy( Qt::StrongFocus );
55 setAcceptDrops(
true );
61 mStops = mGradient.
stops();
70 return QSize( 200, 80 );
76 QPainter painter(
this );
78 QRect frameRect( rect().x() + MARGIN_X, rect().y(), rect().width() - 2 * MARGIN_X, rect().height() - MARGIN_BOTTOM );
81 QStyleOptionFrame option;
82 option.initFrom(
this );
83 option.state = hasFocus() ? QStyle::State_KeyboardFocusChange : QStyle::State_None;
84 option.rect = frameRect;
85 style()->drawPrimitive( QStyle::PE_Frame, &option, &painter );
90 QStyleOptionFocusRect option;
91 option.initFrom(
this );
92 option.state = QStyle::State_KeyboardFocusChange;
93 option.rect = frameRect;
94 style()->drawPrimitive( QStyle::PE_FrameFocusRect, &option, &painter );
98 QBrush checkBrush = QBrush( transparentBackground() );
99 painter.setBrush( checkBrush );
100 painter.setPen( Qt::NoPen );
102 QRect box( frameRect.x() + FRAME_MARGIN_PX, frameRect.y() + FRAME_MARGIN_PX, frameRect.width() - 2 * FRAME_MARGIN_PX, frameRect.height() - 2 * FRAME_MARGIN_PX );
104 painter.drawRect( box );
107 for (
int i = 0; i < box.width() + 1; ++i )
109 QPen pen( mGradient.color(
static_cast<double>( i ) / box.width() ) );
110 painter.setPen( pen );
111 painter.drawLine( box.left() + i, box.top(), box.left() + i, box.height() + 1 );
115 int markerTop = frameRect.bottom() + 1;
116 drawStopMarker( painter, QPoint( box.left(), markerTop ), mGradient.color1(), mSelectedStop == 0 );
117 drawStopMarker( painter, QPoint( box.right(), markerTop ), mGradient.color2(), mSelectedStop == mGradient.count() - 1 );
119 const auto constMStops = mStops;
122 int x = stop.offset * box.width() + box.left();
123 drawStopMarker( painter, QPoint( x, markerTop ), stop.color, mSelectedStop == i );
132 if ( index > 0 && index < mGradient.count() - 1 )
137 const auto constMStops = mStops;
148 mSelectedStop = index;
155 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
157 return mStops.at( mSelectedStop - 1 );
159 else if ( mSelectedStop == 0 )
174 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
176 mStops[mSelectedStop - 1].color = color;
177 mGradient.setStops( mStops );
179 else if ( mSelectedStop == 0 )
181 mGradient.setColor1( color );
185 mGradient.setColor2( color );
193 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
195 mStops[mSelectedStop - 1].offset = offset;
196 mGradient.setStops( mStops );
204 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
206 mStops[mSelectedStop - 1].setColorSpec( spec );
207 mGradient.setStops( mStops );
211 else if ( mSelectedStop == mGradient.count() - 1 )
213 mGradient.setColorSpec( spec );
221 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
223 mStops[mSelectedStop - 1].setDirection( direction );
224 mGradient.setStops( mStops );
228 else if ( mSelectedStop == mGradient.count() - 1 )
230 mGradient.setDirection( direction );
238 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
240 mStops[mSelectedStop - 1].color = color;
241 mStops[mSelectedStop - 1].offset = offset;
242 mGradient.setStops( mStops );
244 else if ( mSelectedStop == 0 )
246 mGradient.setColor1( color );
250 mGradient.setColor2( color );
259 if ( selectedStopIsMovable() )
262 double stopOffset = mStops.at( mSelectedStop - 1 ).offset;
263 mStops.removeAt( mSelectedStop - 1 );
264 mGradient.setStops( mStops );
266 int closest = findClosestStop( relativePositionToPoint( stopOffset ) );
276 mGradient.setColor1( color );
283 mGradient.setColor2( color );
290 if ( e->buttons() & Qt::LeftButton )
292 if ( selectedStopIsMovable() )
294 double offset = pointToRelativePosition( e->pos().x() );
298 mStops[mSelectedStop - 1].offset = offset;
300 mGradient.setStops( mStops );
308int QgsGradientStopEditor::findClosestStop(
int x,
int threshold )
const
310 int closestStop = -1;
311 int closestDiff = std::numeric_limits<int>::max();
312 int currentDiff = std::numeric_limits<int>::max();
318 const auto constStops = mGradient.
stops();
321 currentDiff = std::abs( relativePositionToPoint( stop.offset ) + 1 - x );
322 if ( ( threshold < 0 || currentDiff < threshold ) && currentDiff < closestDiff )
325 closestDiff = currentDiff;
331 currentDiff = std::abs( relativePositionToPoint( 0.0 ) + 1 - x );
332 if ( ( threshold < 0 || currentDiff < threshold ) && currentDiff < closestDiff )
335 closestDiff = currentDiff;
339 currentDiff = std::abs( relativePositionToPoint( 1.0 ) + 1 - x );
340 if ( ( threshold < 0 || currentDiff < threshold ) && currentDiff < closestDiff )
342 closestStop = mGradient.count() - 1;
350 if ( e->pos().y() >= rect().height() - MARGIN_BOTTOM - 1 )
353 int closestStop = findClosestStop( e->pos().x(), CLICK_THRESHOLD );
354 if ( closestStop >= 0 )
365 if ( e->buttons() & Qt::LeftButton )
368 double offset = pointToRelativePosition( e->pos().x() );
370 mSelectedStop = mStops.length();
371 mGradient.setStops( mStops );
380 if ( ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ) )
386 else if ( e->key() == Qt::Key_Left || e->key() == Qt::Key_Right )
388 if ( selectedStopIsMovable() )
391 double offsetDiff = pointToRelativePosition( rect().x() + MARGIN_X + FRAME_MARGIN_PX + 2 ) - pointToRelativePosition( rect().x() + MARGIN_X + FRAME_MARGIN_PX + 1 );
393 if ( e->modifiers() & Qt::ShiftModifier )
396 if ( e->key() == Qt::Key_Left )
399 mStops[mSelectedStop - 1].offset = std::clamp( mStops[mSelectedStop - 1].offset + offsetDiff, 0.0, 1.0 );
400 mGradient.setStops( mStops );
408 QWidget::keyPressEvent( e );
411QPixmap QgsGradientStopEditor::transparentBackground()
413 static QPixmap sTranspBkgrd;
415 if ( sTranspBkgrd.isNull() )
421void QgsGradientStopEditor::drawStopMarker( QPainter &painter, QPoint topMiddle,
const QColor &color,
bool selected )
423 QgsScopedQPainterState painterState( &painter );
424 painter.setRenderHint( QPainter::Antialiasing );
425 painter.setBrush( selected ? QColor( 150, 150, 150 ) : Qt::white );
426 painter.setPen( selected ? Qt::black : QColor( 150, 150, 150 ) );
428 painter.translate( std::round( topMiddle.x() - MARKER_WIDTH / 2.0 ) + 0.5, topMiddle.y() + 0.5 );
429 painter.drawPolygon( sOuterTriangle );
432 painter.setBrush( QBrush( transparentBackground() ) );
433 painter.setPen( Qt::NoPen );
434 painter.drawPolygon( sInnerTriangle );
437 painter.setBrush( color );
438 painter.drawPolygon( sInnerTriangle );
441double QgsGradientStopEditor::pointToRelativePosition(
int x )
const
443 int left = rect().x() + MARGIN_X + FRAME_MARGIN_PX;
444 int right = left + rect().width() - 2 * MARGIN_X - 2 * FRAME_MARGIN_PX;
448 else if ( x >= right )
451 return static_cast<double>( x - left ) / ( right - left );
454int QgsGradientStopEditor::relativePositionToPoint(
double position )
const
456 int left = rect().x() + MARGIN_X + FRAME_MARGIN_PX;
457 int right = left + rect().width() - 2 * MARGIN_X - 2 * FRAME_MARGIN_PX;
461 else if ( position >= 1.0 )
464 return left + ( right - left ) * position;
467bool QgsGradientStopEditor::selectedStopIsMovable()
const
470 return mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1;
480 if ( mimeColor.isValid() )
483 e->acceptProposedAction();
490 bool hasAlpha =
false;
493 if ( mimeColor.isValid() )
496 e->acceptProposedAction();
499 double offset = pointToRelativePosition( e->pos().x() );
501 mSelectedStop = mStops.length();
502 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.