File indexing completed on 2024-12-22 04:13:06

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 <QComboBox>
0011 #include <QDoubleSpinBox>
0012 #include <QAction>
0013 #include <QDialog>
0014 #include <QMenu>
0015 
0016 #include <KoColorSpace.h>
0017 #include <resources/KoSegmentGradient.h>
0018 
0019 #include "kis_debug.h"
0020 
0021 #include "KisSegmentGradientSlider.h"
0022 
0023 #include <KoCanvasResourcesIds.h>
0024 #include <KoCanvasResourcesInterface.h>
0025 
0026 #include <kis_icon_utils.h>
0027 #include <kis_signals_blocker.h>
0028 #include <KisSpinBoxI18nHelper.h>
0029 
0030 #include "KisSegmentGradientEditor.h"
0031 
0032 KisSegmentGradientEditor::KisSegmentGradientEditor(QWidget *parent)
0033     : QWidget(parent)
0034     , m_gradient(nullptr)
0035     , m_canvasResourcesInterface(nullptr)
0036 {
0037     setupUi(this);
0038 
0039     QAction *selectPreviousHandleAction = new QAction(KisIconUtils::loadIcon("arrow-left"),
0040         i18nc("Action to select previous handle in the segment gradient editor", "Select previous handle"), this);
0041     selectPreviousHandleAction->setToolTip(selectPreviousHandleAction->text());
0042     connect(selectPreviousHandleAction, SIGNAL(triggered()), gradientSlider, SLOT(selectPreviousHandle()));
0043 
0044     QAction *selectNextHandleAction = new QAction(KisIconUtils::loadIcon("arrow-right"),
0045         i18nc("Action to select next handle in the segment gradient editor", "Select next handle"), this);
0046     selectNextHandleAction->setToolTip(selectNextHandleAction->text());
0047     connect(selectNextHandleAction, SIGNAL(triggered()), gradientSlider, SLOT(selectNextHandle()));
0048 
0049     m_editHandleAction = new QAction(KisIconUtils::loadIcon("document-edit"), i18nc("Button to edit the selected handle in the segment gradient editor", "Edit handle"), this);
0050     m_editHandleAction->setToolTip(m_editHandleAction->text());
0051     connect(m_editHandleAction, SIGNAL(triggered()), this, SLOT(editSelectedHandle()));
0052 
0053     m_deleteSegmentAction = new QAction(KisIconUtils::loadIcon("edit-delete"),
0054         i18nc("Action to delete the selected segment in the segment gradient editor", "Delete segment"), this);
0055     m_deleteSegmentAction->setToolTip(m_deleteSegmentAction->text());
0056     connect(m_deleteSegmentAction, SIGNAL(triggered()), gradientSlider, SLOT(collapseSelectedSegment()));
0057 
0058     m_flipSegmentAction = new QAction(KisIconUtils::loadIcon("transform_icons_mirror_x"),
0059         i18nc("Action to flip the selected segment in the segment gradient editor", "Flip segment"), this);
0060     m_flipSegmentAction->setToolTip(m_flipSegmentAction->text());
0061     connect(m_flipSegmentAction, SIGNAL(triggered()), gradientSlider, SLOT(mirrorSelectedSegment()));
0062 
0063     m_splitSegmentAction = new QAction(KisIconUtils::loadIcon("cut-item"),
0064         i18nc("Action to split the selected segment in the segment gradient editor", "Split segment"), this);
0065     m_splitSegmentAction->setToolTip(m_splitSegmentAction->text());
0066     connect(m_splitSegmentAction, SIGNAL(triggered()), gradientSlider, SLOT(splitSelectedSegment()));
0067 
0068     m_duplicateSegmentAction = new QAction(KisIconUtils::loadIcon("duplicateitem"),
0069         i18nc("Action to duplicate the selected segment in the segment gradient editor", "Duplicate segment"), this);
0070     m_duplicateSegmentAction->setToolTip(m_duplicateSegmentAction->text());
0071     connect(m_duplicateSegmentAction, SIGNAL(triggered()), gradientSlider, SLOT(duplicateSelectedSegment()));
0072 
0073     m_deleteStopAction = new QAction(KisIconUtils::loadIcon("edit-delete"),
0074         i18nc("Action to delete the selected stop in the segment gradient editor", "Delete stop"), this);
0075     m_deleteStopAction->setToolTip(m_deleteStopAction->text());
0076     connect(m_deleteStopAction, SIGNAL(triggered()), gradientSlider, SLOT(deleteSelectedHandle()));
0077 
0078     m_centerStopAction = new QAction(KisIconUtils::loadIcon("object-align-horizontal-center-calligra"),
0079         i18nc("Action to center the selected stop in the segment gradient editor", "Center stop"), this);
0080     m_centerStopAction->setToolTip(m_centerStopAction->text());
0081     connect(m_centerStopAction, SIGNAL(triggered()), gradientSlider, SLOT(centerSelectedHandle()));
0082 
0083     m_centerMidPointAction = new QAction(KisIconUtils::loadIcon("object-align-horizontal-center-calligra"),
0084         i18nc("Action to center the selected mid point in the segment gradient editor", "Center middle point"), this);
0085     m_centerMidPointAction->setToolTip(m_centerMidPointAction->text());
0086     connect(m_centerMidPointAction, SIGNAL(triggered()), gradientSlider, SLOT(centerSelectedHandle()));
0087 
0088     QAction *flipGradientAction = new QAction(KisIconUtils::loadIcon("transform_icons_mirror_x"),
0089         i18nc("Button to flip the gradient in the segment gradient editor", "Flip gradient"), this);
0090     flipGradientAction->setToolTip(flipGradientAction->text());
0091     connect(flipGradientAction, SIGNAL(triggered()), gradientSlider, SLOT(flipGradient()));
0092 
0093     QAction *distributeSegmentsEvenlyAction = new QAction(KisIconUtils::loadIcon("distribute-horizontal"),
0094         i18nc("Button to evenly distribute the segments in the segment gradient editor", "Distribute segments evenly"), this);
0095     distributeSegmentsEvenlyAction->setToolTip(distributeSegmentsEvenlyAction->text());
0096     connect(distributeSegmentsEvenlyAction, SIGNAL(triggered()), gradientSlider, SLOT(distributeStopsEvenly()));
0097 
0098     selectPreviousHandleButton->setAutoRaise(true);
0099     selectPreviousHandleButton->setDefaultAction(selectPreviousHandleAction);
0100     
0101     selectNextHandleButton->setAutoRaise(true);
0102     selectNextHandleButton->setDefaultAction(selectNextHandleAction);
0103 
0104     deleteSegmentButton->setAutoRaise(true);
0105     deleteSegmentButton->setDefaultAction(m_deleteSegmentAction);
0106 
0107     flipSegmentButton->setAutoRaise(true);
0108     flipSegmentButton->setDefaultAction(m_flipSegmentAction);
0109 
0110     splitSegmentButton->setAutoRaise(true);
0111     splitSegmentButton->setDefaultAction(m_splitSegmentAction);
0112 
0113     duplicateSegmentButton->setAutoRaise(true);
0114     duplicateSegmentButton->setDefaultAction(m_duplicateSegmentAction);
0115 
0116     deleteStopButton->setAutoRaise(true);
0117     deleteStopButton->setDefaultAction(m_deleteStopAction);
0118 
0119     centerStopButton->setAutoRaise(true);
0120     centerStopButton->setDefaultAction(m_centerStopAction);
0121 
0122     centerMidPointButton->setAutoRaise(true);
0123     centerMidPointButton->setDefaultAction(m_centerMidPointAction);
0124 
0125     flipGradientButton->setAutoRaise(true);
0126     flipGradientButton->setDefaultAction(flipGradientAction);
0127 
0128     distributeSegmentsEvenlyButton->setAutoRaise(true);
0129     distributeSegmentsEvenlyButton->setDefaultAction(distributeSegmentsEvenlyAction);
0130 
0131     compactModeSelectPreviousHandleButton->setAutoRaise(true);
0132     compactModeSelectPreviousHandleButton->setDefaultAction(selectPreviousHandleAction);
0133     
0134     compactModeSelectNextHandleButton->setAutoRaise(true);
0135     compactModeSelectNextHandleButton->setDefaultAction(selectNextHandleAction);
0136 
0137     compactModeMiscOptionsButton->setPopupMode(QToolButton::InstantPopup);
0138     compactModeMiscOptionsButton->setArrowVisible(false);
0139     compactModeMiscOptionsButton->setAutoRaise(true);
0140     compactModeMiscOptionsButton->setIcon(KisIconUtils::loadIcon("view-choose"));
0141     QMenu *compactModeMiscOptionsButtonMenu = new QMenu;
0142     QAction *separator = new QAction;
0143     separator->setSeparator(true);
0144     compactModeMiscOptionsButtonMenu->addAction(m_editHandleAction);
0145     compactModeMiscOptionsButtonMenu->addAction(m_deleteSegmentAction);
0146     compactModeMiscOptionsButtonMenu->addAction(m_flipSegmentAction);
0147     compactModeMiscOptionsButtonMenu->addAction(m_splitSegmentAction);
0148     compactModeMiscOptionsButtonMenu->addAction(m_duplicateSegmentAction);
0149     compactModeMiscOptionsButtonMenu->addAction(m_deleteStopAction);
0150     compactModeMiscOptionsButtonMenu->addAction(m_centerStopAction);
0151     compactModeMiscOptionsButtonMenu->addAction(m_centerMidPointAction);
0152     compactModeMiscOptionsButtonMenu->addAction(separator);
0153     compactModeMiscOptionsButtonMenu->addAction(flipGradientAction);
0154     compactModeMiscOptionsButtonMenu->addAction(distributeSegmentsEvenlyAction);
0155     compactModeMiscOptionsButton->setPopupWidget(compactModeMiscOptionsButtonMenu);
0156 
0157     stopLeftEditor->setUsePositionSlider(false);
0158     stopRightEditor->setUsePositionSlider(false);
0159     constrainStopButton->setKeepAspectRatio(false);
0160     constrainStopButton->setToolTip(i18nc("Button to link both end colors of a stop handle in the segment gradient editor", "Link colors"));
0161     stopPositionSlider->setRange(0, 100, 2);
0162     KisSpinBoxI18nHelper::setText(stopPositionSlider,
0163                                   i18nc("{n} is the number value, % is the percent sign", "Position: {n}%"));
0164     midPointPositionSlider->setRange(0, 100, 2);
0165     KisSpinBoxI18nHelper::setText(midPointPositionSlider,
0166                                   i18nc("{n} is the number value, % is the percent sign", "Position: {n}%"));
0167 
0168     setCompactMode(false);
0169     setGradient(0);
0170 }
0171 
0172 KisSegmentGradientEditor::KisSegmentGradientEditor(KoSegmentGradientSP gradient, QWidget *parent, const char* name, const QString& caption, KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0173     : KisSegmentGradientEditor(parent)
0174 {
0175     m_canvasResourcesInterface = canvasResourcesInterface;
0176     setObjectName(name);
0177     setWindowTitle(caption);
0178     setGradient(gradient);
0179 }
0180 
0181 void KisSegmentGradientEditor::setCompactMode(bool value)
0182 {
0183     lblName->setVisible(!value);
0184     nameedit->setVisible(!value);
0185     buttonsContainer->setVisible(!value);
0186     handleEditorContainer->setVisible(!value);
0187     compactModeButtonsContainer->setVisible(value);
0188 }
0189 
0190 void KisSegmentGradientEditor::setGradient(KoSegmentGradientSP gradient)
0191 {
0192     m_gradient = gradient;
0193     setEnabled(m_gradient);
0194 
0195     if (m_gradient) {
0196         nameedit->setText(m_gradient->name());
0197         gradientSlider->setGradientResource(m_gradient);
0198     }
0199 
0200     emit sigGradientChanged();
0201 }
0202 
0203 void KisSegmentGradientEditor::setCanvasResourcesInterface(KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0204 {
0205     m_canvasResourcesInterface = canvasResourcesInterface;
0206 }
0207 
0208 KoCanvasResourcesInterfaceSP KisSegmentGradientEditor::canvasResourcesInterface() const
0209 {
0210     return m_canvasResourcesInterface;
0211 }
0212 
0213 void KisSegmentGradientEditor::on_gradientSlider_selectedHandleChanged()
0214 {
0215     KisSegmentGradientSlider::Handle handle = gradientSlider->selectedHandle();
0216 
0217     if (handle.type == KisSegmentGradientSlider::HandleType_Segment) {
0218         KoGradientSegment *segment = m_gradient->segments()[handle.index];
0219 
0220         KisSignalsBlocker blocker(
0221             segmentLeftEditor, segmentRightEditor,
0222             segmentInterpolationTypeComboBox, segmentColorInterpolationTypeComboBox
0223         );
0224 
0225         selectedHandleLabel->setText(i18nc("Text that indicates the selected segment in the segment gradient editor", "Segment #%1", handle.index + 1));
0226         
0227         segmentLeftEditor->setColorType(KisGradientWidgetsUtils::segmentEndPointTypeToColorType(segment->startType()));
0228         segmentLeftEditor->setTransparent(segment->startType() == FOREGROUND_TRANSPARENT_ENDPOINT ||
0229                                           segment->startType() == BACKGROUND_TRANSPARENT_ENDPOINT);
0230         segmentLeftEditor->setColor(segment->startColor());
0231         segmentLeftEditor->setOpacity(segment->startColor().opacityF() * 100.0);
0232         segmentLeftEditor->setPosition(segment->startOffset() * 100.0);
0233         segmentLeftEditor->setPositionSliderEnabled(handle.index > 0);
0234 
0235         segmentRightEditor->setColorType(KisGradientWidgetsUtils::segmentEndPointTypeToColorType(segment->endType()));
0236         segmentRightEditor->setTransparent(segment->endType() == FOREGROUND_TRANSPARENT_ENDPOINT ||
0237                                            segment->endType() == BACKGROUND_TRANSPARENT_ENDPOINT);
0238         segmentRightEditor->setColor(segment->endColor());
0239         segmentRightEditor->setOpacity(segment->endColor().opacityF() * 100.0);
0240         segmentRightEditor->setPosition(segment->endOffset() * 100.0);
0241         segmentRightEditor->setPositionSliderEnabled(handle.index < m_gradient->segments().size() - 1);
0242 
0243         segmentInterpolationTypeComboBox->setCurrentIndex(segment->interpolation());
0244         segmentColorInterpolationTypeComboBox->setCurrentIndex(segment->colorInterpolation());
0245 
0246         handleEditorContainer->setCurrentIndex(0);
0247 
0248         m_deleteSegmentAction->setEnabled(m_gradient->segments().size() > 1);
0249 
0250     } else if (handle.type == KisSegmentGradientSlider::HandleType_Stop) {
0251         KoGradientSegment *previousSegment = handle.index == 0 ? nullptr : m_gradient->segments()[handle.index - 1];
0252         KoGradientSegment *nextSegment = handle.index == m_gradient->segments().size() ? nullptr : m_gradient->segments()[handle.index];
0253 
0254         KisSignalsBlocker blocker(stopLeftEditor, stopRightEditor, constrainStopButton, stopPositionSlider);
0255 
0256         selectedHandleLabel->setText(i18nc("Text that indicates the selected stop in the segment gradient editor", "Stop #%1", handle.index + 1));
0257         
0258         if (previousSegment) {
0259             stopLeftEditor->setColorType(KisGradientWidgetsUtils::segmentEndPointTypeToColorType(previousSegment->endType()));
0260             stopLeftEditor->setTransparent(previousSegment->endType() == FOREGROUND_TRANSPARENT_ENDPOINT ||
0261                                            previousSegment->endType() == BACKGROUND_TRANSPARENT_ENDPOINT);
0262             stopLeftEditor->setColor(previousSegment->endColor());
0263             stopLeftEditor->setOpacity(previousSegment->endColor().opacityF() * 100.0);
0264         }
0265         stopLeftEditor->setEnabled(previousSegment);
0266 
0267         if (nextSegment) {
0268             stopRightEditor->setColorType(KisGradientWidgetsUtils::segmentEndPointTypeToColorType(nextSegment->startType()));
0269             stopRightEditor->setTransparent(nextSegment->startType() == FOREGROUND_TRANSPARENT_ENDPOINT ||
0270                                             nextSegment->startType() == BACKGROUND_TRANSPARENT_ENDPOINT);
0271             stopRightEditor->setColor(nextSegment->startColor());
0272             stopRightEditor->setOpacity(nextSegment->startColor().opacityF() * 100.0);
0273         }        
0274         stopRightEditor->setEnabled(nextSegment);
0275 
0276         if (previousSegment && nextSegment) {
0277             constrainStopButton->setKeepAspectRatio(
0278                 previousSegment->endType() == nextSegment->startType() &&
0279                 previousSegment->endColor() == nextSegment->startColor()
0280             );
0281         }
0282         constrainStopButton->setEnabled(previousSegment && nextSegment);
0283         if (previousSegment) {
0284             stopPositionSlider->setValue(previousSegment->endOffset() * 100.0);
0285         } else if (nextSegment) {
0286             stopPositionSlider->setValue(nextSegment->startOffset() * 100.0);
0287         }
0288         stopPositionSlider->setEnabled(previousSegment && nextSegment);
0289 
0290         handleEditorContainer->setCurrentIndex(1);
0291 
0292         m_deleteStopAction->setEnabled(previousSegment && nextSegment);
0293         m_centerStopAction->setEnabled(previousSegment && nextSegment);
0294 
0295     } else if (handle.type == KisSegmentGradientSlider::HandleType_MidPoint) {
0296         KoGradientSegment *segment = m_gradient->segments()[handle.index];
0297 
0298         KisSignalsBlocker blocker(midPointPositionSlider);
0299 
0300         selectedHandleLabel->setText(i18nc("Text that indicates the selected mid point in the segment gradient editor", "Mid-Point #%1", handle.index + 1));
0301 
0302         midPointPositionSlider->setValue(
0303             (segment->middleOffset() - segment->startOffset()) / (segment->endOffset() - segment->startOffset()) * 100.0
0304         );
0305 
0306         handleEditorContainer->setCurrentIndex(2);
0307 
0308     } else {
0309         selectedHandleLabel->setText(i18nc("Text that indicates no handle is selected in the stop gradient editor", "No handle selected"));
0310         handleEditorContainer->setCurrentIndex(3);
0311     }
0312 
0313     m_editHandleAction->setEnabled(handle.type != KisSegmentGradientSlider::HandleType_None);
0314 
0315     m_deleteSegmentAction->setVisible(handle.type == KisSegmentGradientSlider::HandleType_Segment);
0316     m_flipSegmentAction->setVisible(handle.type == KisSegmentGradientSlider::HandleType_Segment);
0317     m_splitSegmentAction->setVisible(handle.type == KisSegmentGradientSlider::HandleType_Segment);
0318     m_duplicateSegmentAction->setVisible(handle.type == KisSegmentGradientSlider::HandleType_Segment);
0319     segmentButtonsContainer->setVisible(handle.type == KisSegmentGradientSlider::HandleType_Segment);
0320 
0321     m_deleteStopAction->setVisible(handle.type == KisSegmentGradientSlider::HandleType_Stop);
0322     m_centerStopAction->setVisible(handle.type == KisSegmentGradientSlider::HandleType_Stop);
0323     stopButtonsContainer->setVisible(handle.type == KisSegmentGradientSlider::HandleType_Stop);
0324 
0325     m_centerMidPointAction->setVisible(handle.type == KisSegmentGradientSlider::HandleType_MidPoint);
0326     midPointButtonsContainer->setVisible(handle.type == KisSegmentGradientSlider::HandleType_MidPoint);
0327 
0328     emit sigGradientChanged();
0329 }
0330 
0331 void KisSegmentGradientEditor::on_segmentLeftEditor_positionChanged(double position)
0332 {
0333     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Segment) {
0334         return;
0335     } 
0336     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0337     KisSegmentGradientSlider::Handle stopHandle{KisSegmentGradientSlider::HandleType_Stop, gradientSlider->selectedHandle().index};
0338     {
0339         KisSignalsBlocker blocker(gradientSlider, segmentLeftEditor);
0340         gradientSlider->moveHandle(stopHandle, position / 100.0 - segment->startOffset());
0341         // Set the clamped value
0342         segmentLeftEditor->setPosition(segment->startOffset() * 100.0);
0343     }
0344     emit gradientSlider->updateRequested();
0345     emit sigGradientChanged();
0346 }
0347 
0348 void KisSegmentGradientEditor::on_segmentLeftEditor_colorTypeChanged(KisGradientWidgetsUtils::ColorType type)
0349 {
0350     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Segment) {
0351         return;
0352     } 
0353 
0354     KoGradientSegmentEndpointType endPointType = KisGradientWidgetsUtils::colorTypeToSegmentEndPointType(type, segmentLeftEditor->transparent());
0355     KoColor color;
0356     const qreal opacity = segmentLeftEditor->transparent() ? 0.0 : 1.0;
0357     const KoColorSpace* colorSpace = m_gradient->colorSpace();
0358 
0359     if (endPointType == FOREGROUND_ENDPOINT || endPointType == FOREGROUND_TRANSPARENT_ENDPOINT) {
0360         if (m_canvasResourcesInterface) {
0361             color = m_canvasResourcesInterface->resource(KoCanvasResource::ForegroundColor).value<KoColor>().convertedTo(colorSpace);
0362         } else {
0363             color = KoColor(segmentLeftEditor->color(), colorSpace);
0364         }
0365     } else if (endPointType == BACKGROUND_ENDPOINT || endPointType == BACKGROUND_TRANSPARENT_ENDPOINT) {
0366         if (m_canvasResourcesInterface) {
0367             color = m_canvasResourcesInterface->resource(KoCanvasResource::BackgroundColor).value<KoColor>().convertedTo(colorSpace);
0368         } else {
0369             color = KoColor(segmentLeftEditor->color(), colorSpace);
0370         }
0371     } else {
0372         color = KoColor(segmentLeftEditor->color(), colorSpace);
0373     }
0374 
0375     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0376     segment->setStartType(endPointType);
0377     color.setOpacity(opacity);
0378     segment->setStartColor(color);
0379 
0380     segmentLeftEditor->setColor(color);
0381     segmentLeftEditor->setOpacity(opacity * 100.0);
0382 
0383     emit gradientSlider->updateRequested();
0384     emit sigGradientChanged();
0385 }
0386 
0387 void KisSegmentGradientEditor::on_segmentLeftEditor_transparentToggled(bool checked)
0388 {
0389     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Segment) {
0390         return;
0391     } 
0392     const qreal opacity = checked ? 0.0 : 1.0;
0393     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0394     segment->setStartType(KisGradientWidgetsUtils::colorTypeToSegmentEndPointType(segmentLeftEditor->colorType(), checked));
0395     KoColor color = segment->startColor();
0396     color.setOpacity(opacity);
0397     segment->setStartColor(color);
0398     segmentLeftEditor->setOpacity(opacity * 100.0);
0399     emit gradientSlider->updateRequested();
0400     emit sigGradientChanged();
0401 }
0402 
0403 void KisSegmentGradientEditor::on_segmentLeftEditor_colorChanged(KoColor color)
0404 {
0405     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Segment) {
0406         return;
0407     }
0408     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0409     KoColor c(color, segment->startColor().colorSpace());
0410     c.setOpacity(segmentLeftEditor->opacity() / 100.0);
0411     segment->setStartColor(c);
0412     emit gradientSlider->updateRequested();
0413     emit sigGradientChanged();
0414 }
0415 
0416 void KisSegmentGradientEditor::on_segmentLeftEditor_opacityChanged(double opacity)
0417 {
0418     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Segment) {
0419         return;
0420     }
0421     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0422     KoColor color = segment->startColor();
0423     color.setOpacity(opacity / 100.0);
0424     segment->setStartColor(color);
0425     emit gradientSlider->updateRequested();
0426     emit sigGradientChanged();
0427 }
0428 
0429 void KisSegmentGradientEditor::on_segmentRightEditor_positionChanged(double position)
0430 {
0431     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Segment) {
0432         return;
0433     } 
0434     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0435     KisSegmentGradientSlider::Handle stopHandle{KisSegmentGradientSlider::HandleType_Stop, gradientSlider->selectedHandle().index + 1};
0436     {
0437         KisSignalsBlocker blocker(gradientSlider, segmentLeftEditor);
0438         gradientSlider->moveHandle(stopHandle, position / 100.0 - segment->endOffset());
0439         // Set the clamped value
0440         segmentLeftEditor->setPosition(segment->startOffset() * 100.0);
0441     }
0442     emit gradientSlider->updateRequested();
0443     emit sigGradientChanged();
0444 }
0445 
0446 void KisSegmentGradientEditor::on_segmentRightEditor_colorTypeChanged(KisGradientWidgetsUtils::ColorType type)
0447 {
0448     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Segment) {
0449         return;
0450     } 
0451 
0452     KoGradientSegmentEndpointType endPointType = KisGradientWidgetsUtils::colorTypeToSegmentEndPointType(type, segmentRightEditor->transparent());
0453     KoColor color;
0454     const qreal opacity = segmentRightEditor->transparent() ? 0.0 : 1.0;
0455     const KoColorSpace* colorSpace = m_gradient->colorSpace();
0456 
0457     if (endPointType == FOREGROUND_ENDPOINT || endPointType == FOREGROUND_TRANSPARENT_ENDPOINT) {
0458         if (m_canvasResourcesInterface) {
0459             color = m_canvasResourcesInterface->resource(KoCanvasResource::ForegroundColor).value<KoColor>().convertedTo(colorSpace);
0460         } else {
0461             color = KoColor(segmentRightEditor->color(), colorSpace);
0462         }
0463     } else if (endPointType == BACKGROUND_ENDPOINT || endPointType == BACKGROUND_TRANSPARENT_ENDPOINT) {
0464         if (m_canvasResourcesInterface) {
0465             color = m_canvasResourcesInterface->resource(KoCanvasResource::BackgroundColor).value<KoColor>().convertedTo(colorSpace);
0466         } else {
0467             color = KoColor(segmentRightEditor->color(), colorSpace);
0468         }
0469     } else {
0470         color = KoColor(segmentRightEditor->color(), colorSpace);
0471     }
0472 
0473     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0474     segment->setEndType(endPointType);
0475     color.setOpacity(opacity);
0476     segment->setEndColor(color);
0477 
0478     segmentRightEditor->setColor(color);
0479     segmentRightEditor->setOpacity(opacity * 100.0);
0480 
0481     emit gradientSlider->updateRequested();
0482     emit sigGradientChanged();
0483 }
0484 
0485 void KisSegmentGradientEditor::on_segmentRightEditor_transparentToggled(bool checked)
0486 {
0487     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Segment) {
0488         return;
0489     } 
0490     const qreal opacity = checked ? 0.0 : 1.0;
0491     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0492     segment->setEndType(KisGradientWidgetsUtils::colorTypeToSegmentEndPointType(segmentRightEditor->colorType(), checked));
0493     KoColor color = segment->endColor();
0494     color.setOpacity(opacity);
0495     segment->setEndColor(color);
0496     segmentRightEditor->setOpacity(opacity * 100.0);
0497     emit gradientSlider->updateRequested();
0498     emit sigGradientChanged();
0499 }
0500 
0501 void KisSegmentGradientEditor::on_segmentRightEditor_colorChanged(KoColor color)
0502 {
0503     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Segment) {
0504         return;
0505     }
0506     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0507     KoColor c(color, segment->endColor().colorSpace());
0508     c.setOpacity(segmentRightEditor->opacity() / 100.0);
0509     segment->setEndColor(c);
0510     emit gradientSlider->updateRequested();
0511     emit sigGradientChanged();
0512 }
0513 
0514 void KisSegmentGradientEditor::on_segmentRightEditor_opacityChanged(double opacity)
0515 {
0516     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Segment) {
0517         return;
0518     }
0519     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0520     KoColor color = segment->endColor();
0521     color.setOpacity(opacity / 100.0);
0522     segment->setEndColor(color);
0523     emit gradientSlider->updateRequested();
0524     emit sigGradientChanged();
0525 }
0526 
0527 void KisSegmentGradientEditor::on_segmentInterpolationTypeComboBox_activated(int value)
0528 {
0529     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Segment) {
0530         return;
0531     }
0532     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0533     segment->setInterpolation(value);
0534     emit gradientSlider->updateRequested();
0535     emit sigGradientChanged();
0536 }
0537 
0538 void KisSegmentGradientEditor::on_segmentColorInterpolationTypeComboBox_activated(int value)
0539 {
0540     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Segment) {
0541         return;
0542     }
0543     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0544     segment->setColorInterpolation(value);
0545     emit gradientSlider->updateRequested();
0546     emit sigGradientChanged();
0547 }
0548 
0549 void KisSegmentGradientEditor::on_stopPositionSlider_valueChanged(double position)
0550 {
0551     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Stop) {
0552         return;
0553     } 
0554     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0555     {
0556         KisSignalsBlocker blocker(gradientSlider, stopPositionSlider);
0557         gradientSlider->moveSelectedHandle(position / 100.0 - segment->startOffset());
0558         // Set the clamped value
0559         stopPositionSlider->setValue(segment->startOffset() * 100.0);
0560     }
0561     emit gradientSlider->updateRequested();
0562     emit sigGradientChanged();
0563 }
0564 
0565 void KisSegmentGradientEditor::on_stopLeftEditor_colorTypeChanged(KisGradientWidgetsUtils::ColorType type)
0566 {
0567     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Stop) {
0568         return;
0569     } 
0570 
0571     KoGradientSegmentEndpointType endPointType = KisGradientWidgetsUtils::colorTypeToSegmentEndPointType(type, stopLeftEditor->transparent());
0572     KoColor color;
0573     const qreal opacity = stopLeftEditor->transparent() ? 0.0 : 1.0;
0574     const KoColorSpace* colorSpace = m_gradient->colorSpace();
0575 
0576     if (endPointType == FOREGROUND_ENDPOINT || endPointType == FOREGROUND_TRANSPARENT_ENDPOINT) {
0577         if (m_canvasResourcesInterface) {
0578             color = m_canvasResourcesInterface->resource(KoCanvasResource::ForegroundColor).value<KoColor>().convertedTo(colorSpace);
0579         } else {
0580             color = KoColor(stopLeftEditor->color(), colorSpace);
0581         }
0582     } else if (endPointType == BACKGROUND_ENDPOINT || endPointType == BACKGROUND_TRANSPARENT_ENDPOINT) {
0583         if (m_canvasResourcesInterface) {
0584             color = m_canvasResourcesInterface->resource(KoCanvasResource::BackgroundColor).value<KoColor>().convertedTo(colorSpace);
0585         } else {
0586             color = KoColor(stopLeftEditor->color(), colorSpace);
0587         }
0588     } else {
0589         color = KoColor(stopLeftEditor->color(), colorSpace);
0590     }
0591 
0592     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index - 1];
0593     segment->setEndType(endPointType);
0594     color.setOpacity(opacity);
0595     segment->setEndColor(color);
0596 
0597     stopLeftEditor->setColor(color);
0598     stopLeftEditor->setOpacity(opacity * 100.0);
0599 
0600     emit gradientSlider->updateRequested();
0601     emit sigGradientChanged();
0602 
0603     if (constrainStopButton->keepAspectRatio() &&
0604         gradientSlider->selectedHandle().index < m_gradient->segments().size()) {
0605         stopRightEditor->setColorType(stopLeftEditor->colorType());
0606     }
0607 }
0608 
0609 void KisSegmentGradientEditor::on_stopLeftEditor_transparentToggled(bool checked)
0610 {
0611     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Stop) {
0612         return;
0613     } 
0614     const qreal opacity = checked ? 0.0 : 1.0;
0615     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index - 1];
0616     segment->setEndType(KisGradientWidgetsUtils::colorTypeToSegmentEndPointType(stopLeftEditor->colorType(), checked));
0617     KoColor color = segment->endColor();
0618     color.setOpacity(opacity);
0619     segment->setEndColor(color);
0620     stopLeftEditor->setOpacity(opacity * 100.0);
0621     emit gradientSlider->updateRequested();
0622     emit sigGradientChanged();
0623     if (constrainStopButton->keepAspectRatio() &&
0624         gradientSlider->selectedHandle().index < m_gradient->segments().size()) {
0625         stopRightEditor->setTransparent(stopLeftEditor->transparent());
0626     }
0627 }
0628 
0629 void KisSegmentGradientEditor::on_stopLeftEditor_colorChanged(KoColor color)
0630 {
0631     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Stop) {
0632         return;
0633     }
0634     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index - 1];
0635     KoColor c(color, segment->endColor().colorSpace());
0636     c.setOpacity(stopLeftEditor->opacity() / 100.0);
0637     segment->setEndColor(c);
0638     emit gradientSlider->updateRequested();
0639     emit sigGradientChanged();
0640     if (constrainStopButton->keepAspectRatio() &&
0641         gradientSlider->selectedHandle().index < m_gradient->segments().size()) {
0642         stopRightEditor->setColor(stopLeftEditor->color());
0643     }
0644 }
0645 
0646 void KisSegmentGradientEditor::on_stopLeftEditor_opacityChanged(double opacity)
0647 {
0648     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Stop) {
0649         return;
0650     }
0651     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index - 1];
0652     KoColor color = segment->endColor();
0653     color.setOpacity(opacity / 100.0);
0654     segment->setEndColor(color);
0655     emit gradientSlider->updateRequested();
0656     emit sigGradientChanged();
0657     if (constrainStopButton->keepAspectRatio() &&
0658         gradientSlider->selectedHandle().index < m_gradient->segments().size()) {
0659         stopRightEditor->setOpacity(stopLeftEditor->opacity());
0660     }
0661 }
0662 
0663 void KisSegmentGradientEditor::on_stopRightEditor_colorTypeChanged(KisGradientWidgetsUtils::ColorType type)
0664 {
0665     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Stop) {
0666         return;
0667     } 
0668 
0669     KoGradientSegmentEndpointType endPointType = KisGradientWidgetsUtils::colorTypeToSegmentEndPointType(type, stopRightEditor->transparent());
0670     KoColor color;
0671     const qreal opacity = stopRightEditor->transparent() ? 0.0 : 1.0;
0672     const KoColorSpace* colorSpace = m_gradient->colorSpace();
0673 
0674     if (endPointType == FOREGROUND_ENDPOINT || endPointType == FOREGROUND_TRANSPARENT_ENDPOINT) {
0675         if (m_canvasResourcesInterface) {
0676             color = m_canvasResourcesInterface->resource(KoCanvasResource::ForegroundColor).value<KoColor>().convertedTo(colorSpace);
0677         } else {
0678             color = KoColor(stopRightEditor->color(), colorSpace);
0679         }
0680     } else if (endPointType == BACKGROUND_ENDPOINT || endPointType == BACKGROUND_TRANSPARENT_ENDPOINT) {
0681         if (m_canvasResourcesInterface) {
0682             color = m_canvasResourcesInterface->resource(KoCanvasResource::BackgroundColor).value<KoColor>().convertedTo(colorSpace);
0683         } else {
0684             color = KoColor(stopRightEditor->color(), colorSpace);
0685         }
0686     } else {
0687         color = KoColor(stopRightEditor->color(), colorSpace);
0688     }
0689 
0690     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0691     segment->setStartType(endPointType);
0692     color.setOpacity(opacity);
0693     segment->setStartColor(color);
0694 
0695     stopRightEditor->setColor(color);
0696     stopRightEditor->setOpacity(opacity * 100.0);
0697 
0698     emit gradientSlider->updateRequested();
0699     emit sigGradientChanged();
0700 
0701     if (constrainStopButton->keepAspectRatio() && gradientSlider->selectedHandle().index > 0) {
0702         stopLeftEditor->setColorType(stopRightEditor->colorType());
0703     }
0704 }
0705 
0706 void KisSegmentGradientEditor::on_stopRightEditor_transparentToggled(bool checked)
0707 {
0708     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Stop) {
0709         return;
0710     } 
0711     const qreal opacity = checked ? 0.0 : 1.0;
0712     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0713     segment->setStartType(KisGradientWidgetsUtils::colorTypeToSegmentEndPointType(stopRightEditor->colorType(), checked));
0714     KoColor color = segment->startColor();
0715     color.setOpacity(opacity);
0716     segment->setStartColor(color);
0717     stopRightEditor->setOpacity(opacity * 100.0);
0718     emit gradientSlider->updateRequested();
0719     emit sigGradientChanged();
0720     if (constrainStopButton->keepAspectRatio() && gradientSlider->selectedHandle().index > 0) {
0721         stopLeftEditor->setTransparent(stopRightEditor->transparent());
0722     }
0723 }
0724 
0725 void KisSegmentGradientEditor::on_stopRightEditor_colorChanged(KoColor color)
0726 {
0727     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Stop) {
0728         return;
0729     }
0730     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0731     KoColor c(color, segment->startColor().colorSpace());
0732     c.setOpacity(stopRightEditor->opacity() / 100.0);
0733     segment->setStartColor(c);
0734     emit gradientSlider->updateRequested();
0735     emit sigGradientChanged();
0736     if (constrainStopButton->keepAspectRatio() && gradientSlider->selectedHandle().index > 0) {
0737         stopLeftEditor->setColor(stopRightEditor->color());
0738     }
0739 }
0740 
0741 void KisSegmentGradientEditor::on_stopRightEditor_opacityChanged(double opacity)
0742 {
0743     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_Stop) {
0744         return;
0745     }
0746     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0747     KoColor color = segment->startColor();
0748     color.setOpacity(opacity / 100.0);
0749     segment->setStartColor(color);
0750     emit gradientSlider->updateRequested();
0751     emit sigGradientChanged();
0752     if (constrainStopButton->keepAspectRatio() && gradientSlider->selectedHandle().index > 0) {
0753         stopLeftEditor->setOpacity(stopRightEditor->opacity());
0754     }
0755 }
0756 
0757 void KisSegmentGradientEditor::on_constrainStopButton_keepAspectRatioChanged(bool keep)
0758 {
0759     if (!keep || gradientSlider->selectedHandle().index == m_gradient->segments().size()) {
0760         return;
0761     }
0762     stopRightEditor->setColorType(stopLeftEditor->colorType());
0763     stopRightEditor->setTransparent(stopLeftEditor->transparent());
0764     stopRightEditor->setColor(stopLeftEditor->color());
0765     stopRightEditor->setOpacity(stopLeftEditor->opacity());
0766     emit sigGradientChanged();
0767 }
0768 
0769 void KisSegmentGradientEditor::on_midPointPositionSlider_valueChanged(double position)
0770 {
0771     if (gradientSlider->selectedHandle().type != KisSegmentGradientSlider::HandleType_MidPoint) {
0772         return;
0773     } 
0774     KoGradientSegment *segment = m_gradient->segments()[gradientSlider->selectedHandle().index];
0775     segment->setMiddleOffset(segment->startOffset() + (position / 100.0) * (segment->endOffset() - segment->startOffset()));    
0776     emit gradientSlider->updateRequested();
0777     emit sigGradientChanged();
0778 }
0779 
0780 void KisSegmentGradientEditor::on_nameedit_editingFinished()
0781 {
0782     m_gradient->setName(nameedit->text());
0783     m_gradient->setFilename(nameedit->text() + m_gradient->defaultFileExtension());
0784     emit sigGradientChanged();
0785 }
0786 
0787 void KisSegmentGradientEditor::editSelectedHandle()
0788 {
0789     if (gradientSlider->selectedHandle().type == KisSegmentGradientSlider::HandleType_None) {
0790         return;
0791     }
0792 
0793     QDialog *dialog = new QDialog(this);
0794     dialog->setModal(true);
0795     dialog->setWindowTitle(i18nc("Title for the segment gradient handle editor", "Edit Handle"));
0796     dialog->setAttribute(Qt::WA_DeleteOnClose);
0797 
0798     QWidget *editor = handleEditorContainer->currentWidget();
0799     int index = handleEditorContainer->indexOf(editor);
0800     handleEditorContainer->removeWidget(editor);
0801 
0802     QVBoxLayout *dialogLayout = new QVBoxLayout;
0803     dialogLayout->setMargin(10);
0804     dialogLayout->addWidget(editor);
0805 
0806     dialog->setLayout(dialogLayout);
0807     editor->show();
0808     dialog->resize(0, 0);
0809 
0810     connect(dialog, &QDialog::finished, [this, editor, index](int)
0811                                         {
0812                                             handleEditorContainer->insertWidget(index, editor);
0813                                             handleEditorContainer->setCurrentIndex(index);
0814                                         });
0815 
0816     dialog->show();
0817     dialog->raise();
0818     dialog->activateWindow();
0819 }