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"
29#include <KisZug.h>
30#include <KisLager.h>
31#include <lager/constant.hpp>
32
33using namespace KisBrushModel;
34using namespace KisWidgetConnectionUtils;
35
36QString calcPrecisionToolTip(int precisionLevel) {
37 QString toolTip;
38
39 KIS_SAFE_ASSERT_RECOVER_NOOP(precisionLevel >= 1);
40 KIS_SAFE_ASSERT_RECOVER_NOOP(precisionLevel <= 5);
41
42 switch (precisionLevel) {
43 case 1:
44 toolTip =
45 i18n("Precision Level 1 (fastest)\n"
46 "Subpixel precision: disabled\n"
47 "Brush size precision: 5%\n"
48 "\n"
49 "Optimal for very big brushes");
50 break;
51 case 2:
52 toolTip =
53 i18n("Precision Level 2\n"
54 "Subpixel precision: disabled\n"
55 "Brush size precision: 1%\n"
56 "\n"
57 "Optimal for big brushes");
58 break;
59 case 3:
60 toolTip =
61 i18n("Precision Level 3\n"
62 "Subpixel precision: disabled\n"
63 "Brush size precision: exact");
64 break;
65 case 4:
66 toolTip =
67 i18n("Precision Level 4 (optimal)\n"
68 "Subpixel precision: 50%\n"
69 "Brush size precision: exact\n"
70 "\n"
71 "Gives up to 50% better performance in comparison to Level 5");
72 break;
73 case 5:
74 toolTip =
75 i18n("Precision Level 5 (best quality)\n"
76 "Subpixel precision: exact\n"
77 "Brush size precision: exact\n"
78 "\n"
79 "The slowest performance. Best quality.");
80 break;
81 }
82 return toolTip;
83}
84
85class PrecisionModel : public QObject
86{
87 Q_OBJECT
88
89public:
90
91 PrecisionModel(lager::cursor<PrecisionData> source)
92 : m_source(source),
93 LAGER_QT(precisionLevel) {m_source[&PrecisionData::precisionLevel]},
94 LAGER_QT(useAutoPrecision) {m_source[&PrecisionData::useAutoPrecision]},
95 LAGER_QT(precisionToolTip) {LAGER_QT(precisionLevel).map(&calcPrecisionToolTip)}
96 {
97 }
98
99 lager::cursor<PrecisionData> m_source;
100
101 LAGER_QT_CURSOR(int, precisionLevel);
102 LAGER_QT_CURSOR(bool, useAutoPrecision);
103 LAGER_QT_READER(QString, precisionToolTip);
104};
105
107{
108 Private(lager::cursor<PrecisionData> precisionData)
109 : model(precisionData)
110 {
111 }
112
114 lager::cursor<int> brushType;
115};
116
118 KisAutoBrushModel *autoBrushModel,
119 KisPredefinedBrushModel *predefinedBrushModel,
120 KisTextBrushModel *textBrushModel,
121 lager::cursor<BrushType> brushType,
122 lager::cursor<PrecisionData> precisionData,
123 KisBrushOptionWidgetFlags flags,
124 QWidget *parent)
125 : QWidget(parent)
126 , m_currentBrushWidget(0)
127 , m_d(new Private(precisionData))
128{
129 uiWdgBrushChooser.setupUi(this);
130
131 m_buttonGroup = new QButtonGroup(this);
132 m_buttonGroup->setExclusive(true);
133 m_layout = new QGridLayout(uiWdgBrushChooser.settingsFrame);
134
135 m_stackedWidget = new QStackedWidget(this);
136 m_layout->addWidget(m_stackedWidget);
137
138 m_autoBrushWidget = new KisAutoBrushWidget(maxBrushSize, autoBrushModel, this, "autobrush");
139 addChooser(i18nc("Autobrush Brush tip mode", "Auto"), m_autoBrushWidget, AUTOBRUSH, KoGroupButton::GroupLeft);
140 m_predefinedBrushWidget = new KisPredefinedBrushChooser(maxBrushSize, predefinedBrushModel, this);
141 addChooser(i18nc("Predefined Brush tip mode", "Predefined"), m_predefinedBrushWidget, PREDEFINEDBRUSH, KoGroupButton::GroupCenter);
142
143 m_textBrushWidget = new KisTextBrushChooser(textBrushModel, this);
144 addChooser(i18nc("Text Brush tip mode", "Text"), m_textBrushWidget, TEXTBRUSH, KoGroupButton::GroupRight);
145
146 m_d->brushType = brushType.zoom(kislager::lenses::do_static_cast<BrushType, int>);
147
148 m_d->brushType.bind([this](int value) {m_stackedWidget->setCurrentIndex(value); });
149 m_d->brushType.bind([this](int value) {m_buttonGroup->button(value)->setChecked(true); });
150 connect(m_buttonGroup, &QButtonGroup::idClicked, [this] (int id) {m_d->brushType.set(id);});
151
152
153 Q_FOREACH (QWidget *widget, m_chooserMap.values()) {
154 m_minimumSize = m_minimumSize.expandedTo(widget->sizeHint());
155 }
156
157
159
160 uiWdgBrushChooser.sliderPrecision->setRange(1, 5);
161 uiWdgBrushChooser.sliderPrecision->setSingleStep(1);
162 uiWdgBrushChooser.sliderPrecision->setPageStep(1);
163
164
166 connectControl(uiWdgBrushChooser.sliderPrecision, &m_d->model, "precisionLevel");
167 connectControl(uiWdgBrushChooser.autoPrecisionCheckBox, &m_d->model, "useAutoPrecision");
168 connect(&m_d->model, &PrecisionModel::precisionToolTipChanged,
169 uiWdgBrushChooser.sliderPrecision, &KisSliderSpinBox::setToolTip);
170
171 connect(&m_d->model, &PrecisionModel::useAutoPrecisionChanged,
172 uiWdgBrushChooser.sliderPrecision, &KisSliderSpinBox::setDisabled);
173 connect(&m_d->model, &PrecisionModel::useAutoPrecisionChanged,
174 uiWdgBrushChooser.lblPrecision, &KisSliderSpinBox::setDisabled);
175 } else {
176 uiWdgBrushChooser.sliderPrecision->setVisible(false);
177 uiWdgBrushChooser.autoPrecisionCheckBox->setVisible(false);
178 uiWdgBrushChooser.lblPrecision->setVisible(false);
179 }
180}
181
182
186
188{
189 KisBrushSP theBrush;
190
191 // Fallback to auto brush if no brush selected
192 // Can happen if there is no predefined brush found
193 if (!theBrush)
194 theBrush = m_autoBrushWidget->brush();
195
196 return theBrush;
197
198}
199
201{
202 Q_FOREACH(const QString &option, options) {
203 QStringList l = option.split("/");
204 if (l.count() != 2) {
205 continue;
206 }
207 QObject *o = 0;
208 if (l[0] == "KisAutoBrushWidget") {
209 o = m_autoBrushWidget->findChild<QObject*>(l[1]);
210 }
211 else if (l[0] == "KisBrushChooser") {
212 o = m_predefinedBrushWidget->findChild<QObject*>(l[1]);
213 }
214 else if (l[0] == "KisTextBrushChooser") {
215 o = m_textBrushWidget->findChild<QObject*>(l[1]);
216 }
217 else {
218 qWarning() << "KisBrushSelectionWidget: Invalid option given to disable:" << option;
219 }
220
221 if (o) {
222 QWidget *w = qobject_cast<QWidget*>(o);
223 if (w) {
224 w->setVisible(false);
225 }
226 o = 0;
227 }
228 }
229}
230
232{
233 return lager::with(m_d->brushType.xform(kiszug::map_equal<int>(Predefined)),
235 .map(std::logical_and{});
236}
237
239{
240 return;
241
242 if (widget == m_currentBrushWidget) return;
243
245 m_layout->removeWidget(m_currentBrushWidget);
246 m_currentBrushWidget->setParent(this);
247 m_currentBrushWidget->hide();
248 }
249 widget->setMinimumSize(m_minimumSize);
250
251 m_currentBrushWidget = widget;
252 m_layout->addWidget(widget);
253
254 m_currentBrushWidget->show();
255 m_buttonGroup->button(m_chooserMap.key(widget))->setChecked(true);
256}
257
258void KisBrushSelectionWidget::addChooser(const QString& text, QWidget* widget, int id, KoGroupButton::GroupPosition pos)
259{
261 button->setGroupPosition(pos);
262 button->setText(text);
263 button->setAutoRaise(false);
264 button->setCheckable(true);
265 uiWdgBrushChooser.brushChooserButtonLayout->addWidget(button);
266 m_buttonGroup->addButton(button, id);
267
268 m_stackedWidget->insertWidget(id, widget);
269}
270
271#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)
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)