Krita Source Code Documentation
Loading...
Searching...
No Matches
KisMaskingBrushOption.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2017 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
11
12#include <QWidget>
13#include <QVBoxLayout>
14#include <QHBoxLayout>
15#include <QComboBox>
16
17#include <QDomDocument>
18#include "kis_brush.h"
19#include "kis_image.h"
20#include "kis_image_config.h"
21#include "kis_brush_option.h"
22
28#include <lager/state.hpp>
29#include <lager/constant.hpp>
31#include <functional>
32#include "KisAutoBrushModel.h"
34#include "KisTextBrushModel.h"
35
36
37using namespace KisBrushModel;
38using namespace KisWidgetConnectionUtils;
39
40
41namespace detail {
42
43QString warningLabelText(qreal realBrushSize, qreal theoreticalMaskingBrushSize)
44{
45 return
46 i18nc("warning about too big size of the masked brush",
47 "WARNING: Dependent size of the masked brush grew too big (%1 pixels). Its value has been cropped to %2 pixels.",
48 theoreticalMaskingBrushSize,
49 realBrushSize);
50}
51
52bool warningLabelVisible(qreal theoreticalBrushSize) {
53 KisImageConfig cfg(true);
54 return theoreticalBrushSize > cfg.maxMaskingBrushSize();
55}
56
57
58}
59
60class MaskingBrushModel : public QObject
61{
62 Q_OBJECT
63public:
64 MaskingBrushModel(lager::cursor<MaskingBrushData> maskingData, lager::cursor<qreal> commonBrushSizeData, lager::reader<qreal> masterBrushSize)
65 : m_maskingData(maskingData),
66 m_commonBrushSizeData(commonBrushSizeData),
67 m_masterBrushSize(masterBrushSize),
68 m_preserveMode(false),
70 m_maskingData[&MaskingBrushData::brush][&BrushData::autoBrush],
73 m_maskingData[&MaskingBrushData::brush][&BrushData::predefinedBrush],
75 false),
77 m_maskingData[&MaskingBrushData::brush][&BrushData::textBrush]),
80 LAGER_QT(theoreticalBrushSize) {
83 .map(std::multiplies<qreal>{})},
85 LAGER_QT(warningLabelVisible) {
86 lager::with(m_preserveMode,
87 LAGER_QT(theoreticalBrushSize).map(&detail::warningLabelVisible))
88 .map(std::logical_and<bool>{})},
89 LAGER_QT(warningLabelText) {
90 lager::with(LAGER_QT(realBrushSize),
91 LAGER_QT(theoreticalBrushSize))
99
100 // the state must be declared **before** any cursors or readers
101 lager::cursor<MaskingBrushData> m_maskingData;
102 lager::cursor<qreal> m_commonBrushSizeData;
103 lager::reader<qreal> m_masterBrushSize;
104 lager::state<bool, lager::automatic_tag> m_preserveMode;
105
109
110 LAGER_QT_CURSOR(bool, isEnabled);
111 LAGER_QT_CURSOR(QString, compositeOpId);
112 LAGER_QT_READER(qreal, theoreticalBrushSize);
113 LAGER_QT_READER(qreal, realBrushSize);
114 LAGER_QT_READER(bool, warningLabelVisible);
115 LAGER_QT_READER(QString, warningLabelText);
116
118 {
119 if (!m_preserveMode.get() || !m_originalBrushInfo) return;
120
121 if (m_originalBrushInfo->brush != m_maskingData->brush ||
122 !qFuzzyCompare(m_originalBrushInfo->masterSize, m_masterBrushSize.get()) ||
123 !qFuzzyCompare(m_originalBrushInfo->commonSize, m_commonBrushSizeData.get())) {
124
125 m_originalBrushInfo = std::nullopt;
126 m_preserveMode.set(false);
127 }
128 }
129
131 {
133 {m_maskingData->brush,
134 m_masterBrushSize.get(),
136
137 m_preserveMode.set(true);
138 }
139
147
148private:
154
155 std::optional<OriginalBrushInfo> m_originalBrushInfo;
156 lager::reader<BrushData> m_maskingBrushCursor;
157
158};
159
160
162{
163 Private(lager::reader<qreal> effectiveBrushSize)
164 : ui(new QWidget())
165 , commonBrushSizeData(777.0)
166 , masterBrushSize(effectiveBrushSize)
167
168 , maskingModel(maskingData, commonBrushSizeData, effectiveBrushSize)
169 {
170 compositeSelector = new QComboBox(ui.data());
171
173 Q_FOREACH (const QString &id, supportedComposites) {
174 const QString name = KoCompositeOpRegistry::instance().getKoID(id).name();
175 compositeSelector->addItem(name, id);
176 }
177 compositeSelector->setCurrentIndex(0);
178
179 QHBoxLayout *compositeOpLayout = new QHBoxLayout();
180 compositeOpLayout->addWidget(new QLabel(i18n("Blending Mode:")), 0);
181 compositeOpLayout->addWidget(compositeSelector, 1);
182
183 brushSizeWarningLabel = new QLabel(ui.data());
184 brushSizeWarningLabel->setVisible(false);
185 brushSizeWarningLabel->setWordWrap(true);
186
188
189 QVBoxLayout *layout = new QVBoxLayout(ui.data());
190 layout->addLayout(compositeOpLayout, 0);
191 layout->addWidget(brushSizeWarningLabel, 0);
192 layout->addWidget(brushChooser, 1);
193 }
194
195 QScopedPointer<QWidget> ui;
197 QComboBox *compositeSelector = 0;
199
200 lager::state<KisBrushModel::MaskingBrushData, lager::automatic_tag> maskingData;
201 lager::state<qreal, lager::automatic_tag> commonBrushSizeData;
202 lager::reader<qreal> masterBrushSize;
204
207 lager::state<KisBrushModel::PrecisionData, lager::automatic_tag> brushPrecisionData;
208};
209
210KisMaskingBrushOption::KisMaskingBrushOption(lager::reader<qreal> effectiveBrushSize)
211 : KisPaintOpOption(i18n("Brush Tip"), KisPaintOpOption::MASKING_BRUSH, true)
212 , m_d(new Private(effectiveBrushSize))
213{
214 setObjectName("KisMaskingBrushOption");
215 setConfigurationPage(m_d->ui.data());
216
217 connect(&m_d->maskingModel, &MaskingBrushModel::isEnabledChanged,
220 &m_d->maskingModel, &MaskingBrushModel::setisEnabled);
221 m_d->maskingModel.LAGER_QT(isEnabled).nudge();
222
223 connect(&m_d->maskingModel, &MaskingBrushModel::compositeOpIdChanged,
225 connect(m_d->compositeSelector, qOverload<int>(&QComboBox::currentIndexChanged),
227 m_d->maskingModel.LAGER_QT(compositeOpId).nudge();
228
229 connect(&m_d->maskingModel, &MaskingBrushModel::warningLabelVisibleChanged,
230 m_d->brushSizeWarningLabel, &QLabel::setVisible);
231 m_d->maskingModel.LAGER_QT(warningLabelVisible).nudge();
232
233 connect(&m_d->maskingModel, &MaskingBrushModel::warningLabelTextChanged,
234 m_d->brushSizeWarningLabel, &QLabel::setText);
235 m_d->maskingModel.LAGER_QT(warningLabelText).nudge();
236
237 m_d->maskingData.watch(std::bind(&KisMaskingBrushOption::emitSettingChanged, this));
238 m_d->commonBrushSizeData.watch(std::bind(&KisMaskingBrushOption::emitSettingChanged, this));
239}
240
245
247{
248 using namespace KisBrushModel;
249
250 if (m_d->maskingData->useMasterSize &&
251 !m_d->maskingModel.m_preserveMode.get()) {
252
253 MaskingBrushData tempData = m_d->maskingModel.bakedOptionData();
254 tempData.masterSizeCoeff = m_d->commonBrushSizeData.get() / m_d->masterBrushSize.get();
255 tempData.write(setting.data());
256 } else {
257 m_d->maskingModel.bakedOptionData().write(setting.data());
258 }
259}
260
262{
263 MaskingBrushData data = MaskingBrushData::read(setting.data(), m_d->masterBrushSize.get(), resourcesInterface());
264
265 m_d->commonBrushSizeData.set(effectiveSizeForBrush(data.brush.type,
266 data.brush.autoBrush,
268 data.brush.textBrush));
269 m_d->maskingData.set(data);
270 m_d->maskingModel.startPreserveMode();
271}
272
274{
275 m_d->brushChooser->setImage(image);
276}
277
282
284{
285 return m_d->maskingData[&MaskingBrushData::isEnabled];
286}
287
289{
290 m_d->maskingModel.setcompositeOpId(m_d->compositeSelector->itemData(index).toString());
291}
292
294{
295 const int index = m_d->compositeSelector->findData(QVariant::fromValue(value));
297 m_d->compositeSelector->setCurrentIndex(index);
298}
299
300#include "KisMaskingBrushOption.moc"
float value(const T *src, size_t ch)
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
AutoBrushData bakedOptionData() const
int maxMaskingBrushSize() const
void lodLimitations(KisPaintopLodLimitations *l) const override
lager::reader< bool > maskingBrushEnabledReader() const
void readOptionSetting(const KisPropertiesConfigurationSP setting) override
void slotCompositeModeWidgetChanged(int index)
void writeOptionSetting(KisPropertiesConfigurationSP setting) const override
KisMaskingBrushOption(lager::reader< qreal > effectiveBrushSize)
void slotCompositeModePropertyChanged(const QString &value)
const QScopedPointer< Private > m_d
void setImage(KisImageWSP image) override
KisResourcesInterfaceSP resourcesInterface() const
virtual void setChecked(bool checked)
void setConfigurationPage(QWidget *page)
void sigCheckedChanged(bool value)
PredefinedBrushData bakedOptionData() const
static const KoCompositeOpRegistry & instance()
KoID getKoID(const QString &compositeOpID) const
QString name() const
Definition KoID.cpp:68
lager::reader< qreal > m_masterBrushSize
MaskingBrushData bakedOptionData() const
KisPredefinedBrushModel predefinedBrushModel
std::optional< OriginalBrushInfo > m_originalBrushInfo
KisTextBrushModel textBrushModel
LAGER_QT_READER(qreal, realBrushSize)
lager::reader< BrushData > m_maskingBrushCursor
LAGER_QT_READER(bool, warningLabelVisible)
LAGER_QT(warningLabelText)
LAGER_QT_CURSOR(QString, compositeOpId)
KisAutoBrushModel autoBrushModel
lager::cursor< qreal > m_commonBrushSizeData
LAGER_QT(theoreticalBrushSize)
lager::state< bool, lager::automatic_tag > m_preserveMode
MaskingBrushModel(lager::cursor< MaskingBrushData > maskingData, lager::cursor< qreal > commonBrushSizeData, lager::reader< qreal > masterBrushSize)
LAGER_QT_CURSOR(bool, isEnabled)
lager::cursor< MaskingBrushData > m_maskingData
LAGER_QT_READER(QString, warningLabelText)
LAGER_QT_READER(qreal, theoreticalBrushSize)
m_maskingBrushCursor(m_maskingData[&MaskingBrushData::brush])
LAGER_QT(warningLabelVisible)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
qreal effectiveSizeForBrush(BrushType type, const AutoBrushData &autoBrush, const PredefinedBrushData &predefinedBrush, const TextBrushData &textBrush)
KisPaintopLodLimitations brushLodLimitations(const BrushData &data)
QString warningLabelText(qreal realBrushSize, qreal theoreticalMaskingBrushSize)
bool warningLabelVisible(qreal theoreticalBrushSize)
PredefinedBrushData predefinedBrush
static MaskingBrushData read(const KisPropertiesConfiguration *config, qreal masterBrushSize, KisResourcesInterfaceSP resourcesInterface)
void write(KisPropertiesConfiguration *config) const
KisBrushSelectionWidget * brushChooser
lager::state< KisBrushModel::PrecisionData, lager::automatic_tag > brushPrecisionData
lager::state< qreal, lager::automatic_tag > commonBrushSizeData
lager::state< KisBrushModel::MaskingBrushData, lager::automatic_tag > maskingData
Private(lager::reader< qreal > effectiveBrushSize)