File indexing completed on 2024-12-22 04:16:23
0001 /* 0002 * SPDX-FileCopyrightText: 2022 Agata Cacko <cacko.azh@gmail.com> 0003 * SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com> 0004 * 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 #include "KisSprayOpOptionWidget.h" 0009 0010 #include <QButtonGroup> 0011 #include <QMetaProperty> 0012 0013 #include <lager/constant.hpp> 0014 #include "ui_wdgsprayoptions.h" 0015 0016 #include "KisSprayOpOptionModel.h" 0017 #include <KisSpinBoxI18nHelper.h> 0018 #include "kis_curve_widget.h" 0019 #include <KisCurveWidgetConnectionHelper.h> 0020 0021 namespace { 0022 0023 class KisSprayOptionsWidget: public QWidget, public Ui::WdgSprayOptions 0024 { 0025 public: 0026 KisSprayOptionsWidget(QWidget *parent = 0) 0027 : QWidget(parent) { 0028 setupUi(this); 0029 0030 diameterSpinBox->setRange(1, 1000, 0); 0031 diameterSpinBox->setValue(100); 0032 diameterSpinBox->setExponentRatio(1.5); 0033 diameterSpinBox->setSuffix(i18n(" px")); 0034 0035 aspectSPBox->setRange(0.0, 2.0, 2); 0036 aspectSPBox->setSingleStep(0.01); 0037 aspectSPBox->setValue(1.0); 0038 0039 rotationAngleSelector->setDecimals(0); 0040 rotationAngleSelector->setIncreasingDirection(KisAngleGauge::IncreasingDirection_Clockwise); 0041 0042 scaleSpin->setRange(0.0, 10.0, 2); 0043 scaleSpin->setSingleStep(0.01); 0044 scaleSpin->setValue(1.0); 0045 0046 spacingSpin->setRange(0.0, 5.0, 2); 0047 spacingSpin->setSingleStep(0.01); 0048 spacingSpin->setValue(0.5); 0049 0050 jitterMovementSpin->setRange(0.0,5.0, 1); 0051 jitterMovementSpin->setSingleStep(0.1); 0052 jitterMovementSpin->setValue(1.0); 0053 0054 particlesSpinBox->setRange(1.0, 1000.0, 0); 0055 particlesSpinBox->setValue(12); 0056 particlesSpinBox->setExponentRatio(3.0); 0057 0058 coverageSpin->setRange(0.001, 0.02, 3); 0059 coverageSpin->setSingleStep(0.001); 0060 coverageSpin->setValue(0.003); 0061 KisSpinBoxI18nHelper::setText(coverageSpin, i18nc("{n} is the number value, % is the percent sign", "{n}%")); 0062 coverageSpin->setVisible(false); 0063 0064 angularDistCombo->setToolTip(i18n("Select how the particles are distributed as a function of the angle to the center of the spray area.")); 0065 0066 curveAngularDistWidget->setToolTip(i18n( 0067 "Set a custom distribution of the particles." 0068 "\nThe horizontal axis represents the angle from 0 to 360 degrees." 0069 "\nThe vertical axis represents how probable it is for a particle ending at that angle." 0070 "\nThe higher the curve at a given angle, the more particles will end at that angle." 0071 )); 0072 curveAngularDistSpin->setPrefix(i18n("Repeat: ")); 0073 curveAngularDistSpin->setSuffix(i18nc("Times symbol, like in 10x", "x")); 0074 curveAngularDistSpin->setRange(1, 10); 0075 curveAngularDistSpin->setToolTip(i18n( 0076 "Set how many times should the curve repeat from 0 degrees to 360 degrees." 0077 )); 0078 0079 radialDistCombo->setToolTip(i18n("Select how the particles are distributed as a function of the distance from the center of the spray area.")); 0080 0081 0082 centerBiasedPolarDistanceBox->setToolTip(i18n("Activates the old behavior where the particles are more accumulated towards the center of the spray area.")); 0083 0084 stdDeviationRadialDistSpin->setPrefix(i18n("Standard deviation: ")); 0085 stdDeviationRadialDistSpin->setRange(0.01, 1.0, 2); 0086 stdDeviationRadialDistSpin->setSingleStep(0.01); 0087 stdDeviationRadialDistSpin->setToolTip(i18n( 0088 "Set the standard deviation for the gaussian distribution." 0089 "\nLower values will make the particles concentrate towards the center of the spray area." 0090 )); 0091 0092 clusterRadialDistSpin->setPrefix(i18n("Clustering amount: ")); 0093 clusterRadialDistSpin->setRange(-100.0, 100.0, 2); 0094 clusterRadialDistSpin->setSoftRange(-10.0, 10.0); 0095 clusterRadialDistSpin->setToolTip(i18n( 0096 "Set how the particles should spread in the spray area." 0097 "\nPositive values will make the particles concentrate towards the center of the spray area." 0098 "\nNegative values will make the particles concentrate towards the border of the spray area." 0099 "\nValues near 0 will make the particles spread more uniformly." 0100 )); 0101 0102 curveRadialDistWidget->setToolTip(i18n( 0103 "Set a custom distribution of the particles." 0104 "\nThe horizontal axis represents the distance from the center to the border of the spray area." 0105 "\nThe vertical axis represents how probable it is for a particle ending at that distance." 0106 "\nThe higher the curve at a given distance, the more particles will end at that distance." 0107 )); 0108 curveRadialDistSpin->setPrefix(i18n("Repeat: ")); 0109 curveRadialDistSpin->setSuffix(i18nc("Times symbol, like in 10x", "x")); 0110 curveRadialDistSpin->setRange(1, 10); 0111 curveRadialDistSpin->setToolTip(i18n( 0112 "Set how many times should the curve repeat from the center to the border of the spray area." 0113 )); 0114 0115 layoutAngularDist->takeAt(1); 0116 0117 curveAngularDistContainer->setVisible(false); 0118 0119 layoutRadialDist->takeAt(1); 0120 layoutRadialDist->takeAt(1); 0121 layoutRadialDist->takeAt(1); 0122 0123 stdDeviationRadialDistSpin->setVisible(false); 0124 clusterRadialDistSpin->setVisible(false); 0125 curveRadialDistContainer->setVisible(false); 0126 } 0127 }; 0128 } 0129 0130 struct KisSprayOpOptionWidget::Private 0131 { 0132 Private(lager::cursor<KisSprayOpOptionData> optionData) 0133 : model(optionData) 0134 { 0135 } 0136 0137 KisSprayOpOptionModel model; 0138 }; 0139 0140 namespace { 0141 void slotSetupAngularDistributionWidget(KisSprayOptionsWidget *widget, int index) 0142 { 0143 if (index == 0 && widget->layoutAngularDist->count() == 3) { 0144 widget->layoutAngularDist->takeAt(1); 0145 widget->curveAngularDistContainer->setVisible(false); 0146 } else if (index == 1 && widget->layoutAngularDist->count() == 2) { 0147 widget->layoutAngularDist->insertWidget(1, widget->curveAngularDistContainer, 0); 0148 widget->curveAngularDistContainer->setVisible(true); 0149 } 0150 } 0151 0152 void slotSetupRadialDistributionWidget(KisSprayOptionsWidget *widget, int index) 0153 { 0154 while (widget->layoutRadialDist->count() > 2) { 0155 widget->layoutRadialDist->takeAt(1)->widget()->setVisible(false); 0156 } 0157 if (index == 0) { 0158 widget->layoutRadialDist->insertWidget(1, widget->centerBiasedPolarDistanceBox, 0); 0159 widget->centerBiasedPolarDistanceBox->setVisible(true); 0160 } else if (index == 1) { 0161 widget->layoutRadialDist->insertWidget(1, widget->centerBiasedPolarDistanceBox, 0); 0162 widget->layoutRadialDist->insertWidget(1, widget->stdDeviationRadialDistSpin, 0); 0163 widget->centerBiasedPolarDistanceBox->setVisible(true); 0164 widget->stdDeviationRadialDistSpin->setVisible(true); 0165 } else if (index == 2) { 0166 widget->layoutRadialDist->insertWidget(1, widget->clusterRadialDistSpin, 0); 0167 widget->clusterRadialDistSpin->setVisible(true); 0168 } else if (index == 3) { 0169 widget->layoutRadialDist->insertWidget(1, widget->curveRadialDistContainer, 0); 0170 widget->curveRadialDistContainer->setVisible(true); 0171 } 0172 } 0173 } 0174 0175 0176 KisSprayOpOptionWidget::KisSprayOpOptionWidget(lager::cursor<KisSprayOpOptionData> optionData) 0177 : KisPaintOpOption(i18n("Spray Area"), KisPaintOpOption::GENERAL, true) 0178 , m_d(new Private(optionData)) 0179 { 0180 0181 KisSprayOptionsWidget *widget = new KisSprayOptionsWidget(); 0182 setObjectName("KisSprayOpOption"); 0183 0184 m_checkable = false; 0185 0186 using namespace KisWidgetConnectionUtils; 0187 0188 connectControl(widget->diameterSpinBox, &m_d->model, "diameter"); 0189 connectControl(widget->aspectSPBox, &m_d->model, "aspect"); 0190 connectControl(widget->rotationAngleSelector, &m_d->model, "brushRotation"); 0191 connectControl(widget->scaleSpin, &m_d->model, "scale"); 0192 connectControl(widget->spacingSpin, &m_d->model, "spacing"); 0193 connectControl(widget->jitterMoveBox, &m_d->model, "jitterMovement"); 0194 connectControl(widget->jitterMovementSpin, &m_d->model, "jitterAmount"); 0195 0196 connectControl(widget->densityRadioButton, &m_d->model, "useDensity"); 0197 0198 0199 connectControl(widget->particlesSpinBox, &m_d->model, "particleCount"); 0200 connectControl(widget->coverageSpin, &m_d->model, "coverage"); 0201 0202 0203 connectControl(widget->angularDistCombo, &m_d->model, "angularDistributionType"); 0204 0205 connectControl(widget->curveAngularDistWidget, &m_d->model, "angularDistributionCurve"); 0206 connectControl(widget->curveAngularDistSpin, &m_d->model, "angularDistributionCurveRepeat"); 0207 0208 // enable widgets for the angular distribution 0209 slotSetupAngularDistributionWidget(widget, m_d->model.angularDistributionType() == KisSprayOpOptionData::ParticleDistribution_Uniform ? 0 : 1); 0210 connect(&m_d->model, &KisSprayOpOptionModel::angularDistributionTypeChanged, widget, [this, widget] (int index) { 0211 slotSetupAngularDistributionWidget(widget, index); 0212 }); 0213 0214 0215 connectControl(widget->radialDistCombo, &m_d->model, "radialDistributionType"); 0216 connectControl(widget->stdDeviationRadialDistSpin, &m_d->model, "radialDistributionStdDeviation"); 0217 connectControl(widget->clusterRadialDistSpin, &m_d->model, "radialDistributionClusteringAmount"); 0218 0219 connectControl(widget->curveRadialDistWidget, &m_d->model, "radialDistributionCurve"); 0220 0221 // enable widgets for radial distribution 0222 slotSetupRadialDistributionWidget(widget, (int)m_d->model.radialDistributionType()); 0223 connect(&m_d->model, &KisSprayOpOptionModel::radialDistributionTypeChanged, widget, [this, widget] (int index) { 0224 slotSetupRadialDistributionWidget(widget, index); 0225 }); 0226 0227 0228 connectControl(widget->curveRadialDistSpin, &m_d->model, "radialDistributionCurveRepeat"); 0229 connectControl(widget->centerBiasedPolarDistanceBox, &m_d->model, "radialDistributionCenterBiased"); 0230 0231 widget->jitterMovementSpin->setEnabled(m_d->model.jitterMovement()); 0232 connect(&m_d->model, &KisSprayOpOptionModel::jitterMovementChanged, widget->jitterMovementSpin, &KisDoubleSliderSpinBox::setEnabled); 0233 0234 connectWidgetVisibleToProperty(widget->particlesSpinBox, &m_d->model, "isNumParticlesVisible"); 0235 connectWidgetVisibleToProperty(widget->coverageSpin, &m_d->model, "useDensity"); 0236 0237 m_d->model.optionData.bind(std::bind(&KisSprayOpOptionWidget::emitSettingChanged, this)); 0238 0239 setConfigurationPage(widget); 0240 } 0241 0242 KisSprayOpOptionWidget::~KisSprayOpOptionWidget() 0243 { 0244 } 0245 0246 void KisSprayOpOptionWidget::writeOptionSetting(KisPropertiesConfigurationSP setting) const 0247 { 0248 KisSprayOpOptionData data = *m_d->model.optionData; 0249 data.write(setting.data()); 0250 } 0251 0252 void KisSprayOpOptionWidget::readOptionSetting(const KisPropertiesConfigurationSP setting) 0253 { 0254 KisSprayOpOptionData data = *m_d->model.optionData; 0255 data.read(setting.data()); 0256 m_d->model.optionData.set(data); 0257 } 0258 0259 lager::cursor<qreal> KisSprayOpOptionWidget::scale() const 0260 { 0261 return m_d->model.LAGER_QT(scale); 0262 } 0263 0264 lager::cursor<int> KisSprayOpOptionWidget::diameter() const 0265 { 0266 return m_d->model.LAGER_QT(diameter); 0267 }