24#include <QStyleOptionFrame>
26#include "moc_qgsgradientstopeditor.cpp"
28using namespace Qt::StringLiterals;
35 mStops = mGradient.
stops();
37 if ( sOuterTriangle.isEmpty() )
40 << QPointF( 0, MARKER_HEIGHT )
41 << QPointF( MARKER_WIDTH, MARKER_HEIGHT )
42 << QPointF( MARKER_WIDTH, MARKER_WIDTH / 2.0 )
43 << QPointF( MARKER_WIDTH / 2.0, 0 )
44 << QPointF( 0, MARKER_WIDTH / 2.0 )
45 << QPointF( 0, MARKER_HEIGHT );
47 if ( sInnerTriangle.isEmpty() )
50 << QPointF( MARKER_GAP, MARKER_HEIGHT - MARKER_GAP )
51 << QPointF( MARKER_WIDTH - MARKER_GAP, MARKER_HEIGHT - MARKER_GAP )
52 << QPointF( MARKER_WIDTH - MARKER_GAP, MARKER_WIDTH / 2.0 + 1 )
53 << QPointF( MARKER_WIDTH / 2.0, MARKER_GAP )
54 << QPointF( MARKER_GAP, MARKER_WIDTH / 2.0 + 1 )
55 << QPointF( MARKER_GAP, MARKER_HEIGHT - MARKER_GAP );
58 setFocusPolicy( Qt::StrongFocus );
59 setAcceptDrops(
true );
65 mStops = mGradient.
stops();
74 return QSize( 200, 80 );
80 QPainter painter(
this );
82 QRect frameRect( rect().x() + MARGIN_X, rect().y(), rect().width() - 2 * MARGIN_X, rect().height() - MARGIN_BOTTOM );
85 QStyleOptionFrame option;
86 option.initFrom(
this );
87 option.state = hasFocus() ? QStyle::State_KeyboardFocusChange : QStyle::State_None;
88 option.rect = frameRect;
89 style()->drawPrimitive( QStyle::PE_Frame, &option, &painter );
94 QStyleOptionFocusRect option;
95 option.initFrom(
this );
96 option.state = QStyle::State_KeyboardFocusChange;
97 option.rect = frameRect;
98 style()->drawPrimitive( QStyle::PE_FrameFocusRect, &option, &painter );
102 QBrush checkBrush = QBrush( transparentBackground() );
103 painter.setBrush( checkBrush );
104 painter.setPen( Qt::NoPen );
106 QRect box( frameRect.x() + FRAME_MARGIN_PX, frameRect.y() + FRAME_MARGIN_PX, frameRect.width() - 2 * FRAME_MARGIN_PX, frameRect.height() - 2 * FRAME_MARGIN_PX );
108 painter.drawRect( box );
111 for (
int i = 0; i < box.width() + 1; ++i )
113 QPen pen( mGradient.color(
static_cast<double>( i ) / box.width() ) );
114 painter.setPen( pen );
115 painter.drawLine( box.left() + i, box.top(), box.left() + i, box.height() + 1 );
119 int markerTop = frameRect.bottom() + 1;
120 drawStopMarker( painter, QPoint( box.left(), markerTop ), mGradient.color1(), mSelectedStop == 0 );
121 drawStopMarker( painter, QPoint( box.right(), markerTop ), mGradient.color2(), mSelectedStop == mGradient.count() - 1 );
123 const auto constMStops = mStops;
126 int x = stop.offset * box.width() + box.left();
127 drawStopMarker( painter, QPoint( x, markerTop ), stop.color, mSelectedStop == i );
136 if ( index > 0 && index < mGradient.count() - 1 )
141 const auto constMStops = mStops;
152 mSelectedStop = index;
159 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
161 return mStops.at( mSelectedStop - 1 );
163 else if ( mSelectedStop == 0 )
178 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
180 mStops[mSelectedStop - 1].color = color;
181 mGradient.setStops( mStops );
183 else if ( mSelectedStop == 0 )
185 mGradient.setColor1( color );
189 mGradient.setColor2( color );
197 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
199 mStops[mSelectedStop - 1].offset = offset;
200 mGradient.setStops( mStops );
208 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
210 mStops[mSelectedStop - 1].setColorSpec( spec );
211 mGradient.setStops( mStops );
215 else if ( mSelectedStop == mGradient.count() - 1 )
217 mGradient.setColorSpec( spec );
225 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
227 mStops[mSelectedStop - 1].setDirection( direction );
228 mGradient.setStops( mStops );
232 else if ( mSelectedStop == mGradient.count() - 1 )
234 mGradient.setDirection( direction );
242 if ( mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1 )
244 mStops[mSelectedStop - 1].color = color;
245 mStops[mSelectedStop - 1].offset = offset;
246 mGradient.setStops( mStops );
248 else if ( mSelectedStop == 0 )
250 mGradient.setColor1( color );
254 mGradient.setColor2( color );
263 if ( selectedStopIsMovable() )
266 double stopOffset = mStops.at( mSelectedStop - 1 ).offset;
267 mStops.removeAt( mSelectedStop - 1 );
268 mGradient.setStops( mStops );
270 int closest = findClosestStop( relativePositionToPoint( stopOffset ) );
280 mGradient.setColor1( color );
287 mGradient.setColor2( color );
294 if ( e->buttons() & Qt::LeftButton )
296 if ( selectedStopIsMovable() )
298 double offset = pointToRelativePosition( e->pos().x() );
302 mStops[mSelectedStop - 1].offset = offset;
304 mGradient.setStops( mStops );
312int QgsGradientStopEditor::findClosestStop(
int x,
int threshold )
const
314 int closestStop = -1;
315 int closestDiff = std::numeric_limits<int>::max();
316 int currentDiff = std::numeric_limits<int>::max();
322 const auto constStops = mGradient.
stops();
325 currentDiff = std::abs( relativePositionToPoint( stop.offset ) + 1 - x );
326 if ( ( threshold < 0 || currentDiff < threshold ) && currentDiff < closestDiff )
329 closestDiff = currentDiff;
335 currentDiff = std::abs( relativePositionToPoint( 0.0 ) + 1 - x );
336 if ( ( threshold < 0 || currentDiff < threshold ) && currentDiff < closestDiff )
339 closestDiff = currentDiff;
343 currentDiff = std::abs( relativePositionToPoint( 1.0 ) + 1 - x );
344 if ( ( threshold < 0 || currentDiff < threshold ) && currentDiff < closestDiff )
346 closestStop = mGradient.count() - 1;
354 if ( e->pos().y() >= rect().height() - MARGIN_BOTTOM - 1 )
357 int closestStop = findClosestStop( e->pos().x(), CLICK_THRESHOLD );
358 if ( closestStop >= 0 )
369 if ( e->buttons() & Qt::LeftButton )
372 double offset = pointToRelativePosition( e->pos().x() );
374 mSelectedStop = mStops.length();
375 mGradient.setStops( mStops );
384 if ( ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ) )
390 else if ( e->key() == Qt::Key_Left || e->key() == Qt::Key_Right )
392 if ( selectedStopIsMovable() )
395 double offsetDiff = pointToRelativePosition( rect().x() + MARGIN_X + FRAME_MARGIN_PX + 2 ) - pointToRelativePosition( rect().x() + MARGIN_X + FRAME_MARGIN_PX + 1 );
397 if ( e->modifiers() & Qt::ShiftModifier )
400 if ( e->key() == Qt::Key_Left )
403 mStops[mSelectedStop - 1].offset = std::clamp( mStops[mSelectedStop - 1].offset + offsetDiff, 0.0, 1.0 );
404 mGradient.setStops( mStops );
412 QWidget::keyPressEvent( e );
415QPixmap QgsGradientStopEditor::transparentBackground()
417 static QPixmap sTranspBkgrd;
419 if ( sTranspBkgrd.isNull() )
425void QgsGradientStopEditor::drawStopMarker( QPainter &painter, QPoint topMiddle,
const QColor &color,
bool selected )
427 QgsScopedQPainterState painterState( &painter );
428 painter.setRenderHint( QPainter::Antialiasing );
429 painter.setBrush( selected ? QColor( 150, 150, 150 ) : Qt::white );
430 painter.setPen( selected ? Qt::black : QColor( 150, 150, 150 ) );
432 painter.translate( std::round( topMiddle.x() - MARKER_WIDTH / 2.0 ) + 0.5, topMiddle.y() + 0.5 );
433 painter.drawPolygon( sOuterTriangle );
436 painter.setBrush( QBrush( transparentBackground() ) );
437 painter.setPen( Qt::NoPen );
438 painter.drawPolygon( sInnerTriangle );
441 painter.setBrush( color );
442 painter.drawPolygon( sInnerTriangle );
445double QgsGradientStopEditor::pointToRelativePosition(
int x )
const
447 int left = rect().x() + MARGIN_X + FRAME_MARGIN_PX;
448 int right = left + rect().width() - 2 * MARGIN_X - 2 * FRAME_MARGIN_PX;
452 else if ( x >= right )
455 return static_cast<double>( x - left ) / ( right - left );
458int QgsGradientStopEditor::relativePositionToPoint(
double position )
const
460 int left = rect().x() + MARGIN_X + FRAME_MARGIN_PX;
461 int right = left + rect().width() - 2 * MARGIN_X - 2 * FRAME_MARGIN_PX;
465 else if ( position >= 1.0 )
468 return left + ( right - left ) * position;
471bool QgsGradientStopEditor::selectedStopIsMovable()
const
474 return mSelectedStop > 0 && mSelectedStop < mGradient.count() - 1;
484 if ( mimeColor.isValid() )
487 e->acceptProposedAction();
494 bool hasAlpha =
false;
497 if ( mimeColor.isValid() )
500 e->acceptProposedAction();
503 double offset = pointToRelativePosition( e->pos().x() );
505 mSelectedStop = mStops.length();
506 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.