21 #include <QStyleOptionFrameV3>
22 #include <QMouseEvent>
24 #define MARKER_WIDTH 11
25 #define MARKER_HEIGHT 14
26 #define MARKER_GAP 1.5
27 #define MARGIN_BOTTOM ( MARKER_HEIGHT + 2 )
28 #define MARGIN_X ( MARKER_WIDTH / 2 )
29 #define FRAME_MARGIN 2
30 #define CLICK_THRESHOLD ( MARKER_WIDTH / 2 + 3 )
37 mStops = mGradient.
stops();
39 if ( sOuterTriangle.isEmpty() )
47 if ( sInnerTriangle.isEmpty() )
56 setFocusPolicy( Qt::StrongFocus );
57 setAcceptDrops(
true );
63 mStops = mGradient.
stops();
72 return QSize( 200, 80 );
78 QPainter painter(
this );
80 QRect frameRect( rect().x() +
MARGIN_X, rect().y(),
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 );
110 painter.drawRect( box );
113 for (
int i = 0; i < box.width() + 1; ++i )
115 QPen pen( mGradient.
color(
static_cast< double >( i ) / box.width() ) );
116 painter.setPen( pen );
117 painter.drawLine( box.left() + i, box.top(), box.left() + i, box.height() + 1 );
121 int markerTop = frameRect.bottom() + 1;
122 drawStopMarker( painter, QPoint( box.left(), markerTop ), mGradient.
color1(), mSelectedStop == 0 );
123 drawStopMarker( painter, QPoint( box.right(), markerTop ), mGradient.
color2(), mSelectedStop == mGradient.
count() - 1 );
125 const auto constMStops = mStops;
128 int x = stop.offset * box.width() + box.left();
129 drawStopMarker( painter, QPoint( x, markerTop ), stop.color, mSelectedStop == i );
138 if ( index > 0 && index < mGradient.
count() - 1 )
143 const auto constMStops = mStops;
154 mSelectedStop = index;
161 if ( mSelectedStop > 0 && mSelectedStop < mGradient.
count() - 1 )
163 return mStops.at( mSelectedStop - 1 );
165 else if ( mSelectedStop == 0 )
177 if ( mSelectedStop > 0 && mSelectedStop < mGradient.
count() - 1 )
179 mStops[ mSelectedStop - 1 ].color = color;
182 else if ( mSelectedStop == 0 )
196 if ( mSelectedStop > 0 && mSelectedStop < mGradient.
count() - 1 )
198 mStops[ mSelectedStop - 1 ].offset = offset;
207 if ( mSelectedStop > 0 && mSelectedStop < mGradient.
count() - 1 )
209 mStops[ mSelectedStop - 1 ].color = color;
210 mStops[ mSelectedStop - 1 ].offset = offset;
213 else if ( mSelectedStop == 0 )
228 if ( selectedStopIsMovable() )
231 double stopOffset = mStops.at( mSelectedStop - 1 ).offset;
232 mStops.removeAt( mSelectedStop - 1 );
235 int closest = findClosestStop( relativePositionToPoint( stopOffset ) );
259 if ( e->buttons() & Qt::LeftButton )
261 if ( selectedStopIsMovable() )
263 double offset = pointToRelativePosition( e->pos().x() );
267 mStops[ mSelectedStop - 1 ].offset = offset;
277 int QgsGradientStopEditor::findClosestStop(
int x,
int threshold )
const
279 int closestStop = -1;
280 int closestDiff = std::numeric_limits<int>::max();
281 int currentDiff = std::numeric_limits<int>::max();
287 const auto constStops = mGradient.
stops();
290 currentDiff = std::abs( relativePositionToPoint( stop.offset ) + 1 - x );
291 if ( ( threshold < 0 || currentDiff < threshold ) && currentDiff < closestDiff )
294 closestDiff = currentDiff;
300 currentDiff = std::abs( relativePositionToPoint( 0.0 ) + 1 - x );
301 if ( ( threshold < 0 || currentDiff < threshold ) && currentDiff < closestDiff )
304 closestDiff = currentDiff;
308 currentDiff = std::abs( relativePositionToPoint( 1.0 ) + 1 - x );
309 if ( ( threshold < 0 || currentDiff < threshold ) && currentDiff < closestDiff )
311 closestStop = mGradient.
count() - 1;
323 if ( closestStop >= 0 )
334 if ( e->buttons() & Qt::LeftButton )
337 double offset = pointToRelativePosition( e->pos().x() );
339 mSelectedStop = mStops.length();
349 if ( ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ) )
355 else if ( e->key() == Qt::Key_Left || e->key() == Qt::Key_Right )
357 if ( selectedStopIsMovable() )
362 if ( e->modifiers() & Qt::ShiftModifier )
365 if ( e->key() == Qt::Key_Left )
368 mStops[ mSelectedStop - 1 ].offset = std::clamp( mStops[ mSelectedStop - 1 ].offset + offsetDiff, 0.0, 1.0 );
377 QWidget::keyPressEvent( e );
380 QPixmap QgsGradientStopEditor::transparentBackground()
382 static QPixmap sTranspBkgrd;
384 if ( sTranspBkgrd.isNull() )
390 void QgsGradientStopEditor::drawStopMarker( QPainter &painter, QPoint topMiddle,
const QColor &color,
bool selected )
393 painter.setRenderHint( QPainter::Antialiasing );
394 painter.setBrush( selected ? QColor( 150, 150, 150 ) : Qt::white );
395 painter.setPen( selected ? Qt::black : QColor( 150, 150, 150 ) );
397 painter.translate( std::round( topMiddle.x() -
MARKER_WIDTH / 2.0 ) + 0.5, topMiddle.y() + 0.5 );
398 painter.drawPolygon( sOuterTriangle );
401 painter.setBrush( QBrush( transparentBackground() ) );
402 painter.setPen( Qt::NoPen );
403 painter.drawPolygon( sInnerTriangle );
406 painter.setBrush( color );
407 painter.drawPolygon( sInnerTriangle );
410 double QgsGradientStopEditor::pointToRelativePosition(
int x )
const
417 else if ( x >= right )
420 return static_cast< double >( x - left ) / ( right - left );
423 int QgsGradientStopEditor::relativePositionToPoint(
double position )
const
430 else if ( position >= 1.0 )
433 return left + ( right - left ) * position;
436 bool QgsGradientStopEditor::selectedStopIsMovable()
const
439 return mSelectedStop > 0 && mSelectedStop < mGradient.
count() - 1;
449 if ( mimeColor.isValid() )
452 e->acceptProposedAction();
459 bool hasAlpha =
false;
462 if ( mimeColor.isValid() )
465 e->acceptProposedAction();
468 double offset = pointToRelativePosition( e->pos().x() );
470 mSelectedStop = mStops.length();
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 ...
void setColor1(const QColor &color)
Sets the gradient start color.
void setColor2(const QColor &color)
Sets the gradient end color.
int count() const override
Returns number of defined colors, or -1 if undefined.
QColor color(double value) const override
Returns the color corresponding to a specified value.
void setStops(const QgsGradientStopsList &stops)
Sets the list of intermediate gradient stops for the ramp.
QColor color1() const
Returns the gradient start color.
QgsGradientStopsList stops() const
Returns the list of intermediate gradient stops for the ramp.
QColor color2() const
Returns the gradient end color.
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
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 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.
Scoped object for saving and restoring a QPainter object's state.
static QColor colorFromMimeData(const QMimeData *data, bool &hasAlpha)
Attempts to parse mime data as a color.