Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_brush_selection_widget.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2008 Boudewijn Rempt <boud@valdyas.org>
3 * SPDX-FileCopyrightText: 2014 Mohit Goyal <mohit.bits2011@gmail.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
8#include <QLayout>
9#include <QTabWidget>
10#include <QPainter>
11#include <QBrush>
12#include <QColor>
13#include <QButtonGroup>
14#include <QStackedWidget>
15
16#include <klocalizedstring.h>
17
19#include <kis_image.h>
21
22#include "kis_brush.h"
23#include "kis_auto_brush.h"
24#include "kis_imagepipe_brush.h"
31#include <KisZug.h>
32#include <KisLager.h>
33#include <lager/constant.hpp>
34
35using namespace KisBrushModel;
36using namespace KisWidgetConnectionUtils;
37
38QString calcPrecisionToolTip(int precisionLevel) {
39 QString toolTip;
40
41 KIS_SAFE_ASSERT_RECOVER_NOOP(precisionLevel >= 1);
42 KIS_SAFE_ASSERT_RECOVER_NOOP(precisionLevel <= 5);
43
44 switch (precisionLevel) {
45 case 1:
46 toolTip =
47 i18n("Precision Level 1 (fastest)\n"
48 "Subpixel precision: disabled\n"
49 "Brush size precision: 5%\n"
50 "\n"
51 "Optimal for very big brushes");
52 break;
53 case 2:
54 toolTip =
55 i18n("Precision Level 2\n"
56 "Subpixel precision: disabled\n"
57 "Brush size precision: 1%\n"
58 "\n"
59 "Optimal for big brushes");
60 break;
61 case 3:
62 toolTip =
63 i18n("Precision Level 3\n"
64 "Subpixel precision: disabled\n"
65 "Brush size precision: exact");
66 break;
67 case 4:
68 toolTip =
69 i18n("Precision Level 4 (optimal)\n"
70 "Subpixel precision: 50%\n"
71 "Brush size precision: exact\n"
72 "\n"
73 "Gives up to 50% better performance in comparison to Level 5");
74 break;
75 case 5:
76 toolTip =
77 i18n("Precision Level 5 (best quality)\n"
78 "Subpixel precision: exact\n"
79 "Brush size precision: exact\n"
80 "\n"
81 "The slowest performance. Best quality.");
82 break;
83 }
84 return toolTip;
85}
86
87class PrecisionModel : public QObject
88{
89 Q_OBJECT
90
91public:
92
93 PrecisionModel(lager::cursor<PrecisionData> source)
94 : m_source(source),
95 LAGER_QT(precisionLevel) {m_source[&PrecisionData::precisionLevel]},
96 LAGER_QT(useAutoPrecision) {m_source[&PrecisionData::useAutoPrecision]},
97 LAGER_QT(precisionToolTip) {LAGER_QT(precisionLevel).map(&calcPrecisionToolTip)}
98 {
99 }
100
101 lager::cursor<PrecisionData> m_source;
102
103 LAGER_QT_CURSOR(int, precisionLevel);
104 LAGER_QT_CURSOR(bool, useAutoPrecision);
105 LAGER_QT_READER(QString, precisionToolTip);
106};
107
109{
110 Private(lager::cursor<PrecisionData> precisionData)
111 : model(precisionData)
112 {
113 }
114
116 lager::cursor<int> brushType;
117};
118
120 KisAutoBrushModel *autoBrushModel,
121 KisPredefinedBrushModel *predefinedBrushModel,
122 KisTextBrushModel *textBrushModel,
123 lager::cursor<BrushType> brushType,
124 lager::cursor<PrecisionData> precisionData,
125 KisBrushOptionWidgetFlags flags,
126 QWidget *parent)
127 : QWidget(parent)
128 , m_currentBrushWidget(0)
129 , m_d(new Private(precisionData))
130{
131 uiWdgBrushChooser.setupUi(this);
132
133 m_buttonGroup = new QButtonGroup(this);
134 m_buttonGroup->setExclusive(true);
135 m_layout = new QGridLayout(uiWdgBrushChooser.settingsFrame);
136
137 m_stackedWidget = new QStackedWidget(this);
138 m_layout->addWidget(m_stackedWidget);
139
140 m_autoBrushWidget = new KisAutoBrushWidget(maxBrushSize, autoBrushModel, this, "autobrush");
141 addChooser(i18nc("Autobrush Brush tip mode", "Auto"), m_autoBrushWidget, AUTOBRUSH, KoGroupButton::GroupLeft);
142 m_predefinedBrushWidget = new KisPredefinedBrushChooser(maxBrushSize, predefinedBrushModel, this);
143 addChooser(i18nc("Predefined Brush tip mode", "Predefined"), m_predefinedBrushWidget, PREDEFINEDBRUSH, KoGroupButton::GroupCenter);
144
145 m_textBrushWidget = new KisTextBrushChooser(textBrushModel, this);
146 addChooser(i18nc("Text Brush tip mode", "Text"), m_textBrushWidget, TEXTBRUSH, KoGroupButton::GroupRight);
147
148 m_d->brushType = brushType.zoom(kislager::lenses::do_static_cast<BrushType, int>);
149
150 m_d->brushType.bind([this](int value) {m_stackedWidget->setCurrentIndex(value); });
151 m_d->brushType.bind([this](int value) {m_buttonGroup->button(value)->setChecked(true); });
152 connect(m_buttonGroup, &QButtonGroup::idClicked, [this] (int id) {m_d->brushType.set(id);});
153
154
155 Q_FOREACH (QWidget *widget, m_chooserMap.values()) {
156 m_minimumSize = m_minimumSize.expandedTo(widget->sizeHint());
157 }
158
159
161
162 uiWdgBrushChooser.sliderPrecision->setRange(1, 5);
163 uiWdgBrushChooser.sliderPrecision->setSingleStep(1);
164 uiWdgBrushChooser.sliderPrecision->setPageStep(1);
165
166
168 connectControl(uiWdgBrushChooser.sliderPrecision, &m_d->model, "precisionLevel");
169 connectControl(uiWdgBrushChooser.autoPrecisionCheckBox, &m_d->model, "useAutoPrecision");
170 connect(&m_d->model, &PrecisionModel::precisionToolTipChanged,
171 uiWdgBrushChooser.sliderPrecision, &KisSliderSpinBox::setToolTip);
172
173 connect(&m_d->model, &PrecisionModel::useAutoPrecisionChanged,
174 uiWdgBrushChooser.sliderPrecision, &KisSliderSpinBox::setDisabled);
175 connect(&m_d->model, &PrecisionModel::useAutoPrecisionChanged,
176 uiWdgBrushChooser.lblPrecision, &KisSliderSpinBox::setDisabled);
177 } else {
178 uiWdgBrushChooser.sliderPrecision->setVisible(false);
179 uiWdgBrushChooser.autoPrecisionCheckBox->setVisible(false);
180 uiWdgBrushChooser.lblPrecision->setVisible(false);
181 }
182}
183
184
188
190{
191 KisBrushSP theBrush;
192
193 // Fallback to auto brush if no brush selected
194 // Can happen if there is no predefined brush found
195 if (!theBrush)
196 theBrush = m_autoBrushWidget->brush();
197
198 return theBrush;
199
200}
205
207{
208 Q_FOREACH(const QString &option, options) {
209 QStringList l = option.split("/");
210 if (l.count() != 2) {
211 continue;
212 }
213 QObject *o = 0;
214 if (l[0] == "KisAutoBrushWidget") {
215 o = m_autoBrushWidget->findChild<QObject*>(l[1]);
216 }
217 else if (l[0] == "KisBrushChooser") {
218 o = m_predefinedBrushWidget->findChild<QObject*>(l[1]);
219 }
220 else if (l[0] == "KisTextBrushChooser") {
221 o = m_textBrushWidget->findChild<QObject*>(l[1]);
222 }
223 else {
224 qWarning() << "KisBrushSelectionWidget: Invalid option given to disable:" << option;
225 }
226
227 if (o) {
228 QWidget *w = qobject_cast<QWidget*>(o);
229 if (w) {
230 w->setVisible(false);
231 }
232 o = 0;
233 }
234 }
235}
236
238{
239 return lager::with(m_d->brushType.xform(kiszug::map_equal<int>(Predefined)),
241 .map(std::logical_and{});
242}
243
245{
246 return;
247
248 if (widget == m_currentBrushWidget) return;
249
251 m_layout->removeWidget(m_currentBrushWidget);
252 m_currentBrushWidget->setParent(this);
253 m_currentBrushWidget->hide();
254 }
255 widget->setMinimumSize(m_minimumSize);
256
257 m_currentBrushWidget = widget;
258 m_layout->addWidget(widget);
259
260 m_currentBrushWidget->show();
261 m_buttonGroup->button(m_chooserMap.key(widget))->setChecked(true);
262}
263
264void KisBrushSelectionWidget::addChooser(const QString& text, QWidget* widget, int id, KoGroupButton::GroupPosition pos)
265{
267 button->setGroupPosition(pos);
268 button->setText(text);
269 button->setAutoRaise(false);
270 button->setCheckable(true);
271 uiWdgBrushChooser.brushChooserButtonLayout->addWidget(button);
272 m_buttonGroup->addButton(button, id);
273
274 m_stackedWidget->insertWidget(id, widget);
275}
276
277#include "kis_brush_selection_widget.moc"
float value(const T *src, size_t ch)
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
KisTextBrushChooser * m_textBrushWidget
void hideOptions(const QStringList &options)
const QScopedPointer< Private > m_d
KisBrushSelectionWidget(int maxBrushSize, KisAutoBrushModel *autoBrushModel, KisPredefinedBrushModel *predefinedBrushModel, KisTextBrushModel *textBrushModel, lager::cursor< KisBrushModel::BrushType > brushType, lager::cursor< KisBrushModel::PrecisionData > precisionData, KisBrushOptionWidgetFlags flags, QWidget *parent=0)
lager::reader< bool > lightnessModeEnabled() const
QHash< int, QWidget * > m_chooserMap
void addChooser(const QString &text, QWidget *widget, int id, KoGroupButton::GroupPosition pos)
KisAutoBrushWidget * m_autoBrushWidget
KisPredefinedBrushChooser * m_predefinedBrushWidget
lager::reader< bool > lightnessModeEnabled() const
@ GroupLeft
The button is at the left of the group, so it would have rounded the left part.
@ GroupRight
The button is at the right of the group, so it would have rounded the right part.
@ GroupCenter
The button is on the center of the group, so it would have separators on both sides.
LAGER_QT_CURSOR(bool, useAutoPrecision)
PrecisionModel(lager::cursor< PrecisionData > source)
LAGER_QT_READER(QString, precisionToolTip)
LAGER_QT_CURSOR(int, precisionLevel)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
QString calcPrecisionToolTip(int precisionLevel)
QString button(const QWheelEvent &ev)
void connectControl(KisCompositeOpListWidget *widget, QObject *source, const char *property)
Private(lager::cursor< PrecisionData > precisionData)