1 /*
2 * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "kis_selection_options.h"
20
21 #include <QWidget>
22 #include <QRadioButton>
23 #include <QComboBox>
24 #include <QVBoxLayout>
25 #include <QLayout>
26 #include <QButtonGroup>
27
28 #include <kis_icon.h>
29 #include "kis_types.h"
30 #include "kis_layer.h"
31 #include "kis_image.h"
32 #include "kis_selection.h"
33 #include "kis_paint_device.h"
34 #include "canvas/kis_canvas2.h"
35 #include "KisViewManager.h"
36 #include "kis_signal_compressor.h"
37 #include "kis_shape_controller.h"
38 #include "kis_canvas2.h"
39 #include "KisDocument.h"
40 #include "kis_dummies_facade_base.h"
41
42 #include <ksharedconfig.h>
43 #include <kconfiggroup.h>
44
KisSelectionOptions(KisCanvas2 *)45 KisSelectionOptions::KisSelectionOptions(KisCanvas2 * /*canvas*/)
46 : m_colorLabelsCompressor(900, KisSignalCompressor::FIRST_INACTIVE)
47 {
48 m_page = new WdgSelectionOptions(this);
49 Q_CHECK_PTR(m_page);
50
51 QVBoxLayout * l = new QVBoxLayout(this);
52 l->addWidget(m_page);
53 l->addSpacerItem(new QSpacerItem(0,0, QSizePolicy::Preferred, QSizePolicy::Expanding));
54 l->setContentsMargins(0,0,0,0);
55
56 m_mode = new QButtonGroup(this);
57 m_mode->addButton(m_page->pixel, PIXEL_SELECTION);
58 m_mode->addButton(m_page->shape, SHAPE_PROTECTION);
59
60 m_action = new QButtonGroup(this);
61 m_action->addButton(m_page->add, SELECTION_ADD);
62 m_action->addButton(m_page->subtract, SELECTION_SUBTRACT);
63 m_action->addButton(m_page->replace, SELECTION_REPLACE);
64 m_action->addButton(m_page->intersect, SELECTION_INTERSECT);
65 m_action->addButton(m_page->symmetricdifference, SELECTION_SYMMETRICDIFFERENCE);
66
67 m_page->pixel->setGroupPosition(KoGroupButton::GroupLeft);
68 m_page->shape->setGroupPosition(KoGroupButton::GroupRight);
69 m_page->pixel->setIcon(KisIconUtils::loadIcon("select_pixel"));
70 m_page->shape->setIcon(KisIconUtils::loadIcon("select_shape"));
71
72 m_page->add->setGroupPosition(KoGroupButton::GroupCenter);
73 m_page->subtract->setGroupPosition(KoGroupButton::GroupCenter);
74 m_page->replace->setGroupPosition(KoGroupButton::GroupLeft);
75 m_page->intersect->setGroupPosition(KoGroupButton::GroupCenter);
76 m_page->symmetricdifference->setGroupPosition(KoGroupButton::GroupRight);
77 m_page->add->setIcon(KisIconUtils::loadIcon("selection_add"));
78 m_page->subtract->setIcon(KisIconUtils::loadIcon("selection_subtract"));
79 m_page->replace->setIcon(KisIconUtils::loadIcon("selection_replace"));
80 m_page->intersect->setIcon(KisIconUtils::loadIcon("selection_intersect"));
81 m_page->symmetricdifference->setIcon(KisIconUtils::loadIcon("selection_symmetric_difference"));
82
83 m_page->cmbSampleLayersMode->addItem(sampleLayerModeToUserString(SAMPLE_LAYERS_MODE_CURRENT), SAMPLE_LAYERS_MODE_CURRENT);
84 m_page->cmbSampleLayersMode->addItem(sampleLayerModeToUserString(SAMPLE_LAYERS_MODE_ALL), SAMPLE_LAYERS_MODE_ALL);
85 m_page->cmbSampleLayersMode->addItem(sampleLayerModeToUserString(SAMPLE_LAYERS_MODE_COLOR_LABELED), SAMPLE_LAYERS_MODE_COLOR_LABELED);
86 m_page->cmbSampleLayersMode->setEditable(false);
87
88 m_page->cmbColorLabels->setModes(false, false);
89
90 connect(m_mode, SIGNAL(buttonClicked(int)), this, SIGNAL(modeChanged(int)));
91 connect(m_action, SIGNAL(buttonClicked(int)), this, SIGNAL(actionChanged(int)));
92 connect(m_mode, SIGNAL(buttonClicked(int)), this, SLOT(hideActionsForSelectionMode(int)));
93 connect(m_page->chkAntiAliasing, SIGNAL(toggled(bool)), this, SIGNAL(antiAliasSelectionChanged(bool)));
94 connect(m_page->cmbColorLabels, SIGNAL(selectedColorsChanged()), this, SIGNAL(selectedColorLabelsChanged()));
95 connect(m_page->cmbSampleLayersMode, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSampleLayersModeChanged(int)));
96
97 KConfigGroup cfg = KSharedConfig::openConfig()->group("KisToolSelectBase");
98 m_page->chkAntiAliasing->setChecked(cfg.readEntry("antiAliasSelection", true));
99
100 connect(&m_colorLabelsCompressor, SIGNAL(timeout()), this, SLOT(slotUpdateAvailableColorLabels()));
101 }
102
~KisSelectionOptions()103 KisSelectionOptions::~KisSelectionOptions()
104 {
105 }
106
action()107 int KisSelectionOptions::action()
108 {
109 return m_action->checkedId();
110 }
111
setAction(int action)112 void KisSelectionOptions::setAction(int action) {
113 QAbstractButton* button = m_action->button(action);
114 KIS_SAFE_ASSERT_RECOVER_RETURN(button);
115
116 button->setChecked(true);
117 }
118
setMode(int mode)119 void KisSelectionOptions::setMode(int mode) {
120 QAbstractButton* button = m_mode->button(mode);
121 KIS_SAFE_ASSERT_RECOVER_RETURN(button);
122
123 button->setChecked(true);
124 hideActionsForSelectionMode(mode);
125 }
126
setAntiAliasSelection(bool value)127 void KisSelectionOptions::setAntiAliasSelection(bool value)
128 {
129 m_page->chkAntiAliasing->setChecked(value);
130 }
131
setSampleLayersMode(QString mode)132 void KisSelectionOptions::setSampleLayersMode(QString mode)
133 {
134 if (mode != SAMPLE_LAYERS_MODE_ALL && mode != SAMPLE_LAYERS_MODE_COLOR_LABELED && mode != SAMPLE_LAYERS_MODE_CURRENT) {
135 mode = SAMPLE_LAYERS_MODE_CURRENT;
136 }
137 setCmbSampleLayersMode(mode);
138 }
139
enablePixelOnlySelectionMode()140 void KisSelectionOptions::enablePixelOnlySelectionMode()
141 {
142 setMode(PIXEL_SELECTION);
143 disableSelectionModeOption();
144 }
145
setColorLabelsEnabled(bool enabled)146 void KisSelectionOptions::setColorLabelsEnabled(bool enabled)
147 {
148 if (enabled) {
149 m_page->cmbColorLabels->show();
150 m_page->cmbSampleLayersMode->show();
151 } else {
152 m_page->cmbColorLabels->hide();
153 m_page->cmbSampleLayersMode->hide();
154 }
155 }
156
updateActionButtonToolTip(int action,const QKeySequence & shortcut)157 void KisSelectionOptions::updateActionButtonToolTip(int action, const QKeySequence &shortcut)
158 {
159 const QString shortcutString = shortcut.toString(QKeySequence::NativeText);
160 QString toolTipText;
161 switch ((SelectionAction)action) {
162 case SELECTION_DEFAULT:
163 case SELECTION_REPLACE:
164 toolTipText = shortcutString.isEmpty() ?
165 i18nc("@info:tooltip", "Replace") :
166 i18nc("@info:tooltip", "Replace (%1)", shortcutString);
167
168 m_action->button(SELECTION_REPLACE)->setToolTip(toolTipText);
169 break;
170 case SELECTION_ADD:
171 toolTipText = shortcutString.isEmpty() ?
172 i18nc("@info:tooltip", "Add") :
173 i18nc("@info:tooltip", "Add (%1)", shortcutString);
174
175 m_action->button(SELECTION_ADD)->setToolTip(toolTipText);
176 break;
177 case SELECTION_SUBTRACT:
178 toolTipText = shortcutString.isEmpty() ?
179 i18nc("@info:tooltip", "Subtract") :
180 i18nc("@info:tooltip", "Subtract (%1)", shortcutString);
181
182 m_action->button(SELECTION_SUBTRACT)->setToolTip(toolTipText);
183
184 break;
185 case SELECTION_INTERSECT:
186 toolTipText = shortcutString.isEmpty() ?
187 i18nc("@info:tooltip", "Intersect") :
188 i18nc("@info:tooltip", "Intersect (%1)", shortcutString);
189
190 m_action->button(SELECTION_INTERSECT)->setToolTip(toolTipText);
191
192 break;
193
194 case SELECTION_SYMMETRICDIFFERENCE:
195 toolTipText = shortcutString.isEmpty() ?
196 i18nc("@info:tooltip", "Symmetric Difference") :
197 i18nc("@info:tooltip", "Symmetric Difference (%1)", shortcutString);
198
199 m_action->button(SELECTION_SYMMETRICDIFFERENCE)->setToolTip(toolTipText);
200
201 break;
202 }
203 }
204
attachToImage(KisImageSP image,KisCanvas2 * canvas)205 void KisSelectionOptions::attachToImage(KisImageSP image, KisCanvas2* canvas)
206 {
207 m_image = image;
208 m_canvas = canvas;
209 activateConnectionToImage();
210 }
211
activateConnectionToImage()212 void KisSelectionOptions::activateConnectionToImage()
213 {
214 if (m_image && m_canvas) {
215 m_page->cmbColorLabels->updateAvailableLabels(m_image->root());
216 KIS_SAFE_ASSERT_RECOVER_RETURN(m_canvas);
217 KisDocument *doc = m_canvas->imageView()->document();
218
219 KisShapeController *kritaShapeController =
220 dynamic_cast<KisShapeController*>(doc->shapeController());
221 KisDummiesFacadeBase* m_dummiesFacade = static_cast<KisDummiesFacadeBase*>(kritaShapeController);
222 if (m_dummiesFacade) {
223 m_nodesUpdatesConnectionsStore.addConnection(m_dummiesFacade, SIGNAL(sigEndInsertDummy(KisNodeDummy*)),
224 &m_colorLabelsCompressor, SLOT(start()));
225 m_nodesUpdatesConnectionsStore.addConnection(m_dummiesFacade, SIGNAL(sigEndRemoveDummy()),
226 &m_colorLabelsCompressor, SLOT(start()));
227 m_nodesUpdatesConnectionsStore.addConnection(m_dummiesFacade, SIGNAL(sigDummyChanged(KisNodeDummy*)),
228 &m_colorLabelsCompressor, SLOT(start()));
229 }
230 }
231 }
232
deactivateConnectionToImage()233 void KisSelectionOptions::deactivateConnectionToImage()
234 {
235 m_nodesUpdatesConnectionsStore.clear();
236 }
237
238 //hide action buttons and antialiasing, if shape selection is active (actions currently don't work on shape selection)
hideActionsForSelectionMode(int mode)239 void KisSelectionOptions::hideActionsForSelectionMode(int mode) {
240 const bool isPixelSelection = (mode == (int)PIXEL_SELECTION);
241
242 m_page->chkAntiAliasing->setVisible(isPixelSelection);
243 }
244
slotUpdateAvailableColorLabels()245 void KisSelectionOptions::slotUpdateAvailableColorLabels()
246 {
247 if (m_image) {
248 m_page->cmbColorLabels->updateAvailableLabels(m_image->root());
249 }
250 }
251
slotSampleLayersModeChanged(int index)252 void KisSelectionOptions::slotSampleLayersModeChanged(int index)
253 {
254 QString newSampleLayersMode = m_page->cmbSampleLayersMode->itemData(index).toString();
255 m_page->cmbColorLabels->setEnabled(newSampleLayersMode == SAMPLE_LAYERS_MODE_COLOR_LABELED);
256 emit sampleLayersModeChanged(newSampleLayersMode);
257 }
258
sampleLayerModeToUserString(QString sampleLayersModeId)259 QString KisSelectionOptions::sampleLayerModeToUserString(QString sampleLayersModeId)
260 {
261 QString currentLayer = i18nc("Option in selection tool: take only the current layer into account when calculating the selection", "Current Layer");
262 if (sampleLayersModeId == SAMPLE_LAYERS_MODE_CURRENT) {
263 return currentLayer;
264 } else if (sampleLayersModeId == SAMPLE_LAYERS_MODE_ALL) {
265 return i18nc("Option in selection tool: take all layers (merged) into account when calculating the selection", "All Layers");
266 } else if (sampleLayersModeId == SAMPLE_LAYERS_MODE_COLOR_LABELED) {
267 return i18nc("Option in selection tool: take all layers that were marked with specific color labels (more precisely, all of them merged) "
268 "into account when calculating the selection", "Color Labeled Layers");
269 }
270
271 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(false, currentLayer);
272 return currentLayer;
273 }
274
setCmbSampleLayersMode(QString sampleLayersModeId)275 void KisSelectionOptions::setCmbSampleLayersMode(QString sampleLayersModeId)
276 {
277 for (int i = 0; i < m_page->cmbSampleLayersMode->count(); i++) {
278 if (m_page->cmbSampleLayersMode->itemData(i).toString() == sampleLayersModeId)
279 {
280 m_page->cmbSampleLayersMode->setCurrentIndex(i);
281 break;
282 }
283 }
284 m_page->cmbColorLabels->setEnabled(sampleLayersModeId == SAMPLE_LAYERS_MODE_COLOR_LABELED);
285 }
286
antiAliasSelection()287 bool KisSelectionOptions::antiAliasSelection()
288 {
289 return m_page->chkAntiAliasing->isChecked();
290 }
291
colorLabelsSelected()292 QList<int> KisSelectionOptions::colorLabelsSelected()
293 {
294 return m_page->cmbColorLabels->selectedColors();
295 }
296
sampleLayersMode()297 QString KisSelectionOptions::sampleLayersMode()
298 {
299 return m_page->cmbSampleLayersMode->currentData().toString();
300 }
301
disableAntiAliasSelectionOption()302 void KisSelectionOptions::disableAntiAliasSelectionOption()
303 {
304 m_page->chkAntiAliasing->hide();
305 disconnect(m_page->pixel, SIGNAL(clicked()), m_page->chkAntiAliasing, SLOT(show()));
306 }
307
disableSelectionModeOption()308 void KisSelectionOptions::disableSelectionModeOption()
309 {
310 m_page->lblMode->hide();
311 m_page->pixel->hide();
312 m_page->shape->hide();
313 }
314
315