File indexing completed on 2024-12-22 04:13:07
0001 /* 0002 * SPDX-FileCopyrightText: 2004 Cyrille Berger <cberger@cberger.net> 0003 * SPDX-FileCopyrightText: 2004 Sven Langkamp <sven.langkamp@gmail.com> 0004 * SPDX-FileCopyrightText: 2021 Deif Lou <ginoba@gmail.com> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include <QPainter> 0010 #include <QContextMenuEvent> 0011 #include <QPixmap> 0012 #include <QMouseEvent> 0013 #include <QPolygon> 0014 #include <QPaintEvent> 0015 #include <QMenu> 0016 #include <QStyleOptionToolButton> 0017 #include <QWindow> 0018 #include <QAction> 0019 #include <QColorDialog> 0020 0021 #include <kis_debug.h> 0022 #include <klocalizedstring.h> 0023 #include <resources/KoSegmentGradient.h> 0024 #include <KisGradientWidgetsUtils.h> 0025 #include <KisDlgInternalColorSelector.h> 0026 #include <krita_utils.h> 0027 #include <kconfiggroup.h> 0028 #include <ksharedconfig.h> 0029 0030 #include "KisSegmentGradientSlider.h" 0031 0032 #define MARGIN 5 0033 #define HANDLE_SIZE 10 0034 0035 KisSegmentGradientSlider::KisSegmentGradientSlider(QWidget *parent, const char* name, Qt::WindowFlags f) 0036 : QWidget(parent, f) 0037 , m_drag(false) 0038 , m_updateCompressor(40, KisSignalCompressor::FIRST_ACTIVE) 0039 { 0040 setObjectName(name); 0041 setMouseTracking(true); 0042 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); 0043 setFocusPolicy(Qt::WheelFocus); 0044 0045 connect(this, SIGNAL(updateRequested()), &m_updateCompressor, SLOT(start())); 0046 connect(&m_updateCompressor, SIGNAL(timeout()), this, SLOT(update())); 0047 0048 QWindow *window = this->window()->windowHandle(); 0049 if (window) { 0050 connect(window, SIGNAL(screenChanged(QScreen*)), SLOT(updateHandleSize())); 0051 } 0052 updateHandleSize(); 0053 } 0054 0055 void KisSegmentGradientSlider::setGradientResource(KoSegmentGradientSP agr) 0056 { 0057 m_gradient = agr; 0058 m_selectedHandle = { HandleType_Stop, 0 }; 0059 emit selectedHandleChanged(); 0060 emit updateRequested(); 0061 } 0062 0063 void KisSegmentGradientSlider::paintEvent(QPaintEvent*) 0064 { 0065 QPainter painter(this); 0066 0067 const QRect previewRect = gradientStripeRect(); 0068 0069 if (m_gradient) { 0070 // Gradient 0071 KisGradientWidgetsUtils::paintGradientBox(painter, m_gradient, previewRect); 0072 // Handles 0073 QList<KoGradientSegment*> segments = m_gradient->segments(); 0074 painter.setRenderHint(QPainter::Antialiasing, true); 0075 const QRect handlesRect = this->handlesStripeRect(); 0076 const bool hasFocus = this->hasFocus(); 0077 // Segment handles 0078 if (m_selectedHandle.type == HandleType_Segment) { 0079 const KoGradientSegment *selectedSegment = segments[m_selectedHandle.index]; 0080 QRectF segmentHandleRect = 0081 handlesRect.adjusted( 0082 selectedSegment->startOffset() * handlesRect.width(), 0083 -1, 0084 -(handlesRect.width() - selectedSegment->endOffset() * handlesRect.width()), 0085 -4 0086 ); 0087 painter.fillRect(segmentHandleRect, palette().highlight()); 0088 } 0089 if (m_hoveredHandle.type == HandleType_Segment && 0090 (m_selectedHandle.type != HandleType_Segment || m_hoveredHandle.index != m_selectedHandle.index)) { 0091 const KoGradientSegment *hoveredSegment = segments[m_hoveredHandle.index]; 0092 QRectF segmentHandleRect = 0093 handlesRect.adjusted( 0094 hoveredSegment->startOffset() * handlesRect.width(), 0095 -1, 0096 -(handlesRect.width() - hoveredSegment->endOffset() * handlesRect.width()), 0097 -4 0098 ); 0099 QColor c = palette().highlight().color(); 0100 c.setAlpha(96); 0101 painter.fillRect(segmentHandleRect, c); 0102 } 0103 // Mid-Point handles 0104 const qreal midPointHandleSize = m_handleSize.height() * 0.5; 0105 const qreal midPointHandleOffsetY = (handlesRect.height() - 5.0 - midPointHandleSize) * 0.5; 0106 for (int i = 0; i < segments.count(); i++) { 0107 if (m_selectedHandle.type == HandleType_MidPoint && m_selectedHandle.index == i) { 0108 // If this handle is selected then we will paint it later 0109 // on top of everything else 0110 continue; 0111 } 0112 QPointF handlePos = 0113 handlesRect.topLeft() + 0114 QPointF(segments[i]->middleOffset() * handlesRect.width(), midPointHandleOffsetY); 0115 KisGradientWidgetsUtils::paintMidPointHandle( 0116 painter, handlePos, midPointHandleSize, 0117 false, m_hoveredHandle.type == HandleType_MidPoint && m_hoveredHandle.index == i, hasFocus, 0118 palette().windowText().color(), palette().window().color(), palette().highlight().color() 0119 ); 0120 } 0121 // Stop handles 0122 const QColor highlightColor = palette().color(QPalette::Highlight); 0123 // First stop if it is not selected, in which case it will be painted 0124 // later on top of everything else 0125 if (m_selectedHandle.type != HandleType_Stop || m_selectedHandle.index != 0) { 0126 KoGradientSegment* segment = segments.front(); 0127 KisGradientWidgetsUtils::ColorType colorType = KisGradientWidgetsUtils::segmentEndPointTypeToColorType(segment->startType()); 0128 // Pass the color info as color 2 so that the type indicator is 0129 // shown on the right side of the handle for this stop 0130 KisGradientWidgetsUtils::paintStopHandle( 0131 painter, 0132 QPointF(handlesRect.left() + segment->startOffset() * handlesRect.width(), handlesRect.top()), 0133 QSizeF(m_handleSize), 0134 false, m_hoveredHandle.type == HandleType_Stop && m_hoveredHandle.index == 0, hasFocus, 0135 highlightColor, 0136 {}, 0137 { colorType, segment->startColor().toQColor() } 0138 ); 0139 } 0140 // Middle stops 0141 if (segments.size() > 1) { 0142 for (int i = 0; i < segments.count() - 1; ++i) { 0143 if (m_selectedHandle.type == HandleType_Stop && m_selectedHandle.index == i + 1) { 0144 // If this handle is selected then we will paint it later 0145 // on top of everything else 0146 continue; 0147 } 0148 KoGradientSegment* currentSegment = segments[i]; 0149 KoGradientSegment* nextSegment = segments[i + 1]; 0150 // If the end point of the current segment and the start point 0151 // of the next segment have the same offset, that means the 0152 // segments touch each other, are connected (normal behavior), 0153 // so we paint a single special handle. 0154 // If the end points have different offsets then krita stills 0155 // considers the gradient valid (although Gimp doesn't) so we 0156 // paint two different handles. 0157 if (currentSegment->endOffset() == nextSegment->startOffset()) { 0158 KisGradientWidgetsUtils::paintStopHandle( 0159 painter, 0160 QPointF(handlesRect.left() + currentSegment->endOffset() * handlesRect.width(), handlesRect.top()), 0161 QSizeF(m_handleSize), 0162 false, m_hoveredHandle.type == HandleType_Stop && m_hoveredHandle.index == i + 1, hasFocus, 0163 highlightColor, 0164 { KisGradientWidgetsUtils::segmentEndPointTypeToColorType(currentSegment->endType()), currentSegment->endColor().toQColor() }, 0165 { KisGradientWidgetsUtils::segmentEndPointTypeToColorType(nextSegment->startType()), nextSegment->startColor().toQColor() } 0166 ); 0167 } else { 0168 KisGradientWidgetsUtils::paintStopHandle( 0169 painter, 0170 QPointF(handlesRect.left() + currentSegment->endOffset() * handlesRect.width(), handlesRect.top()), 0171 QSizeF(m_handleSize), 0172 false, m_hoveredHandle.type == HandleType_Stop && m_hoveredHandle.index == i + 1, hasFocus, 0173 highlightColor, 0174 { KisGradientWidgetsUtils::segmentEndPointTypeToColorType(currentSegment->endType()), currentSegment->endColor().toQColor() } 0175 ); 0176 KisGradientWidgetsUtils::paintStopHandle( 0177 painter, 0178 QPointF(handlesRect.left() + nextSegment->startOffset() * handlesRect.width(), handlesRect.top()), 0179 QSizeF(m_handleSize), 0180 false, m_hoveredHandle.type == HandleType_Stop && m_hoveredHandle.index == i + 1, hasFocus, 0181 highlightColor, 0182 { KisGradientWidgetsUtils::segmentEndPointTypeToColorType(nextSegment->startType()), nextSegment->startColor().toQColor() } 0183 ); 0184 } 0185 } 0186 } 0187 // Last stop. This is the last thing to be painted before the selected 0188 // handle, so we don't need to make a special case here 0189 { 0190 KoGradientSegment* segment = segments.back(); 0191 KisGradientWidgetsUtils::ColorType colorType = KisGradientWidgetsUtils::segmentEndPointTypeToColorType(segment->endType()); 0192 KisGradientWidgetsUtils::paintStopHandle( 0193 painter, 0194 QPointF(handlesRect.left() + segment->endOffset() * handlesRect.width(), handlesRect.top()), 0195 QSizeF(m_handleSize), 0196 m_selectedHandle.type == HandleType_Stop && m_selectedHandle.index == segments.size(), 0197 m_hoveredHandle.type == HandleType_Stop && m_hoveredHandle.index == segments.size() && 0198 (m_selectedHandle.type != HandleType_Stop || m_selectedHandle.index != segments.size()), 0199 hasFocus, 0200 highlightColor, 0201 { colorType, segment->endColor().toQColor() } 0202 ); 0203 } 0204 // Selected stop 0205 if (m_selectedHandle.type == HandleType_MidPoint) { 0206 QPointF handlePos = 0207 handlesRect.topLeft() + 0208 QPointF(segments[m_selectedHandle.index]->middleOffset() * handlesRect.width(), midPointHandleOffsetY); 0209 KisGradientWidgetsUtils::paintMidPointHandle( 0210 painter, handlePos, midPointHandleSize, 0211 true, false, hasFocus, 0212 palette().windowText().color(), palette().window().color(), palette().highlight().color() 0213 ); 0214 } else if (m_selectedHandle.type == HandleType_Stop) { 0215 if (m_selectedHandle.index == 0) { 0216 KoGradientSegment* segment = segments.front(); 0217 KisGradientWidgetsUtils::ColorType colorType = KisGradientWidgetsUtils::segmentEndPointTypeToColorType(segment->startType()); 0218 // Pass the color info as color 2 so that the type indicator is 0219 // shown on the right side of the handle for this stop 0220 KisGradientWidgetsUtils::paintStopHandle( 0221 painter, 0222 QPointF(handlesRect.left() + segment->startOffset() * handlesRect.width(), handlesRect.top()), 0223 QSizeF(m_handleSize), 0224 true, false, hasFocus, 0225 highlightColor, 0226 {}, 0227 { colorType, segment->startColor().toQColor() } 0228 ); 0229 } else if (m_selectedHandle.index < segments.size()) { 0230 KoGradientSegment* currentSegment = segments[m_selectedHandle.index - 1]; 0231 KoGradientSegment* nextSegment = segments[m_selectedHandle.index]; 0232 if (currentSegment->endOffset() == nextSegment->startOffset()) { 0233 KisGradientWidgetsUtils::paintStopHandle( 0234 painter, 0235 QPointF(handlesRect.left() + currentSegment->endOffset() * handlesRect.width(), handlesRect.top()), 0236 QSizeF(m_handleSize), 0237 true, false, hasFocus, 0238 highlightColor, 0239 { KisGradientWidgetsUtils::segmentEndPointTypeToColorType(currentSegment->endType()), currentSegment->endColor().toQColor() }, 0240 { KisGradientWidgetsUtils::segmentEndPointTypeToColorType(nextSegment->startType()), nextSegment->startColor().toQColor() } 0241 ); 0242 } else { 0243 KisGradientWidgetsUtils::paintStopHandle( 0244 painter, 0245 QPointF(handlesRect.left() + currentSegment->endOffset() * handlesRect.width(), handlesRect.top()), 0246 QSizeF(m_handleSize), 0247 true, false, hasFocus, 0248 highlightColor, 0249 { KisGradientWidgetsUtils::segmentEndPointTypeToColorType(currentSegment->endType()), currentSegment->endColor().toQColor() } 0250 ); 0251 KisGradientWidgetsUtils::paintStopHandle( 0252 painter, 0253 QPointF(handlesRect.left() + nextSegment->startOffset() * handlesRect.width(), handlesRect.top()), 0254 QSizeF(m_handleSize), 0255 true, false, hasFocus, 0256 highlightColor, 0257 { KisGradientWidgetsUtils::segmentEndPointTypeToColorType(nextSegment->startType()), nextSegment->startColor().toQColor() } 0258 ); 0259 } 0260 } 0261 } 0262 } else { 0263 painter.setPen(palette().color(QPalette::Mid)); 0264 painter.drawRect(previewRect); 0265 } 0266 } 0267 0268 void KisSegmentGradientSlider::mousePressEvent(QMouseEvent * e) 0269 { 0270 if (e->button() != Qt::LeftButton) { 0271 QWidget::mousePressEvent(e); 0272 return; 0273 } 0274 0275 const QRect rect = sliderRect(); 0276 const QRect handlesRect = handlesStripeRect(); 0277 0278 // Find segment under cursor 0279 Handle selectedHandle; 0280 const qreal t = (e->x() - rect.left()) / static_cast<qreal>(rect.width()); 0281 const qreal handleClickTolerance = m_handleSize.width() / static_cast<qreal>(rect.width()); 0282 m_dragT = t; 0283 0284 for (int i = 0; i < m_gradient->segments().size(); ++i) { 0285 KoGradientSegment *segment = m_gradient->segments()[i]; 0286 // Check if a knob was pressed 0287 if (qAbs(t - segment->startOffset()) <= handleClickTolerance && e->pos().y() >= handlesRect.y()) { 0288 // Left knob was pressed 0289 selectedHandle.type = HandleType_Stop; 0290 selectedHandle.index = i; 0291 m_drag = true; 0292 break; 0293 } else if (qAbs(t - segment->endOffset()) <= handleClickTolerance && e->pos().y() >= handlesRect.y()) { 0294 // Right knob was pressed 0295 selectedHandle.type = HandleType_Stop; 0296 selectedHandle.index = i + 1; 0297 m_drag = true; 0298 break; 0299 } else if (qAbs(t - segment->middleOffset()) <= handleClickTolerance && e->pos().y() >= handlesRect.y()) { 0300 // middle knob was pressed 0301 selectedHandle.type = HandleType_MidPoint; 0302 selectedHandle.index = i; 0303 m_drag = true; 0304 break; 0305 } else if (t >= segment->startOffset() && t <= segment->endOffset()) { 0306 // the segment area was pressed 0307 selectedHandle.type = HandleType_Segment; 0308 selectedHandle.index = i; 0309 if (e->modifiers() & Qt::ControlModifier) { 0310 KoColor color; 0311 m_gradient->colorAt(color, t); 0312 m_selectedHandle = selectedHandle; 0313 segment->setMiddleOffset(t); 0314 m_gradient->splitSegment(segment); 0315 m_selectedHandle.type = HandleType_Stop; 0316 m_selectedHandle.index = i + 1; 0317 m_gradient->segments()[i]->setEndColor(color); 0318 m_gradient->segments()[i + 1]->setStartColor(color); 0319 m_drag = true; 0320 emit selectedHandleChanged(); 0321 emit updateRequested(); 0322 return; 0323 } else if (e->modifiers() & Qt::ShiftModifier) { 0324 m_selectedHandle = selectedHandle; 0325 duplicateSelectedSegment(); 0326 return; 0327 } 0328 m_drag = true; 0329 m_relativeDragOffset = t - segment->startOffset(); 0330 break; 0331 } 0332 } 0333 0334 if (m_drag) { 0335 m_hoveredHandle = {}; 0336 } 0337 0338 if (m_selectedHandle.type != selectedHandle.type || m_selectedHandle.index != selectedHandle.index) { 0339 m_selectedHandle = selectedHandle; 0340 emit selectedHandleChanged(); 0341 emit updateRequested(); 0342 } 0343 } 0344 0345 void KisSegmentGradientSlider::mouseReleaseEvent(QMouseEvent * e) 0346 { 0347 Q_UNUSED(e); 0348 m_temporallyDeletedHandleInfo.handle.type = HandleType_None; 0349 m_drag = false; 0350 } 0351 0352 void KisSegmentGradientSlider::mouseMoveEvent(QMouseEvent * e) 0353 { 0354 const QRect rect = sliderRect(); 0355 const qreal t = (e->x() - rect.left()) / static_cast<qreal>(rect.width()); 0356 0357 if (m_drag) { 0358 if (!(e->buttons() & Qt::LeftButton)) { 0359 QWidget::mouseMoveEvent(e); 0360 return; 0361 } 0362 const QRect augmentedRect = kisGrowRect(this->rect(), removeStopDistance); 0363 if (m_temporallyDeletedHandleInfo.handle.type == HandleType_Segment) { 0364 if (augmentedRect.contains(e->pos())) { 0365 m_gradient->duplicateSegment(m_gradient->segments()[m_temporallyDeletedHandleInfo.handle.index - 1]); 0366 KoGradientSegment *segment = m_gradient->segments()[m_temporallyDeletedHandleInfo.handle.index]; 0367 segment->setStartType(m_temporallyDeletedHandleInfo.leftEndPointType); 0368 segment->setStartOffset(m_temporallyDeletedHandleInfo.leftEndPointOffset); 0369 segment->setStartColor(m_temporallyDeletedHandleInfo.leftEndPointColor); 0370 segment->setEndType(m_temporallyDeletedHandleInfo.rightEndPointType); 0371 segment->setEndOffset(m_temporallyDeletedHandleInfo.rightEndPointOffset); 0372 segment->setEndColor(m_temporallyDeletedHandleInfo.rightEndPointColor); 0373 segment->setMiddleOffset(m_temporallyDeletedHandleInfo.leftMiddleOffset); 0374 segment->setInterpolation(m_temporallyDeletedHandleInfo.leftInterpolationType); 0375 segment->setColorInterpolation(m_temporallyDeletedHandleInfo.leftColorInterpolationType); 0376 m_selectedHandle.type = HandleType_Segment; 0377 m_selectedHandle.index = m_temporallyDeletedHandleInfo.handle.index; 0378 m_temporallyDeletedHandleInfo.handle.type = HandleType_None; 0379 } 0380 } else if (m_temporallyDeletedHandleInfo.handle.type == HandleType_Stop) { 0381 if (augmentedRect.contains(e->pos())) { 0382 m_gradient->duplicateSegment(m_gradient->segments()[m_temporallyDeletedHandleInfo.handle.index - 1]); 0383 KoGradientSegment *previousSegment = m_gradient->segments()[m_temporallyDeletedHandleInfo.handle.index - 1]; 0384 KoGradientSegment *nextSegment = m_gradient->segments()[m_temporallyDeletedHandleInfo.handle.index]; 0385 previousSegment->setEndType(m_temporallyDeletedHandleInfo.leftEndPointType); 0386 previousSegment->setEndColor(m_temporallyDeletedHandleInfo.leftEndPointColor); 0387 previousSegment->setInterpolation(m_temporallyDeletedHandleInfo.leftInterpolationType); 0388 previousSegment->setColorInterpolation(m_temporallyDeletedHandleInfo.leftColorInterpolationType); 0389 previousSegment->setMiddleOffset( 0390 previousSegment->startOffset() + 0391 (m_temporallyDeletedHandleInfo.leftMiddleOffset - previousSegment->startOffset()) / 0392 (m_temporallyDeletedHandleInfo.leftEndPointOffset - previousSegment->startOffset()) * 0393 previousSegment->length() 0394 ); 0395 nextSegment->setStartType(m_temporallyDeletedHandleInfo.rightEndPointType); 0396 nextSegment->setStartColor(m_temporallyDeletedHandleInfo.rightEndPointColor); 0397 nextSegment->setInterpolation(m_temporallyDeletedHandleInfo.rightInterpolationType); 0398 nextSegment->setColorInterpolation(m_temporallyDeletedHandleInfo.rightColorInterpolationType); 0399 nextSegment->setMiddleOffset( 0400 nextSegment->startOffset() + 0401 (m_temporallyDeletedHandleInfo.rightMiddleOffset - m_temporallyDeletedHandleInfo.rightEndPointOffset) / 0402 (nextSegment->endOffset() - m_temporallyDeletedHandleInfo.rightEndPointOffset) * 0403 nextSegment->length() 0404 ); 0405 m_selectedHandle.type = HandleType_Stop; 0406 m_selectedHandle.index = m_temporallyDeletedHandleInfo.handle.index; 0407 m_temporallyDeletedHandleInfo.handle.type = HandleType_None; 0408 } 0409 } 0410 0411 if (m_selectedHandle.type == HandleType_Segment) { 0412 if (m_temporallyDeletedHandleInfo.handle.type == HandleType_None) { 0413 KoGradientSegment *segment = m_gradient->segments()[m_selectedHandle.index]; 0414 if (m_gradient->segments().size() > 1 && m_selectedHandle.index > 0 && m_selectedHandle.index < m_gradient->segments().size() - 1 && 0415 !augmentedRect.contains(e->pos())) { 0416 m_temporallyDeletedHandleInfo.handle.type = HandleType_Segment; 0417 m_temporallyDeletedHandleInfo.handle.index = m_selectedHandle.index; 0418 m_temporallyDeletedHandleInfo.leftEndPointType = segment->startType(); 0419 m_temporallyDeletedHandleInfo.leftEndPointOffset = segment->startOffset(); 0420 m_temporallyDeletedHandleInfo.leftEndPointColor = segment->startColor(); 0421 m_temporallyDeletedHandleInfo.rightEndPointType = segment->endType(); 0422 m_temporallyDeletedHandleInfo.rightEndPointOffset = segment->endOffset(); 0423 m_temporallyDeletedHandleInfo.rightEndPointColor = segment->endColor(); 0424 m_temporallyDeletedHandleInfo.leftInterpolationType = segment->interpolation(); 0425 m_temporallyDeletedHandleInfo.leftColorInterpolationType = segment->colorInterpolation(); 0426 m_temporallyDeletedHandleInfo.leftMiddleOffset = segment->middleOffset(); 0427 m_gradient->collapseSegment(m_gradient->segments()[m_selectedHandle.index]); 0428 m_selectedHandle.type = HandleType_None; 0429 } else { 0430 KoGradientSegment *segment = m_gradient->segments()[m_selectedHandle.index]; 0431 KoGradientSegment *previousSegment = m_selectedHandle.index == 0 ? nullptr : m_gradient->segments()[m_selectedHandle.index - 1]; 0432 KoGradientSegment *nextSegment = m_selectedHandle.index == m_gradient->segments().size() - 1 ? nullptr : m_gradient->segments()[m_selectedHandle.index + 1]; 0433 if (previousSegment && nextSegment) { 0434 const qreal midPointRelativePos = segment->middleOffset() - segment->startOffset(); 0435 const qreal previousMidPointLocalPos = 0436 previousSegment->length() > std::numeric_limits<qreal>::epsilon() 0437 ? (previousSegment->middleOffset() - previousSegment->startOffset()) / previousSegment->length() 0438 : 0.0; 0439 const qreal nextMidPointLocalPos = 0440 nextSegment->length() > std::numeric_limits<qreal>::epsilon() 0441 ? (nextSegment->middleOffset() - nextSegment->startOffset()) / nextSegment->length() 0442 : 0.0; 0443 qreal newStartOffset, newEndOffset; 0444 if (t < m_dragT) { 0445 newStartOffset = qMax(t - m_relativeDragOffset, previousSegment->startOffset() + shrinkEpsilon); 0446 newEndOffset = newStartOffset + segment->length(); 0447 } else { 0448 newEndOffset = qMin(t + (segment->length() - m_relativeDragOffset), nextSegment->endOffset() - shrinkEpsilon); 0449 newStartOffset = newEndOffset - segment->length(); 0450 } 0451 previousSegment->setEndOffset(newStartOffset); 0452 segment->setStartOffset(newStartOffset); 0453 segment->setEndOffset(newEndOffset); 0454 nextSegment->setStartOffset(newEndOffset); 0455 previousSegment->setMiddleOffset( 0456 previousSegment->startOffset() + 0457 previousMidPointLocalPos * previousSegment->length() 0458 ); 0459 nextSegment->setMiddleOffset( 0460 nextSegment->startOffset() + 0461 nextMidPointLocalPos * nextSegment->length() 0462 ); 0463 segment->setMiddleOffset(segment->startOffset() + midPointRelativePos); 0464 } else { 0465 if (!previousSegment) { 0466 segment->setStartOffset(0.0); 0467 } 0468 if (!nextSegment) { 0469 segment->setEndOffset(1.0); 0470 } 0471 } 0472 } 0473 emit selectedHandleChanged(); 0474 emit updateRequested(); 0475 } 0476 0477 } else if (m_selectedHandle.type == HandleType_Stop) { 0478 if (m_temporallyDeletedHandleInfo.handle.type == HandleType_None) { 0479 KoGradientSegment *previousSegment = m_selectedHandle.index == 0 ? nullptr : m_gradient->segments()[m_selectedHandle.index - 1]; 0480 KoGradientSegment *nextSegment = m_selectedHandle.index == m_gradient->segments().size() ? nullptr : m_gradient->segments()[m_selectedHandle.index]; 0481 if (m_gradient->segments().size() > 1 && m_selectedHandle.index > 0 && m_selectedHandle.index < m_gradient->segments().size() && 0482 !augmentedRect.contains(e->pos())) { 0483 m_temporallyDeletedHandleInfo.handle.type = HandleType_Stop; 0484 m_temporallyDeletedHandleInfo.handle.index = m_selectedHandle.index; 0485 m_temporallyDeletedHandleInfo.leftEndPointType = previousSegment->endType(); 0486 m_temporallyDeletedHandleInfo.leftEndPointOffset = previousSegment->endOffset(); 0487 m_temporallyDeletedHandleInfo.leftEndPointColor = previousSegment->endColor(); 0488 m_temporallyDeletedHandleInfo.leftInterpolationType = previousSegment->interpolation(); 0489 m_temporallyDeletedHandleInfo.leftColorInterpolationType = previousSegment->colorInterpolation(); 0490 m_temporallyDeletedHandleInfo.leftMiddleOffset = previousSegment->middleOffset(); 0491 m_temporallyDeletedHandleInfo.rightEndPointType = nextSegment->startType(); 0492 m_temporallyDeletedHandleInfo.rightEndPointOffset = nextSegment->startOffset(); 0493 m_temporallyDeletedHandleInfo.rightEndPointColor = nextSegment->startColor(); 0494 m_temporallyDeletedHandleInfo.rightInterpolationType = nextSegment->interpolation(); 0495 m_temporallyDeletedHandleInfo.rightColorInterpolationType = nextSegment->colorInterpolation(); 0496 m_temporallyDeletedHandleInfo.rightMiddleOffset = nextSegment->middleOffset(); 0497 previousSegment->setEndType(nextSegment->endType()); 0498 previousSegment->setEndColor(nextSegment->endColor()); 0499 deleteHandleImpl(m_selectedHandle); 0500 m_selectedHandle.type = HandleType_None; 0501 } else { 0502 KoGradientSegment *previousSegment = m_selectedHandle.index == 0 ? nullptr : m_gradient->segments()[m_selectedHandle.index - 1]; 0503 KoGradientSegment *nextSegment = m_selectedHandle.index == m_gradient->segments().size() ? nullptr : m_gradient->segments()[m_selectedHandle.index]; 0504 if (previousSegment && nextSegment) { 0505 const qreal previousMidPointLocalPos = 0506 previousSegment->length() > std::numeric_limits<qreal>::epsilon() 0507 ? (previousSegment->middleOffset() - previousSegment->startOffset()) / previousSegment->length() 0508 : 0.0; 0509 const qreal nextMidPointLocalPos = 0510 nextSegment->length() > std::numeric_limits<qreal>::epsilon() 0511 ? (nextSegment->middleOffset() - nextSegment->startOffset()) / nextSegment->length() 0512 : 0.0; 0513 qreal newOffset; 0514 if (t < m_dragT) { 0515 newOffset = qMax(t, previousSegment->startOffset() + shrinkEpsilon); 0516 } else { 0517 newOffset = qMin(t, nextSegment->endOffset() - shrinkEpsilon); 0518 } 0519 previousSegment->setEndOffset(newOffset); 0520 nextSegment->setStartOffset(newOffset); 0521 previousSegment->setMiddleOffset( 0522 previousSegment->startOffset() + 0523 previousMidPointLocalPos * previousSegment->length() 0524 ); 0525 nextSegment->setMiddleOffset( 0526 nextSegment->startOffset() + 0527 nextMidPointLocalPos * nextSegment->length() 0528 ); 0529 } else { 0530 if (!previousSegment) { 0531 nextSegment->setStartOffset(0.0); 0532 } 0533 if (!nextSegment) { 0534 previousSegment->setEndOffset(1.0); 0535 } 0536 } 0537 } 0538 emit selectedHandleChanged(); 0539 emit updateRequested(); 0540 } 0541 0542 } else if (m_selectedHandle.type == HandleType_MidPoint) { 0543 KoGradientSegment *segment = m_gradient->segments()[m_selectedHandle.index]; 0544 segment->setMiddleOffset(qBound(segment->startOffset(), t, segment->endOffset())); 0545 emit selectedHandleChanged(); 0546 emit updateRequested(); 0547 } 0548 0549 } else { 0550 const QRect handlesRect = handlesStripeRect(); 0551 Handle hoveredHandle; 0552 const qreal handleClickTolerance = m_handleSize.width() / static_cast<qreal>(rect.width()); 0553 for (int i = 0; i < m_gradient->segments().size(); ++i) { 0554 KoGradientSegment *segment = m_gradient->segments()[i]; 0555 // Check if a knob was hovered 0556 if (qAbs(t - segment->startOffset()) <= handleClickTolerance && e->pos().y() >= handlesRect.y()) { 0557 // Left knob was hovered 0558 hoveredHandle.type = HandleType_Stop; 0559 hoveredHandle.index = i; 0560 break; 0561 } else if (qAbs(t - segment->endOffset()) <= handleClickTolerance && e->pos().y() >= handlesRect.y()) { 0562 // Right knob was hovered 0563 hoveredHandle.type = HandleType_Stop; 0564 hoveredHandle.index = i + 1; 0565 break; 0566 } else if (qAbs(t - segment->middleOffset()) <= handleClickTolerance && e->pos().y() >= handlesRect.y()) { 0567 // middle knob was hovered 0568 hoveredHandle.type = HandleType_MidPoint; 0569 hoveredHandle.index = i; 0570 break; 0571 } else if (t >= segment->startOffset() && t <= segment->endOffset()) { 0572 // the segment area was hovered 0573 hoveredHandle.type = HandleType_Segment; 0574 hoveredHandle.index = i; 0575 break; 0576 } 0577 } 0578 m_hoveredHandle = hoveredHandle; 0579 emit updateRequested(); 0580 } 0581 } 0582 0583 void KisSegmentGradientSlider::mouseDoubleClickEvent(QMouseEvent *e) 0584 { 0585 if (e->button() != Qt::LeftButton) { 0586 QWidget::mouseDoubleClickEvent(e); 0587 return; 0588 } 0589 0590 const QRect rect = sliderRect(); 0591 const QRect handlesRect = handlesStripeRect(); 0592 const qreal t = (e->x() - rect.left()) / static_cast<qreal>(rect.width()); 0593 const qreal handleClickTolerance = m_handleSize.width() / static_cast<qreal>(rect.width()); 0594 const KoGradientSegment *previousSegment = m_selectedHandle.index == 0 ? nullptr : m_gradient->segments()[m_selectedHandle.index - 1]; 0595 const KoGradientSegment *nextSegment = m_selectedHandle.index == m_gradient->segments().size() ? nullptr : m_gradient->segments()[m_selectedHandle.index]; 0596 0597 if ((previousSegment && qAbs(t - previousSegment->endOffset()) <= handleClickTolerance && e->pos().y() >= handlesRect.y()) || 0598 (nextSegment && qAbs(t - nextSegment->startOffset()) <= handleClickTolerance && e->pos().y() >= handlesRect.y())) { 0599 chooseSelectedStopColor(); 0600 } 0601 } 0602 0603 void KisSegmentGradientSlider::selectPreviousHandle() 0604 { 0605 if (m_selectedHandle.type == HandleType_Segment) { 0606 m_selectedHandle.type = HandleType_Stop; 0607 emit selectedHandleChanged(); 0608 emit updateRequested(); 0609 } else if (m_selectedHandle.type == HandleType_Stop) { 0610 if (m_selectedHandle.index > 0) { 0611 m_selectedHandle.type = HandleType_MidPoint; 0612 --m_selectedHandle.index; 0613 emit selectedHandleChanged(); 0614 emit updateRequested(); 0615 } 0616 } else if (m_selectedHandle.type == HandleType_MidPoint) { 0617 m_selectedHandle.type = HandleType_Segment; 0618 emit selectedHandleChanged(); 0619 emit updateRequested(); 0620 } 0621 } 0622 0623 void KisSegmentGradientSlider::selectNextHandle() 0624 { 0625 if (m_selectedHandle.type == HandleType_Segment) { 0626 m_selectedHandle.type = HandleType_MidPoint; 0627 emit selectedHandleChanged(); 0628 emit updateRequested(); 0629 } else if (m_selectedHandle.type == HandleType_Stop) { 0630 if (m_selectedHandle.index < m_gradient->segments().size()) { 0631 m_selectedHandle.type = HandleType_Segment; 0632 emit selectedHandleChanged(); 0633 emit updateRequested(); 0634 } 0635 } else if (m_selectedHandle.type == HandleType_MidPoint) { 0636 m_selectedHandle.type = HandleType_Stop; 0637 ++m_selectedHandle.index; 0638 emit selectedHandleChanged(); 0639 emit updateRequested(); 0640 } 0641 } 0642 0643 void KisSegmentGradientSlider::handleIncrementInput(int direction, Qt::KeyboardModifiers modifiers) 0644 { 0645 if (direction == 0) { 0646 return; 0647 } 0648 if (modifiers & Qt::ControlModifier) { 0649 if (direction < 0) { 0650 selectPreviousHandle(); 0651 } else { 0652 selectNextHandle(); 0653 } 0654 } else { 0655 const qreal increment = modifiers & Qt::ShiftModifier ? 0.001 : 0.01; 0656 moveSelectedHandle(direction < 0 ? -increment : increment); 0657 } 0658 } 0659 0660 void KisSegmentGradientSlider::wheelEvent(QWheelEvent *e) 0661 { 0662 if (e->angleDelta().y() != 0) { 0663 handleIncrementInput(e->angleDelta().y(), e->modifiers()); 0664 e->accept(); 0665 } else { 0666 QWidget::wheelEvent(e); 0667 } 0668 } 0669 0670 void KisSegmentGradientSlider::keyPressEvent(QKeyEvent *e) 0671 { 0672 switch (e->key()) { 0673 case Qt::Key_Left: 0674 handleIncrementInput(-1, e->modifiers()); 0675 break; 0676 case Qt::Key_Right: 0677 handleIncrementInput(1, e->modifiers()); 0678 break; 0679 case Qt::Key_Return: 0680 case Qt::Key_Enter: 0681 chooseSelectedStopColor(); 0682 break; 0683 case Qt::Key_Delete: 0684 deleteSelectedHandle(); 0685 break; 0686 default: 0687 QWidget::keyPressEvent(e); 0688 break; 0689 } 0690 } 0691 0692 void KisSegmentGradientSlider::leaveEvent(QEvent *e) 0693 { 0694 m_hoveredHandle = {}; 0695 emit updateRequested(); 0696 QWidget::leaveEvent(e); 0697 } 0698 0699 void KisSegmentGradientSlider::moveHandle(Handle handle, qreal distance, bool useShrinkEpsilon) 0700 { 0701 const qreal epsilon = useShrinkEpsilon ? shrinkEpsilon : 0.0; 0702 if (handle.type == HandleType_Segment) { 0703 KoGradientSegment *segment = m_gradient->segments()[handle.index]; 0704 KoGradientSegment *previousSegment = handle.index == 0 ? nullptr : m_gradient->segments()[handle.index - 1]; 0705 KoGradientSegment *nextSegment = handle.index == m_gradient->segments().size() - 1 ? nullptr : m_gradient->segments()[handle.index + 1]; 0706 if (previousSegment && nextSegment) { 0707 const qreal midPointRelativePos = segment->middleOffset() - segment->startOffset(); 0708 const qreal previousMidPointLocalPos = 0709 previousSegment->length() > std::numeric_limits<qreal>::epsilon() 0710 ? (previousSegment->middleOffset() - previousSegment->startOffset()) / previousSegment->length() 0711 : 0.0; 0712 const qreal nextMidPointLocalPos = 0713 nextSegment->length() > std::numeric_limits<qreal>::epsilon() 0714 ? (nextSegment->middleOffset() - nextSegment->startOffset()) / nextSegment->length() 0715 : 0.0; 0716 qreal newStartOffset, newEndOffset; 0717 if (distance < 0.0) { 0718 newStartOffset = qMax(segment->startOffset() + distance, previousSegment->startOffset() + epsilon); 0719 newEndOffset = newStartOffset + segment->length(); 0720 } else { 0721 newEndOffset = qMin(segment->endOffset() + distance, nextSegment->endOffset() - epsilon); 0722 newStartOffset = newEndOffset - segment->length(); 0723 } 0724 previousSegment->setEndOffset(newStartOffset); 0725 segment->setStartOffset(newStartOffset); 0726 segment->setEndOffset(newEndOffset); 0727 nextSegment->setStartOffset(newEndOffset); 0728 previousSegment->setMiddleOffset( 0729 previousSegment->startOffset() + 0730 previousMidPointLocalPos * previousSegment->length() 0731 ); 0732 nextSegment->setMiddleOffset( 0733 nextSegment->startOffset() + 0734 nextMidPointLocalPos * nextSegment->length() 0735 ); 0736 segment->setMiddleOffset(segment->startOffset() + midPointRelativePos); 0737 } else { 0738 if (!previousSegment) { 0739 segment->setStartOffset(0.0); 0740 } 0741 if (!nextSegment) { 0742 segment->setEndOffset(1.0); 0743 } 0744 } 0745 emit selectedHandleChanged(); 0746 emit updateRequested(); 0747 } else if (handle.type == HandleType_Stop) { 0748 KoGradientSegment *previousSegment = handle.index == 0 ? nullptr : m_gradient->segments()[handle.index - 1]; 0749 KoGradientSegment *nextSegment = handle.index == m_gradient->segments().size() ? nullptr : m_gradient->segments()[handle.index]; 0750 if (previousSegment && nextSegment) { 0751 const qreal previousMidPointLocalPos = 0752 previousSegment->length() > std::numeric_limits<qreal>::epsilon() 0753 ? (previousSegment->middleOffset() - previousSegment->startOffset()) / previousSegment->length() 0754 : 0.0; 0755 const qreal nextMidPointLocalPos = 0756 nextSegment->length() > std::numeric_limits<qreal>::epsilon() 0757 ? (nextSegment->middleOffset() - nextSegment->startOffset()) / nextSegment->length() 0758 : 0.0; 0759 qreal newOffset; 0760 if (distance < 0) { 0761 newOffset = qMax(previousSegment->endOffset() + distance, previousSegment->startOffset() + epsilon); 0762 } else { 0763 newOffset = qMin(previousSegment->endOffset() + distance, nextSegment->endOffset() - epsilon); 0764 } 0765 previousSegment->setEndOffset(newOffset); 0766 nextSegment->setStartOffset(newOffset); 0767 previousSegment->setMiddleOffset( 0768 previousSegment->startOffset() + 0769 previousMidPointLocalPos * previousSegment->length() 0770 ); 0771 nextSegment->setMiddleOffset( 0772 nextSegment->startOffset() + 0773 nextMidPointLocalPos * nextSegment->length() 0774 ); 0775 } else { 0776 if (!previousSegment) { 0777 nextSegment->setStartOffset(0.0); 0778 } 0779 if (!nextSegment) { 0780 previousSegment->setEndOffset(1.0); 0781 } 0782 } 0783 emit selectedHandleChanged(); 0784 emit updateRequested(); 0785 } else if (handle.type == HandleType_MidPoint) { 0786 KoGradientSegment *segment = m_gradient->segments()[handle.index]; 0787 segment->setMiddleOffset(qBound(segment->startOffset(), segment->middleOffset() + distance, segment->endOffset())); 0788 emit selectedHandleChanged(); 0789 emit updateRequested(); 0790 } 0791 } 0792 0793 void KisSegmentGradientSlider::moveHandleLeft(Handle handle, qreal distance, bool useShrinkEpsilon) 0794 { 0795 moveHandle(handle, -distance, useShrinkEpsilon); 0796 } 0797 0798 void KisSegmentGradientSlider::moveHandleRight(Handle handle, qreal distance, bool useShrinkEpsilon) 0799 { 0800 moveHandle(handle, distance, useShrinkEpsilon); 0801 } 0802 0803 void KisSegmentGradientSlider::moveSelectedHandle(qreal distance, bool useShrinkEpsilon) 0804 { 0805 moveHandle(m_selectedHandle, distance, useShrinkEpsilon); 0806 } 0807 0808 void KisSegmentGradientSlider::moveSelectedHandleLeft(qreal distance, bool useShrinkEpsilon) 0809 { 0810 moveSelectedHandle(-distance, useShrinkEpsilon); 0811 } 0812 0813 void KisSegmentGradientSlider::moveSelectedHandleRight(qreal distance, bool useShrinkEpsilon) 0814 { 0815 moveSelectedHandle(distance, useShrinkEpsilon); 0816 } 0817 0818 bool KisSegmentGradientSlider::deleteHandleImpl(Handle handle) 0819 { 0820 if (handle.type == HandleType_Segment) { 0821 if (m_gradient->removeSegment(m_gradient->segments()[handle.index])) { 0822 if (m_selectedHandle.index > 0) { 0823 --m_selectedHandle.index; 0824 } 0825 return true; 0826 } 0827 } else if (m_selectedHandle.type == HandleType_Stop) { 0828 if (m_selectedHandle.index <= 0 || m_selectedHandle.index >= m_gradient->segments().size()) { 0829 return false; 0830 } 0831 KoGradientSegment *previousSegment = m_gradient->segments()[m_selectedHandle.index - 1]; 0832 KoGradientSegment *nextSegment = m_gradient->segments()[m_selectedHandle.index]; 0833 const qreal middleOffset = previousSegment->endOffset(); 0834 previousSegment->setEndType(nextSegment->endType()); 0835 previousSegment->setEndColor(nextSegment->endColor()); 0836 m_gradient->removeSegment(nextSegment); 0837 previousSegment->setMiddleOffset(middleOffset); 0838 m_selectedHandle.type = HandleType_Segment; 0839 m_selectedHandle.index = m_selectedHandle.index - 1; 0840 return true; 0841 } 0842 return false; 0843 } 0844 0845 void KisSegmentGradientSlider::deleteHandle(Handle handle) 0846 { 0847 if (deleteHandleImpl(handle)) { 0848 emit selectedHandleChanged(); 0849 emit updateRequested(); 0850 } 0851 } 0852 0853 void KisSegmentGradientSlider::deleteSelectedHandle() 0854 { 0855 deleteHandle(m_selectedHandle); 0856 } 0857 0858 void KisSegmentGradientSlider::collapseSelectedSegment() 0859 { 0860 if (m_selectedHandle.type != HandleType_Segment) { 0861 return; 0862 } 0863 if (m_gradient->collapseSegment(m_gradient->segments()[m_selectedHandle.index])) { 0864 if (m_selectedHandle.index == m_gradient->segments().size()) { 0865 --m_selectedHandle.index; 0866 } 0867 emit selectedHandleChanged(); 0868 emit updateRequested(); 0869 } 0870 } 0871 0872 void KisSegmentGradientSlider::centerSelectedHandle() 0873 { 0874 if (m_selectedHandle.type == HandleType_Segment) { 0875 KoGradientSegment *segment = m_gradient->segments()[m_selectedHandle.index]; 0876 KoGradientSegment *previousSegment = m_selectedHandle.index == 0 ? nullptr : m_gradient->segments()[m_selectedHandle.index - 1]; 0877 KoGradientSegment *nextSegment = m_selectedHandle.index == m_gradient->segments().size() - 1 ? nullptr : m_gradient->segments()[m_selectedHandle.index + 1]; 0878 if (previousSegment && nextSegment) { 0879 moveSelectedHandle( 0880 (previousSegment->startOffset() + nextSegment->endOffset()) / 2.0 - 0881 (segment->startOffset() + segment->endOffset()) / 2.0); 0882 } 0883 } else if (m_selectedHandle.type == HandleType_Stop) { 0884 KoGradientSegment *previousSegment = m_selectedHandle.index == 0 ? nullptr : m_gradient->segments()[m_selectedHandle.index - 1]; 0885 KoGradientSegment *nextSegment = m_selectedHandle.index == m_gradient->segments().size() ? nullptr : m_gradient->segments()[m_selectedHandle.index]; 0886 if (previousSegment && nextSegment) { 0887 moveSelectedHandle((previousSegment->startOffset() + nextSegment->endOffset()) / 2.0 - nextSegment->startOffset()); 0888 } 0889 } else if (m_selectedHandle.type == HandleType_MidPoint) { 0890 KoGradientSegment *segment = m_gradient->segments()[m_selectedHandle.index]; 0891 qDebug() << segment->startOffset() << segment->endOffset() << segment->middleOffset() << 0892 ((segment->startOffset() + segment->endOffset()) / 2); 0893 moveSelectedHandle((segment->startOffset() + segment->endOffset()) / 2.0 - segment->middleOffset()); 0894 } 0895 } 0896 0897 void KisSegmentGradientSlider::splitSelectedSegment() 0898 { 0899 if (m_selectedHandle.type != HandleType_Segment) { 0900 return; 0901 } 0902 m_gradient->splitSegment(m_gradient->segments()[m_selectedHandle.index]); 0903 emit selectedHandleChanged(); 0904 emit updateRequested(); 0905 } 0906 0907 void KisSegmentGradientSlider::duplicateSelectedSegment() 0908 { 0909 if (m_selectedHandle.type != HandleType_Segment) { 0910 return; 0911 } 0912 m_gradient->duplicateSegment(m_gradient->segments()[m_selectedHandle.index]); 0913 emit selectedHandleChanged(); 0914 emit updateRequested(); 0915 } 0916 0917 void KisSegmentGradientSlider::mirrorSelectedSegment() 0918 { 0919 if (m_selectedHandle.type != HandleType_Segment) { 0920 return; 0921 } 0922 m_gradient->mirrorSegment(m_gradient->segments()[m_selectedHandle.index]); 0923 emit selectedHandleChanged(); 0924 emit updateRequested(); 0925 } 0926 0927 void KisSegmentGradientSlider::flipGradient() 0928 { 0929 QList<KoGradientSegment*> oldSegments = m_gradient->segments(); 0930 QList<KoGradientSegment*> newSegments; 0931 for (int i = oldSegments.size() - 1; i >= 0; --i) { 0932 KoGradientSegment* oldSegment = oldSegments[i]; 0933 int interpolation = oldSegment->interpolation(); 0934 int colorInterpolation = oldSegment->colorInterpolation(); 0935 0936 if (interpolation == INTERP_SPHERE_INCREASING) { 0937 interpolation = INTERP_SPHERE_DECREASING; 0938 } 0939 else if (interpolation == INTERP_SPHERE_DECREASING) { 0940 interpolation = INTERP_SPHERE_INCREASING; 0941 } 0942 if (colorInterpolation == COLOR_INTERP_HSV_CW) { 0943 colorInterpolation = COLOR_INTERP_HSV_CCW; 0944 } 0945 else if (colorInterpolation == COLOR_INTERP_HSV_CCW) { 0946 colorInterpolation = COLOR_INTERP_HSV_CW; 0947 } 0948 0949 KoGradientSegment* newSegment = new KoGradientSegment( 0950 interpolation, colorInterpolation, 0951 { 1.0 - oldSegment->endOffset(), oldSegment->endColor(), oldSegment->endType() }, 0952 { 1.0 - oldSegment->startOffset(), oldSegment->startColor(), oldSegment->startType() }, 0953 1.0 - oldSegment->middleOffset() 0954 ); 0955 0956 newSegments.push_back(newSegment); 0957 } 0958 m_gradient->setSegments(newSegments); 0959 if (m_selectedHandle.type == HandleType_Stop) { 0960 m_selectedHandle.index = newSegments.size() - m_selectedHandle.index; 0961 } else { 0962 m_selectedHandle.index = newSegments.size() - 1 - m_selectedHandle.index; 0963 } 0964 emit selectedHandleChanged(); 0965 emit updateRequested(); 0966 } 0967 0968 void KisSegmentGradientSlider::distributeStopsEvenly() 0969 { 0970 const qreal size = 1.0 / m_gradient->segments().size(); 0971 for (int i = 0; i < m_gradient->segments().size(); ++i) { 0972 KoGradientSegment *segment = m_gradient->segments()[i]; 0973 const qreal relativeMidPointPosition = 0974 (segment->middleOffset() - segment->startOffset()) / 0975 (segment->endOffset() - segment->startOffset()); 0976 segment->setStartOffset(i * size); 0977 segment->setEndOffset((i + 1) * size); 0978 segment->setMiddleOffset( 0979 segment->startOffset() + relativeMidPointPosition * 0980 (segment->endOffset() - segment->startOffset())); 0981 } 0982 emit selectedHandleChanged(); 0983 emit updateRequested(); 0984 } 0985 0986 QRect KisSegmentGradientSlider::sliderRect() const 0987 { 0988 const qreal handleWidthOverTwo = static_cast<qreal>(m_handleSize.width()) / 2.0; 0989 const int hMargin = static_cast<int>(std::ceil(handleWidthOverTwo)) + 2; 0990 return rect().adjusted(hMargin, 0, -hMargin, 0); 0991 } 0992 0993 QRect KisSegmentGradientSlider::gradientStripeRect() const 0994 { 0995 const QRect rc = sliderRect(); 0996 return rc.adjusted(0, 0, 0, -m_handleSize.height() - 4); 0997 } 0998 0999 QRect KisSegmentGradientSlider::handlesStripeRect() const 1000 { 1001 const QRect rc = sliderRect(); 1002 return rc.adjusted(0, rc.height() - (m_handleSize.height() + 2), 0, -2); 1003 } 1004 1005 void KisSegmentGradientSlider::updateHandleSize() 1006 { 1007 QFontMetrics fm(font()); 1008 const int h = qMax(15, static_cast<int>(std::ceil(fm.height() * 0.75))); 1009 m_handleSize = QSize(h * 0.75, h); 1010 } 1011 1012 int KisSegmentGradientSlider::minimalHeight() const 1013 { 1014 QFontMetrics fm(font()); 1015 const int h = fm.height(); 1016 1017 QStyleOptionToolButton opt; 1018 QSize sz = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(h, h), this); 1019 1020 return qMax(32, sz.height()) + m_handleSize.height(); 1021 } 1022 1023 QSize KisSegmentGradientSlider::sizeHint() const 1024 { 1025 const int h = minimalHeight(); 1026 return QSize(2 * h, h); 1027 } 1028 1029 QSize KisSegmentGradientSlider::minimumSizeHint() const 1030 { 1031 const int h = minimalHeight(); 1032 return QSize(h, h); 1033 } 1034 1035 void KisSegmentGradientSlider::chooseSelectedStopColor() 1036 { 1037 if (m_selectedHandle.type != HandleType_Stop) { 1038 return; 1039 } 1040 QList<KoGradientSegment*> segments = m_gradient->segments(); 1041 if (m_selectedHandle.index < 0 || m_selectedHandle.index > segments.size()) { 1042 return; 1043 } 1044 1045 KoColor color1, color2; 1046 KoGradientSegmentEndpointType endType1{COLOR_ENDPOINT}, endType2{COLOR_ENDPOINT}; 1047 if (m_selectedHandle.index == 0) { 1048 endType1 = segments[0]->startType(); 1049 color1 = segments[0]->startColor(); 1050 } else { 1051 endType1 = segments[m_selectedHandle.index - 1]->endType(); 1052 color1 = segments[m_selectedHandle.index - 1]->endColor(); 1053 if (m_selectedHandle.index < segments.size()) { 1054 endType2 = segments[m_selectedHandle.index]->startType(); 1055 color2 = segments[m_selectedHandle.index]->startColor(); 1056 } 1057 } 1058 1059 KConfigGroup cfg = KSharedConfig::openConfig()->group("colorselector"); 1060 bool usePlatformDialog = cfg.readEntry("UsePlatformColorDialog", false); 1061 QDialog *colorDialog = nullptr; 1062 1063 if (!usePlatformDialog) { 1064 KisDlgInternalColorSelector::Config cfg; 1065 KisDlgInternalColorSelector *dialog = new KisDlgInternalColorSelector(this, color1, cfg, i18n("Choose a color")); 1066 dialog->setPreviousColor(color1); 1067 auto setColorFn = [dialog, segments, this]() mutable 1068 { 1069 if (m_selectedHandle.index == 0) { 1070 segments[0]->setStartType(COLOR_ENDPOINT); 1071 segments[0]->setStartColor(dialog->getCurrentColor()); 1072 } else { 1073 segments[m_selectedHandle.index - 1]->setEndType(COLOR_ENDPOINT); 1074 segments[m_selectedHandle.index - 1]->setEndColor(dialog->getCurrentColor()); 1075 if (m_selectedHandle.index < segments.size()) { 1076 segments[m_selectedHandle.index]->setStartType(COLOR_ENDPOINT); 1077 segments[m_selectedHandle.index]->setStartColor(dialog->getCurrentColor()); 1078 } 1079 } 1080 emit selectedHandleChanged(); 1081 emit updateRequested(); 1082 }; 1083 connect(dialog, &KisDlgInternalColorSelector::signalForegroundColorChosen, setColorFn); 1084 connect(dialog, &QDialog::accepted, setColorFn); 1085 colorDialog = dialog; 1086 } else { 1087 QColorDialog *dialog = new QColorDialog(this); 1088 dialog->setCurrentColor(color1.toQColor()); 1089 auto setColorFn = [dialog, segments, this]() mutable 1090 { 1091 KoColor color; 1092 color.fromQColor(dialog->currentColor()); 1093 if (m_selectedHandle.index == 0) { 1094 segments[0]->setStartType(COLOR_ENDPOINT); 1095 segments[0]->setStartColor(color); 1096 } else { 1097 segments[m_selectedHandle.index - 1]->setEndType(COLOR_ENDPOINT); 1098 segments[m_selectedHandle.index - 1]->setEndColor(color); 1099 if (m_selectedHandle.index < segments.size()) { 1100 segments[m_selectedHandle.index]->setStartType(COLOR_ENDPOINT); 1101 segments[m_selectedHandle.index]->setStartColor(color); 1102 } 1103 } 1104 emit selectedHandleChanged(); 1105 emit updateRequested(); 1106 }; 1107 connect(dialog, &QColorDialog::currentColorChanged, setColorFn); 1108 connect(dialog, &QDialog::accepted, setColorFn); 1109 colorDialog = dialog; 1110 } 1111 // common functionality 1112 connect(colorDialog, &QDialog::rejected, [endType1, endType2, color1, color2, segments, this]() 1113 { 1114 if (m_selectedHandle.index == 0) { 1115 segments[0]->setStartType(endType1); 1116 segments[0]->setStartColor(color1); 1117 } else { 1118 segments[m_selectedHandle.index - 1]->setEndType(endType1); 1119 segments[m_selectedHandle.index - 1]->setEndColor(color1); 1120 if (m_selectedHandle.index < segments.size()) { 1121 segments[m_selectedHandle.index]->setStartType(endType2); 1122 segments[m_selectedHandle.index]->setStartColor(color2); 1123 } 1124 } 1125 emit selectedHandleChanged(); 1126 emit updateRequested(); 1127 }); 1128 colorDialog->setAttribute(Qt::WA_DeleteOnClose); 1129 colorDialog->show(); 1130 colorDialog->raise(); 1131 colorDialog->activateWindow(); 1132 }