Krita Source Code Documentation
Loading...
Searching...
No Matches
KisSprayOpOptionWidget.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2022 Agata Cacko <cacko.azh@gmail.com>
3 * SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
4 *
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
9
10#include <QButtonGroup>
11#include <QMetaProperty>
12
13#include <lager/constant.hpp>
14#include "ui_wdgsprayoptions.h"
15
18#include "kis_curve_widget.h"
20
21namespace {
22
23class KisSprayOptionsWidget: public QWidget, public Ui::WdgSprayOptions
24{
25public:
26 KisSprayOptionsWidget(QWidget *parent = 0)
27 : QWidget(parent) {
28 setupUi(this);
29
30 diameterSpinBox->setRange(1, 1000, 0);
31 diameterSpinBox->setValue(100);
32 diameterSpinBox->setExponentRatio(1.5);
33 diameterSpinBox->setSuffix(i18n(" px"));
34
35 aspectSPBox->setRange(0.0, 2.0, 2);
36 aspectSPBox->setSingleStep(0.01);
37 aspectSPBox->setValue(1.0);
38
39 rotationAngleSelector->setDecimals(0);
40 rotationAngleSelector->setIncreasingDirection(KisAngleGauge::IncreasingDirection_Clockwise);
41
42 scaleSpin->setRange(0.0, 10.0, 2);
43 scaleSpin->setSingleStep(0.01);
44 scaleSpin->setValue(1.0);
45
46 spacingSpin->setRange(0.0, 5.0, 2);
47 spacingSpin->setSingleStep(0.01);
48 spacingSpin->setValue(0.5);
49
50 jitterMovementSpin->setRange(0.0,5.0, 1);
51 jitterMovementSpin->setSingleStep(0.1);
52 jitterMovementSpin->setValue(1.0);
53
54 particlesSpinBox->setRange(1.0, 1000.0, 0);
55 particlesSpinBox->setValue(12);
56 particlesSpinBox->setExponentRatio(3.0);
57
58 coverageSpin->setRange(0.001, 0.02, 3);
59 coverageSpin->setSingleStep(0.001);
60 coverageSpin->setValue(0.003);
61 KisSpinBoxI18nHelper::setText(coverageSpin, i18nc("{n} is the number value, % is the percent sign", "{n}%"));
62 coverageSpin->setVisible(false);
63
64 angularDistCombo->setToolTip(i18n("Select how the particles are distributed as a function of the angle to the center of the spray area."));
65
66 curveAngularDistWidget->setToolTip(i18n(
67 "Set a custom distribution of the particles."
68 "\nThe horizontal axis represents the angle from 0 to 360 degrees."
69 "\nThe vertical axis represents how probable it is for a particle ending at that angle."
70 "\nThe higher the curve at a given angle, the more particles will end at that angle."
71 ));
72 curveAngularDistSpin->setPrefix(i18n("Repeat: "));
73 curveAngularDistSpin->setSuffix(i18nc("Times symbol, like in 10x", "x"));
74 curveAngularDistSpin->setRange(1, 10);
75 curveAngularDistSpin->setToolTip(i18n(
76 "Set how many times should the curve repeat from 0 degrees to 360 degrees."
77 ));
78
79 radialDistCombo->setToolTip(i18n("Select how the particles are distributed as a function of the distance from the center of the spray area."));
80
81
82 centerBiasedPolarDistanceBox->setToolTip(i18n("Activates the old behavior where the particles are more accumulated towards the center of the spray area."));
83
84 stdDeviationRadialDistSpin->setPrefix(i18n("Standard deviation: "));
85 stdDeviationRadialDistSpin->setRange(0.01, 1.0, 2);
86 stdDeviationRadialDistSpin->setSingleStep(0.01);
87 stdDeviationRadialDistSpin->setToolTip(i18n(
88 "Set the standard deviation for the gaussian distribution."
89 "\nLower values will make the particles concentrate towards the center of the spray area."
90 ));
91
92 clusterRadialDistSpin->setPrefix(i18n("Clustering amount: "));
93 clusterRadialDistSpin->setRange(-100.0, 100.0, 2);
94 clusterRadialDistSpin->setSoftRange(-10.0, 10.0);
95 clusterRadialDistSpin->setToolTip(i18n(
96 "Set how the particles should spread in the spray area."
97 "\nPositive values will make the particles concentrate towards the center of the spray area."
98 "\nNegative values will make the particles concentrate towards the border of the spray area."
99 "\nValues near 0 will make the particles spread more uniformly."
100 ));
101
102 curveRadialDistWidget->setToolTip(i18n(
103 "Set a custom distribution of the particles."
104 "\nThe horizontal axis represents the distance from the center to the border of the spray area."
105 "\nThe vertical axis represents how probable it is for a particle ending at that distance."
106 "\nThe higher the curve at a given distance, the more particles will end at that distance."
107 ));
108 curveRadialDistSpin->setPrefix(i18n("Repeat: "));
109 curveRadialDistSpin->setSuffix(i18nc("Times symbol, like in 10x", "x"));
110 curveRadialDistSpin->setRange(1, 10);
111 curveRadialDistSpin->setToolTip(i18n(
112 "Set how many times should the curve repeat from the center to the border of the spray area."
113 ));
114
115 layoutAngularDist->takeAt(1);
116
117 curveAngularDistContainer->setVisible(false);
118
119 layoutRadialDist->takeAt(1);
120 layoutRadialDist->takeAt(1);
121 layoutRadialDist->takeAt(1);
122
123 stdDeviationRadialDistSpin->setVisible(false);
124 clusterRadialDistSpin->setVisible(false);
125 curveRadialDistContainer->setVisible(false);
126 }
127};
128}
129
131{
132 Private(lager::cursor<KisSprayOpOptionData> optionData)
133 : model(optionData)
134 {
135 }
136
138};
139
140namespace {
141 void slotSetupAngularDistributionWidget(KisSprayOptionsWidget *widget, int index)
142 {
143 if (index == 0 && widget->layoutAngularDist->count() == 3) {
144 widget->layoutAngularDist->takeAt(1);
145 widget->curveAngularDistContainer->setVisible(false);
146 } else if (index == 1 && widget->layoutAngularDist->count() == 2) {
147 widget->layoutAngularDist->insertWidget(1, widget->curveAngularDistContainer, 0);
148 widget->curveAngularDistContainer->setVisible(true);
149 }
150 }
151
152 void slotSetupRadialDistributionWidget(KisSprayOptionsWidget *widget, int index)
153 {
154 while (widget->layoutRadialDist->count() > 2) {
155 widget->layoutRadialDist->takeAt(1)->widget()->setVisible(false);
156 }
157 if (index == 0) {
158 widget->layoutRadialDist->insertWidget(1, widget->centerBiasedPolarDistanceBox, 0);
159 widget->centerBiasedPolarDistanceBox->setVisible(true);
160 } else if (index == 1) {
161 widget->layoutRadialDist->insertWidget(1, widget->centerBiasedPolarDistanceBox, 0);
162 widget->layoutRadialDist->insertWidget(1, widget->stdDeviationRadialDistSpin, 0);
163 widget->centerBiasedPolarDistanceBox->setVisible(true);
164 widget->stdDeviationRadialDistSpin->setVisible(true);
165 } else if (index == 2) {
166 widget->layoutRadialDist->insertWidget(1, widget->clusterRadialDistSpin, 0);
167 widget->clusterRadialDistSpin->setVisible(true);
168 } else if (index == 3) {
169 widget->layoutRadialDist->insertWidget(1, widget->curveRadialDistContainer, 0);
170 widget->curveRadialDistContainer->setVisible(true);
171 }
172 }
173}
174
175
176KisSprayOpOptionWidget::KisSprayOpOptionWidget(lager::cursor<KisSprayOpOptionData> optionData)
177 : KisPaintOpOption(i18n("Spray Area"), KisPaintOpOption::GENERAL, true)
178 , m_d(new Private(optionData))
179{
180
181 KisSprayOptionsWidget *widget = new KisSprayOptionsWidget();
182 setObjectName("KisSprayOpOption");
183
184 m_checkable = false;
185
186 using namespace KisWidgetConnectionUtils;
187
188 connectControl(widget->diameterSpinBox, &m_d->model, "diameter");
189 connectControl(widget->aspectSPBox, &m_d->model, "aspect");
190 connectControl(widget->rotationAngleSelector, &m_d->model, "brushRotation");
191 connectControl(widget->scaleSpin, &m_d->model, "scale");
192 connectControl(widget->spacingSpin, &m_d->model, "spacing");
193 connectControl(widget->jitterMoveBox, &m_d->model, "jitterMovement");
194 connectControl(widget->jitterMovementSpin, &m_d->model, "jitterAmount");
195
196 connectControl(widget->densityRadioButton, &m_d->model, "useDensity");
197
198
199 connectControl(widget->particlesSpinBox, &m_d->model, "particleCount");
200 connectControl(widget->coverageSpin, &m_d->model, "coverage");
201
202
203 connectControl(widget->angularDistCombo, &m_d->model, "angularDistributionType");
204
205 connectControl(widget->curveAngularDistWidget, &m_d->model, "angularDistributionCurve");
206 connectControl(widget->curveAngularDistSpin, &m_d->model, "angularDistributionCurveRepeat");
207
208 // enable widgets for the angular distribution
209 slotSetupAngularDistributionWidget(widget, m_d->model.angularDistributionType() == KisSprayOpOptionData::ParticleDistribution_Uniform ? 0 : 1);
210 connect(&m_d->model, &KisSprayOpOptionModel::angularDistributionTypeChanged, widget, [this, widget] (int index) {
211 slotSetupAngularDistributionWidget(widget, index);
212 });
213
214
215 connectControl(widget->radialDistCombo, &m_d->model, "radialDistributionType");
216 connectControl(widget->stdDeviationRadialDistSpin, &m_d->model, "radialDistributionStdDeviation");
217 connectControl(widget->clusterRadialDistSpin, &m_d->model, "radialDistributionClusteringAmount");
218
219 connectControl(widget->curveRadialDistWidget, &m_d->model, "radialDistributionCurve");
220
221 // enable widgets for radial distribution
222 slotSetupRadialDistributionWidget(widget, (int)m_d->model.radialDistributionType());
223 connect(&m_d->model, &KisSprayOpOptionModel::radialDistributionTypeChanged, widget, [this, widget] (int index) {
224 slotSetupRadialDistributionWidget(widget, index);
225 });
226
227
228 connectControl(widget->curveRadialDistSpin, &m_d->model, "radialDistributionCurveRepeat");
229 connectControl(widget->centerBiasedPolarDistanceBox, &m_d->model, "radialDistributionCenterBiased");
230
231 widget->jitterMovementSpin->setEnabled(m_d->model.jitterMovement());
232 connect(&m_d->model, &KisSprayOpOptionModel::jitterMovementChanged, widget->jitterMovementSpin, &KisDoubleSliderSpinBox::setEnabled);
233
234 connectWidgetVisibleToProperty(widget->particlesSpinBox, &m_d->model, "isNumParticlesVisible");
235 connectWidgetVisibleToProperty(widget->coverageSpin, &m_d->model, "useDensity");
236
237 m_d->model.optionData.bind(std::bind(&KisSprayOpOptionWidget::emitSettingChanged, this));
238
239 setConfigurationPage(widget);
240}
241
245
247{
248 KisSprayOpOptionData data = *m_d->model.optionData;
249 data.write(setting.data());
250}
251
253{
254 KisSprayOpOptionData data = *m_d->model.optionData;
255 data.read(setting.data());
256 m_d->model.optionData.set(data);
257}
258
259lager::cursor<qreal> KisSprayOpOptionWidget::scale() const
260{
261 return m_d->model.LAGER_QT(scale);
262}
263
264lager::cursor<int> KisSprayOpOptionWidget::diameter() const
265{
266 return m_d->model.LAGER_QT(diameter);
267}
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
@ IncreasingDirection_Clockwise
void setConfigurationPage(QWidget *page)
const QScopedPointer< Private > m_d
void writeOptionSetting(KisPropertiesConfigurationSP setting) const override
KisSprayOpOptionWidget(lager::cursor< KisSprayOpOptionData > optionData)
lager::cursor< qreal > scale() const
void readOptionSetting(const KisPropertiesConfigurationSP setting) override
lager::cursor< int > diameter() const
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:327
void setText(QSpinBox *spinBox, const QStringView textTemplate)
@ GENERAL
Definition nugrid.h:26
bool read(const KisPropertiesConfiguration *setting)
void write(KisPropertiesConfiguration *setting) const
Private(lager::cursor< KisSprayOpOptionData > optionData)