Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_selection_options.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2005 Boudewijn Rempt <boud@valdyas.org>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QCheckBox>
10#include <QToolButton>
11
12#include <kis_icon.h>
13#include "kis_config.h"
14#include "kis_config_notifier.h"
15#include "kis_paint_device.h"
16
17#include <ksharedconfig.h>
18#include <kconfiggroup.h>
19
21#include <KoGroupButton.h>
23#include <kis_slider_spin_box.h>
24
26{
27public:
31 QCheckBox *checkBoxMoveSelectedContent{nullptr};
32 QCheckBox *checkBoxAntiAliasSelection{nullptr};
34 QToolButton *buttonStopGrowingAtDarkestPixel {nullptr};
38 QCheckBox* checkBoxSelectionActionsPanel{nullptr};
39
41 {
42 return mode == PIXEL_SELECTION ? 0 : 1;
43 }
44
46 {
47 return index == 0 ? PIXEL_SELECTION : SHAPE_PROTECTION;
48 }
49
51 {
52 switch (action) {
54 return 0;
56 return 1;
57 case SELECTION_ADD:
58 return 2;
60 return 3;
62 return 4;
63 default:
64 return 0;
65 }
66 }
67
69 {
70 switch (index) {
71 case 0:
72 return SELECTION_REPLACE;
73 case 1:
75 case 2:
76 return SELECTION_ADD;
77 case 3:
78 return SELECTION_SUBTRACT;
79 case 4:
81 default:
82 return SELECTION_REPLACE;
83 }
84 }
85
87 {
88 switch (action) {
89 case CurrentLayer:
90 return 0;
91 case AllLayers:
92 return 1;
94 return 2;
95 default:
96 return 0;
97 }
98 }
99
101 {
102 switch (index) {
103 case 0:
104 return CurrentLayer;
105 case 1:
106 return AllLayers;
107 case 2:
108 return ColorLabeledLayers;
109 default:
110 return CurrentLayer;
111 }
112 }
113
114 void on_optionButtonStripMode_buttonToggled(int index, bool checked)
115 {
116 if (!checked) {
117 return;
118 }
119 const SelectionMode mode = buttonIndexToMode(index);
121 Q_EMIT q->modeChanged(mode);
122 }
123
124 void on_optionButtonStripAction_buttonToggled(int index, bool checked)
125 {
126 if (!checked) {
127 return;
128 }
129 Q_EMIT q->actionChanged(buttonIndexToAction(index));
130 }
131
133 {
134 if (!checked) {
135 return;
136 }
139 KisOptionCollectionWidgetWithHeader *sectionReference =
141 "sectionReference");
142 sectionReference->setWidgetVisible("widgetLabels",
145
147 }
148};
149
152 , m_d(new Private)
153{
154 m_d->q = this;
155 // Create widgets
156 m_d->optionButtonStripMode = new KisOptionButtonStrip;
157 m_d->optionButtonStripMode->addButton(
158 KisIconUtils::loadIcon("select-pixel"));
159 m_d->optionButtonStripMode->addButton(
160 KisIconUtils::loadIcon("select-shape"));
161 m_d->optionButtonStripMode->button(0)->setChecked(true);
162
163 m_d->optionButtonStripAction = new KisOptionButtonStrip;
164 m_d->optionButtonStripAction->addButton(
165 KisIconUtils::loadIcon("selection_replace"));
166 m_d->optionButtonStripAction->addButton(
167 KisIconUtils::loadIcon("selection_intersect"));
168 m_d->optionButtonStripAction->addButton(
169 KisIconUtils::loadIcon("selection_add"));
170 m_d->optionButtonStripAction->addButton(
171 KisIconUtils::loadIcon("selection_subtract"));
172 m_d->optionButtonStripAction->addButton(
173 KisIconUtils::loadIcon("selection_symmetric_difference"));
174 m_d->optionButtonStripAction->button(0)->setChecked(true);
175
176 m_d->checkBoxSelectionActionsPanel = new QCheckBox(i18n("Enable Selection Actions Bar"));
177 m_d->checkBoxSelectionActionsPanel->setToolTip(
178 i18n("When enabled, any selections will produce a small floating panel of useful selection-related actions."));
179
180 KisConfig cfg(true);
181
182 if (cfg.selectionActionBar()) {
183 m_d->checkBoxSelectionActionsPanel->setCheckState(Qt::CheckState::Checked);
184 } else {
185 m_d->checkBoxSelectionActionsPanel->setCheckState(Qt::CheckState::Unchecked);
186 }
187
188 m_d->checkBoxMoveSelectedContent = new QCheckBox(
189 i18nc("The move-selected-content checkbox in selection tool options",
190 "Move Selected Content"));
191
192 m_d->checkBoxAntiAliasSelection = new QCheckBox(
193 i18nc("The anti-alias checkbox in fill tool options", "Anti-aliasing"));
194 KisOptionCollectionWidget *containerGrowSelection = new KisOptionCollectionWidget;
195 m_d->sliderGrowSelection = new KisSliderSpinBox;
196 m_d->sliderGrowSelection->setPrefix(
197 i18nc("The 'grow/shrink' spinbox prefix in selection tools options",
198 "Grow: "));
199 m_d->sliderGrowSelection->setRange(-400, 400);
200 m_d->sliderGrowSelection->setSoftRange(-40, 40);
201 m_d->sliderGrowSelection->setSuffix(i18n(" px"));
202 m_d->buttonStopGrowingAtDarkestPixel = new QToolButton;
203 m_d->buttonStopGrowingAtDarkestPixel->setAutoRaise(true);
204 m_d->buttonStopGrowingAtDarkestPixel->setCheckable(true);
205 m_d->buttonStopGrowingAtDarkestPixel->setIcon(KisIconUtils::loadIcon("stop-at-boundary"));
206 containerGrowSelection->appendWidget("sliderGrowSelection", m_d->sliderGrowSelection);
207 containerGrowSelection->appendWidget("buttonStopGrowingAtDarkestPixel", m_d->buttonStopGrowingAtDarkestPixel);
208 containerGrowSelection->setOrientation(Qt::Horizontal);
209 containerGrowSelection->setWidgetVisible("buttonStopGrowingAtDarkestPixel", false);
210 m_d->sliderFeatherSelection = new KisSliderSpinBox;
211 m_d->sliderFeatherSelection->setPrefix(
212 i18nc("The 'feather' spinbox prefix in selection tools options",
213 "Feather: "));
214 m_d->sliderFeatherSelection->setRange(0, 400);
215 m_d->sliderFeatherSelection->setSoftRange(0, 40);
216 m_d->sliderFeatherSelection->setSuffix(i18n(" px"));
217
218 m_d->optionButtonStripReference = new KisOptionButtonStrip;
219 m_d->optionButtonStripReference->addButton(
220 KisIconUtils::loadIcon("current-layer"));
221 m_d->optionButtonStripReference->addButton(
222 KisIconUtils::loadIcon("all-layers"));
223 m_d->optionButtonStripReference->addButton(KisIconUtils::loadIcon("tag"));
224 m_d->optionButtonStripReference->button(0)->setChecked(true);
225 m_d->widgetLabels = new KisColorLabelSelectorWidget;
226 m_d->widgetLabels->setExclusive(false);
227 m_d->widgetLabels->setButtonSize(20);
228 m_d->widgetLabels->setButtonWrapEnabled(true);
229 m_d->widgetLabels->setMouseDragEnabled(true);
230
231 // Set the tooltips
232 m_d->optionButtonStripMode->button(0)->setToolTip(
233 i18nc("@info:tooltip", "Pixel Selection"));
234 m_d->optionButtonStripMode->button(1)->setToolTip(
235 i18nc("@info:tooltip", "Vector Selection"));
236
237 m_d->optionButtonStripAction->button(0)->setToolTip(
238 i18nc("@info:tooltip", "Replace"));
239 m_d->optionButtonStripAction->button(1)->setToolTip(
240 i18nc("@info:tooltip", "Intersect"));
241 m_d->optionButtonStripAction->button(2)->setToolTip(
242 i18nc("@info:tooltip", "Add"));
243 m_d->optionButtonStripAction->button(3)->setToolTip(
244 i18nc("@info:tooltip", "Subtract"));
245 m_d->optionButtonStripAction->button(4)->setToolTip(
246 i18nc("@info:tooltip", "Symmetric Difference"));
247
248 m_d->checkBoxMoveSelectedContent->setToolTip(
249 i18nc("@info:tooltip", "Move Selected Content"));
250
251 m_d->checkBoxAntiAliasSelection->setToolTip(
252 i18n("Smooths the edges of the selection"));
253 m_d->sliderGrowSelection->setToolTip(
254 i18n("Grow or shrink the selection by the set amount"));
255 m_d->buttonStopGrowingAtDarkestPixel->setToolTip(
256 i18n("Stop growing at the darkest and/or most opaque pixels"));
257 m_d->sliderFeatherSelection->setToolTip(
258 i18n("Blur the selection by the set amount"));
259
260 m_d->optionButtonStripReference->button(0)->setToolTip(
261 i18n("Select regions found from the active layer"));
262 m_d->optionButtonStripReference->button(1)->setToolTip(
263 i18n("Select regions found from the merging of all layers"));
264 m_d->optionButtonStripReference->button(2)->setToolTip(
265 i18n("Select regions found from the merging of layers with specific color labels"));
266
267 // Construct the option widget
269
272 i18nc("The 'mode' section label in selection tools options",
273 "Mode"));
274 sectionMode->setPrimaryWidget(m_d->optionButtonStripMode);
275 appendWidget("sectionMode", sectionMode);
276
279 i18nc("The 'action' section label in selection tools options",
280 "Action"));
281 sectionAction->setPrimaryWidget(m_d->optionButtonStripAction);
282 appendWidget("sectionAction", sectionAction);
283
284 KisOptionCollectionWidgetWithHeader *sectionReference =
286 i18nc("The 'reference' section label in selection tools options",
287 "Reference"));
288 sectionReference->setPrimaryWidget(m_d->optionButtonStripReference);
289 sectionReference->appendWidget("widgetLabels", m_d->widgetLabels);
290 sectionReference->setWidgetVisible("widgetLabels", false);
291 appendWidget("sectionReference", sectionReference);
292
293
294 appendWidget("checkBoxMoveSelectedContent", m_d->checkBoxMoveSelectedContent);
295 appendWidget("sapCheckBox", m_d->checkBoxSelectionActionsPanel);
296
297 KisOptionCollectionWidgetWithHeader *sectionAdjustments =
299 i18nc("The 'adjustments' section label in selection tools options",
300 "Adjustments"));
301 sectionAdjustments->appendWidget("checkBoxAntiAliasSelection",
302 m_d->checkBoxAntiAliasSelection);
303 sectionAdjustments->appendWidget("containerGrowSelection", containerGrowSelection);
304 sectionAdjustments->appendWidget("sliderFeather",
305 m_d->sliderFeatherSelection);
306 appendWidget("sectionAdjustments", sectionAdjustments);
307
308
309 // Make connections
310 connect(m_d->optionButtonStripMode,
311 QOverload<int, bool>::of(&KisOptionButtonStrip::buttonToggled),
312 [this](int i, int c) {
313 m_d->on_optionButtonStripMode_buttonToggled(i, c);
314 });
315 connect(m_d->optionButtonStripAction,
316 QOverload<int, bool>::of(&KisOptionButtonStrip::buttonToggled),
317 [this](int i, int c) {
318 m_d->on_optionButtonStripAction_buttonToggled(i, c);
319 });
320 connect(m_d->checkBoxMoveSelectedContent,
321 SIGNAL(toggled(bool)),
322 SIGNAL(moveSelectedContentChanged(bool)));
323 connect(m_d->checkBoxAntiAliasSelection,
324 SIGNAL(toggled(bool)),
325 SIGNAL(antiAliasSelectionChanged(bool)));
326 connect(m_d->sliderGrowSelection,
327 SIGNAL(valueChanged(int)),
328 SIGNAL(growSelectionChanged(int)));
329 connect(m_d->buttonStopGrowingAtDarkestPixel,
330 SIGNAL(toggled(bool)),
332 connect(m_d->sliderFeatherSelection,
333 SIGNAL(valueChanged(int)),
334 SIGNAL(featherSelectionChanged(int)));
335 connect(m_d->optionButtonStripReference,
336 QOverload<int, bool>::of(&KisOptionButtonStrip::buttonToggled),
337 [this](int i, int c) {
338 m_d->on_optionButtonStripReference_buttonToggled(i, c);
339 });
340 connect(m_d->widgetLabels,
341 SIGNAL(selectionChanged()),
343
344 connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
345 connect(m_d->checkBoxSelectionActionsPanel,
346 SIGNAL(toggled(bool)),
348}
349
353
355{
356 return m_d->buttonIndexToMode(
357 m_d->optionButtonStripMode->checkedButtonIndex());
358}
359
361{
362 return m_d->buttonIndexToAction(
363 m_d->optionButtonStripAction->checkedButtonIndex());
364}
365
367{
368 return m_d->checkBoxMoveSelectedContent->isChecked();
369}
370
372{
373 return m_d->checkBoxAntiAliasSelection->isChecked();
374}
375
377{
378 return m_d->sliderGrowSelection->value();
379}
380
382{
383 return m_d->buttonStopGrowingAtDarkestPixel->isChecked();
384}
385
387{
388 return m_d->sliderFeatherSelection->value();
389}
390
393{
394 return m_d->buttonIndexToReferenceLayers(
395 m_d->optionButtonStripReference->checkedButtonIndex());
396}
397
399{
400 return m_d->widgetLabels->selection();
401}
402
404{
406 m_d->optionButtonStripMode->button(m_d->modeToButtonIndex(newMode));
408
409 button->setChecked(true);
410}
411
413{
414 KoGroupButton *button = m_d->optionButtonStripAction->button(
415 m_d->actionToButtonIndex(newAction));
417
418 button->setChecked(true);
419}
420
421void KisSelectionOptions::setMoveSelectedContent(bool newMoveSelectedContent)
422{
423 m_d->checkBoxMoveSelectedContent->setChecked(newMoveSelectedContent);
424}
425
426void KisSelectionOptions::setAntiAliasSelection(bool newAntiAliasSelection)
427{
428 m_d->checkBoxAntiAliasSelection->setChecked(newAntiAliasSelection);
429}
430
432{
433 m_d->sliderGrowSelection->setValue(newGrowSelection);
434}
435
436void KisSelectionOptions::setStopGrowingAtDarkestPixel(bool newStopGrowingAtDarkestPixel)
437{
438 m_d->buttonStopGrowingAtDarkestPixel->setChecked(newStopGrowingAtDarkestPixel);
439}
440
441void KisSelectionOptions::setFeatherSelection(int newFeatherSelection)
442{
443 m_d->sliderFeatherSelection->setValue(newFeatherSelection);
444}
445
447{
448 KoGroupButton *button = m_d->optionButtonStripReference->button(
449 m_d->referenceLayersToButtonIndex(newReferenceLayers));
451
452 button->setChecked(true);
453}
454
456 const QList<int> &newSelectedColorLabels)
457{
458 m_d->widgetLabels->setSelection(newSelectedColorLabels);
459}
460
462{
463 setWidgetVisible("sectionMode", visible);
464}
465
467{
468 setWidgetVisible("sectionAction", visible);
469}
470
472{
473 widgetAs<KisOptionCollectionWidgetWithHeader*>("sectionAdjustments")
474 ->widgetAs<KisOptionCollectionWidget*>("containerGrowSelection")
475 ->setWidgetVisible("buttonStopGrowingAtDarkestPixel", visible);
476}
477
479{
480 setWidgetVisible("sectionAdjustments", visible);
481}
482
484{
485 setWidgetVisible("sectionReference", visible);
486}
487
489 SelectionAction action,
490 const QKeySequence &shortcut)
491{
492 const QString shortcutString = shortcut.toString(QKeySequence::NativeText);
493 QString toolTipText;
494 const int buttonIndex = m_d->actionToButtonIndex(action);
495
496 switch (action) {
499 toolTipText = shortcutString.isEmpty()
500 ? i18nc("@info:tooltip", "Replace")
501 : i18nc("@info:tooltip", "Replace (%1)", shortcutString);
502 break;
503 case SELECTION_ADD:
504 toolTipText = shortcutString.isEmpty()
505 ? i18nc("@info:tooltip", "Add")
506 : i18nc("@info:tooltip", "Add (%1)", shortcutString);
507 break;
509 toolTipText = shortcutString.isEmpty()
510 ? i18nc("@info:tooltip", "Subtract")
511 : i18nc("@info:tooltip", "Subtract (%1)", shortcutString);
512 break;
514 toolTipText = shortcutString.isEmpty()
515 ? i18nc("@info:tooltip", "Intersect")
516 : i18nc("@info:tooltip", "Intersect (%1)", shortcutString);
517 break;
519 toolTipText = shortcutString.isEmpty()
520 ? i18nc("@info:tooltip", "Symmetric Difference")
521 : i18nc("@info:tooltip",
522 "Symmetric Difference (%1)",
523 shortcutString);
524 break;
525 }
526
527 m_d->optionButtonStripAction->button(buttonIndex)->setToolTip(toolTipText);
528}
529
531{
532 KisConfig cfg(true);
533
534 if (cfg.selectionActionBar()) {
535 m_d->checkBoxSelectionActionsPanel->setCheckState(Qt::Checked);
536 } else {
537 m_d->checkBoxSelectionActionsPanel->setCheckState(Qt::Unchecked);
538 }
539}
540
542{
543 KisConfig cfg(false);
545
546 blockSignals(true);
548 blockSignals(false);
549}
float value(const T *src, size_t ch)
SelectionMode
@ PIXEL_SELECTION
@ SHAPE_PROTECTION
SelectionAction
@ SELECTION_REPLACE
@ SELECTION_INTERSECT
@ SELECTION_SYMMETRICDIFFERENCE
@ SELECTION_DEFAULT
@ SELECTION_SUBTRACT
@ SELECTION_ADD
void setExclusive(bool exclusive)
Set if the button selection is mutually exclusive. This allows switching between single or multiple s...
static KisConfigNotifier * instance()
bool selectionActionBar(bool defaultValue=false) const
void setSelectionActionBar(bool value)
Provides a list of consecutive tool buttons.
void buttonToggled(KoGroupButton *button, bool checked)
KoGroupButton * addButton(const QIcon &icon, const QString &text=QString())
Wrapper class around a KisOptionCollectionWidget that also provide a header with a title label and an...
void setPrimaryWidget(QWidget *widget)
Set the primary widget. The list widget takes ownership of it.
void appendWidget(const QString &id, QWidget *widget)
Insert the given widget with the given id at the end of the list. The list widget takes ownership of ...
void setWidgetVisible(int index, bool visible)
Set the visibility of the widget that is at the given position.
Class providing a list of widgets with some addons such as separators, orientation or individual widg...
T widgetAs(int index) const
Get the widget that is at the given position casted to some other class.
void setOrientation(Qt::Orientation orientation, bool recursive=false)
Set the orientation of the list of widgets.
KisOptionCollectionWidget(QWidget *parent=nullptr)
void setWidgetVisible(int index, bool visible)
Set the visibility of the widget that is at the given position. Use this function instead of the widg...
void appendWidget(const QString &id, QWidget *widget)
Insert the given widget with the given id at the end of the list. The list widget takes ownership of ...
void setSeparatorsVisible(bool visible)
Set the visibility of the separators.
void on_optionButtonStripAction_buttonToggled(int index, bool checked)
SelectionAction buttonIndexToAction(int index) const
KisOptionButtonStrip * optionButtonStripReference
KisColorLabelSelectorWidget * widgetLabels
ReferenceLayers buttonIndexToReferenceLayers(int index) const
void on_optionButtonStripReference_buttonToggled(int index, bool checked)
int modeToButtonIndex(SelectionMode mode) const
KisOptionButtonStrip * optionButtonStripAction
int referenceLayersToButtonIndex(ReferenceLayers action) const
void on_optionButtonStripMode_buttonToggled(int index, bool checked)
SelectionMode buttonIndexToMode(int index) const
KisOptionButtonStrip * optionButtonStripMode
int actionToButtonIndex(SelectionAction action) const
void updateActionButtonToolTip(SelectionAction action, const QKeySequence &shortcut)
void setStopGrowingAtDarkestPixelButtonVisible(bool visible)
KisSelectionOptions(QWidget *parent=nullptr)
void setModeSectionVisible(bool visible)
void setAdjustmentsSectionVisible(bool visible)
void setMode(SelectionMode newMode)
void setGrowSelection(int newGrowSelection)
void setAntiAliasSelection(bool newAntiAliasSelection)
void slotSelectionActionsPanelCheckboxToggled(bool value)
void actionChanged(SelectionAction action)
void antiAliasSelectionChanged(bool antiAliasSelection)
void setAction(SelectionAction newAction)
void setMoveSelectedContent(bool newMoveSelectedContent)
SelectionMode mode() const
void setSelectedColorLabels(const QList< int > &newSelectedColorLabels)
void featherSelectionChanged(int featherSelection)
void setReferenceLayers(ReferenceLayers newReferenceLayers)
void selectedColorLabelsChanged()
void setFeatherSelection(int newFeatherSelection)
QList< int > selectedColorLabels() const
void setReferenceSectionVisible(bool visible)
ReferenceLayers referenceLayers() const
void referenceLayersChanged(ReferenceLayers referenceLayers)
QScopedPointer< Private > m_d
void setActionSectionVisible(bool visible)
void stopGrowingAtDarkestPixelChanged(bool stopGrowingAtDarkestPixel)
void growSelectionChanged(int growSelection)
void setStopGrowingAtDarkestPixel(bool newStopGrowingAtDarkestPixel)
SelectionAction action() const
void modeChanged(SelectionMode mode)
void moveSelectedContentChanged(bool moveSelectedContent)
This class is a spinbox in which you can click and drag to set the value. A slider like bar is displa...
void setRange(int newMinimum, int newMaximum, bool computeNewFastSliderStep=true)
Set the minimum and the maximum values of the range, computing a new "fast slider step" based on the ...
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
QString button(const QWheelEvent &ev)
QIcon loadIcon(const QString &name)