Krita Source Code Documentation
Loading...
Searching...
No Matches
LayerBox.cpp
Go to the documentation of this file.
1/*
2 * LayerBox.cc - part of Krita aka Krayon aka KimageShop
3 *
4 * SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org>
5 * SPDX-FileCopyrightText: 2006 Gábor Lehel <illissius@gmail.com>
6 * SPDX-FileCopyrightText: 2007 Thomas Zander <zander@kde.org>
7 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
8 * SPDX-FileCopyrightText: 2011 José Luis Vergara <pentalis@gmail.com>
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13#include "LayerBox.h"
14
15#include <QApplication>
16#include <QToolButton>
17#include <QLayout>
18#include <QMouseEvent>
19#include <QPainter>
20#include <QPoint>
21#include <QRect>
22#include <QString>
23#include <QToolTip>
24#include <QWidget>
25#include <QComboBox>
26#include <QCheckBox>
27#include <QVBoxLayout>
28#include <QPixmap>
29#include <QBitmap>
30#include <QList>
31#include <QMenu>
32#include <QWidgetAction>
33#include <QProxyStyle>
34#include <QStyleFactory>
35
36#include <kis_debug.h>
37#include <klocalizedstring.h>
38
40
41#include <kis_icon.h>
42#include <KoColorSpace.h>
44#include <KisDocument.h>
45#include <kis_time_span.h>
46
47#include <kis_types.h>
48#include <kis_image.h>
49#include <kis_paint_device.h>
50#include <kis_layer.h>
51#include <kis_group_layer.h>
52#include <kis_mask.h>
53#include <kis_node.h>
54#include <kis_base_node.h>
58#include <KoProperties.h>
59
60#include <kis_action.h>
61#include "kis_action_manager.h"
63#include "kis_slider_spin_box.h"
64#include "KisViewManager.h"
65#include "kis_node_manager.h"
66#include "kis_node_model.h"
67#include <kis_clipboard.h>
68
69#include "canvas/kis_canvas2.h"
72#include "kis_selection_mask.h"
73#include "kis_config.h"
74#include "KisView.h"
75#include "krita_utils.h"
77#include "kis_signals_blocker.h"
81
82#include "kis_selection.h"
86#include "KisIdleTasksManager.h"
87
88#include "kis_layer_utils.h"
89
90#include "ui_WdgLayerBox.h"
91#include "NodeView.h"
92#include "SyncButtonAndAction.h"
94
95class LayerBoxStyle : public QProxyStyle
96{
97public:
98 LayerBoxStyle(QStyle *baseStyle = 0) : QProxyStyle(baseStyle) {}
99
100 void drawPrimitive(PrimitiveElement element,
101 const QStyleOption *option,
102 QPainter *painter,
103 const QWidget *widget) const override
104 {
105 if (element == QStyle::PE_IndicatorItemViewItemDrop)
106 {
107 QColor color(widget->palette().color(QPalette::Highlight).lighter());
108
109 if (option->rect.height() == 0) {
110 QBrush brush(color);
111
112 QRect r(option->rect);
113 r.setTop(r.top() - 2);
114 r.setBottom(r.bottom() + 2);
115
116 painter->fillRect(r, brush);
117 } else {
118 color.setAlpha(200);
119 QBrush brush(color);
120 painter->fillRect(option->rect, brush);
121 }
122 }
123 else
124 {
125 QProxyStyle::drawPrimitive(element, option, painter, widget);
126 }
127 }
128};
129
130inline void LayerBox::connectActionToButton(KisViewManager* viewManager, QAbstractButton *button, const QString &id)
131{
132 if (!viewManager || !button) return;
133
134 KisAction *action = viewManager->actionManager()->actionByName(id);
135
136 if (!action) return;
137
138 connect(button, SIGNAL(clicked()), action, SLOT(trigger()));
139 connect(action, SIGNAL(sigEnableSlaves(bool)), button, SLOT(setEnabled(bool)));
140 connect(viewManager->mainWindowAsQWidget(), SIGNAL(themeChanged()), this, SLOT(slotUpdateIcons()));
141}
142
143inline void LayerBox::addActionToMenu(QMenu *menu, const QString &id)
144{
145 if (m_canvas) {
146 menu->addAction(m_canvas->viewManager()->actionManager()->actionByName(id));
147 }
148}
149
150qint32 LayerBox::convertOpacityToInt(qreal opacity)
151{
157 return qMin(255, int(opacity * 2.55 + 0.5));
158}
159
161 : QDockWidget(i18n("Layers"))
162 , m_canvas(0)
163 , m_wdgLayerBox(new Ui_WdgLayerBox)
164 , m_colorLabelCompressor(500, KisSignalCompressor::FIRST_INACTIVE)
165 , m_thumbnailSizeCompressor(100, KisSignalCompressor::FIRST_INACTIVE)
166 , m_treeIndentationCompressor(100, KisSignalCompressor::FIRST_INACTIVE)
167 , m_infoTextOpacityCompressor(100, KisSignalCompressor::FIRST_INACTIVE)
168 , m_nodeOpacityCompressor(200, KisSignalCompressor::FIRST_INACTIVE)
169{
170 KisConfig cfg(false);
171
172 QWidget* mainWidget = new QWidget(this);
173 setWidget(mainWidget);
174
175 m_wdgLayerBox->setupUi(mainWidget);
176
177 QStyle *newStyle = QStyleFactory::create(m_wdgLayerBox->listLayers->style()->objectName());
178 // proxy style steals the ownership of the style and deletes it later
179 LayerBoxStyle *proxyStyle = new LayerBoxStyle(newStyle);
180
181 proxyStyle->setParent(m_wdgLayerBox->listLayers);
182 m_wdgLayerBox->listLayers->setStyle(proxyStyle);
183
184 connect(m_wdgLayerBox->listLayers,
185 SIGNAL(contextMenuRequested(QPoint,QModelIndex)),
186 this, SLOT(slotContextMenuRequested(QPoint,QModelIndex)));
187 connect(m_wdgLayerBox->listLayers,
188 SIGNAL(collapsed(QModelIndex)), SLOT(slotCollapsed(QModelIndex)));
189 connect(m_wdgLayerBox->listLayers,
190 SIGNAL(expanded(QModelIndex)), SLOT(slotExpanded(QModelIndex)));
191 connect(m_wdgLayerBox->listLayers,
193
195
196 m_wdgLayerBox->bnAdd->setIconSize(QSize(22, 22));
197 m_wdgLayerBox->bnDelete->setIconSize(QSize(22, 22));
198 m_wdgLayerBox->bnRaise->setIconSize(QSize(22, 22));
199 m_wdgLayerBox->bnLower->setIconSize(QSize(22, 22));
200 m_wdgLayerBox->bnProperties->setIconSize(QSize(22, 22));
201 m_wdgLayerBox->bnDuplicate->setIconSize(QSize(22, 22));
202
203 m_wdgLayerBox->bnLower->setEnabled(false);
204 m_wdgLayerBox->bnRaise->setEnabled(false);
205
206 m_wdgLayerBox->doubleOpacity->setRange(0, 100, 0);
207 if (cfg.sliderLabels()) {
208 m_wdgLayerBox->opacityLabel->hide();
210 i18nc("{n} is the number value, % is the percent sign", "Opacity: {n}%"));
211 } else {
213 i18nc("{n} is the number value, % is the percent sign", "{n}%"));
214 }
215
216 connect(m_wdgLayerBox->doubleOpacity, SIGNAL(valueChanged(qreal)), SLOT(slotOpacitySliderMoved(qreal)));
217 connect(&m_nodeOpacityCompressor, SIGNAL(timeout()), SLOT(slotOpacityChanged()));
218
219 connect(m_wdgLayerBox->cmbComposite, SIGNAL(activated(int)), SLOT(slotCompositeOpChanged(int)));
220
221 m_newLayerMenu = new QMenu(this);
222 m_wdgLayerBox->bnAdd->setMenu(m_newLayerMenu);
223 m_wdgLayerBox->bnAdd->setPopupMode(QToolButton::MenuButtonPopup);
224
225 m_opLayerMenu = new QMenu(this);
226 m_wdgLayerBox->bnProperties->setMenu(m_opLayerMenu);
227 m_wdgLayerBox->bnProperties->setPopupMode(QToolButton::MenuButtonPopup);
228
229 m_nodeModel = new KisNodeModel(this, 2);
231 m_filteringModel->setNodeModel(m_nodeModel);
232
239 connect(m_nodeModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(updateUI()));
240 connect(m_nodeModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(updateUI()));
241 connect(m_nodeModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), SLOT(updateUI()));
242 connect(m_nodeModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(updateUI()));
243 connect(m_nodeModel, SIGNAL(modelReset()), SLOT(slotModelReset()));
244
245 connect(m_nodeModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(slotForgetAboutSavedNodeBeforeEditSelectionMode()));
246 connect(m_nodeModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(slotForgetAboutSavedNodeBeforeEditSelectionMode()));
247 connect(m_nodeModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), SLOT(slotForgetAboutSavedNodeBeforeEditSelectionMode()));
248 connect(m_nodeModel, SIGNAL(modelReset()), SLOT(slotForgetAboutSavedNodeBeforeEditSelectionMode()));
249
250 // we should update expanded state of the nodes on adding the nodes
251 connect(m_nodeModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(slotNodeCollapsedChanged()));
252 connect(m_nodeModel, SIGNAL(modelReset()), SLOT(slotNodeCollapsedChanged()));
253
254 m_showGlobalSelectionMask = new KisAction(i18n("&Show Global Selection Mask"), this);
255 m_showGlobalSelectionMask->setObjectName("show-global-selection-mask");
257 m_showGlobalSelectionMask->setToolTip(i18nc("@info:tooltip", "Shows global selection as a usual selection mask in <b>Layers</b> docker"));
258 m_showGlobalSelectionMask->setCheckable(true);
259 connect(m_showGlobalSelectionMask, SIGNAL(triggered(bool)), SLOT(slotEditGlobalSelection(bool)));
260
262
264 MouseClickIgnore* mouseEater = new MouseClickIgnore(this);
265 m_colorSelector->installEventFilter(mouseEater);
266 connect(m_colorSelector->colorLabelSelector(), SIGNAL(currentIndexChanged(int)), SLOT(slotColorLabelChanged(int)));
267 m_colorSelectorAction = new QWidgetAction(this);
268 m_colorSelectorAction->setDefaultWidget(m_colorSelector);
269
270 connect(m_nodeModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
271 &m_colorLabelCompressor, SLOT(start()));
272
273 m_wdgLayerBox->listLayers->setModel(m_filteringModel);
274 // this connection should be done *after* the setModel() call to
275 // happen later than the internal selection model
278
279
280 //LayerFilter Menu
281 QMenu *layerFilterMenu = new QMenu(this);
282 m_wdgLayerBox->bnLayerFilters->setMenu(layerFilterMenu);
283 m_wdgLayerBox->bnLayerFilters->setPopupMode(QToolButton::InstantPopup);
284
285 const QIcon filterIcon = KisIconUtils::loadIcon("view-filter");
286 m_wdgLayerBox->bnLayerFilters->setIcon(filterIcon);
287 m_wdgLayerBox->bnLayerFilters->setAutoRaise(true);
288 QPixmap filterEnabledPixmap = filterIcon.pixmap(64,64);
289 const QBitmap filterEnabledBitmask = filterEnabledPixmap.mask();
290 filterEnabledPixmap.fill(palette().color(QPalette::Highlight));
291 filterEnabledPixmap.setMask(filterEnabledBitmask);
292 const QIcon filterEnabledIcon = QIcon(filterEnabledPixmap);
293
295 connect(layerFilterWidget, SIGNAL(filteringOptionsChanged()), this, SLOT(updateLayerFiltering()));
296 connect(layerFilterWidget, &KisLayerFilterWidget::filteringOptionsChanged, [this, filterIcon, filterEnabledIcon](){
298 m_wdgLayerBox->bnLayerFilters->setIcon(filterEnabledIcon);
299 } else {
300 m_wdgLayerBox->bnLayerFilters->setIcon(filterIcon);
301 }
302
303 auto activeColors = layerFilterWidget->getActiveColors();
304 m_wdgLayerBox->bnLayerFilters->setSelectedColors(QList(activeColors.begin(), activeColors.end()));
305 m_wdgLayerBox->bnLayerFilters->setTextFilter(layerFilterWidget->hasTextFilter());
306 });
307
308 QWidgetAction *layerFilterMenuAction = new QWidgetAction(this);
309 layerFilterMenuAction->setDefaultWidget(layerFilterWidget);
310 layerFilterMenu->addAction(layerFilterMenuAction);
311
312
313 KisMenuStyleDontCloseOnAlt *menuStyle = new KisMenuStyleDontCloseOnAlt(layerFilterMenu->style());
314 menuStyle->setParent(layerFilterMenu);
315 layerFilterMenu->setStyle(menuStyle);
316
317 setEnabled(false);
318
319 connect(&m_colorLabelCompressor, SIGNAL(timeout()), SLOT(updateAvailableLabels()));
320
321
322 // set up the configure menu for changing thumbnail size
323 QMenu* configureMenu = new QMenu(this);
324 configureMenu->setContentsMargins(6, 6, 6, 6);
325 configureMenu->addSection(i18n("Thumbnail Size"));
326
327 m_wdgLayerBox->configureLayerDockerToolbar->setMenu(configureMenu);
328 m_wdgLayerBox->configureLayerDockerToolbar->setIconSize(QSize(16, 16));
329 m_wdgLayerBox->configureLayerDockerToolbar->setPopupMode(QToolButton::InstantPopup);
330 m_wdgLayerBox->configureLayerDockerToolbar->setAutoRaise(true);
331
332
333 // add horizontal slider
334 thumbnailSizeSlider = new QSlider(this);
335 thumbnailSizeSlider->setOrientation(Qt::Horizontal);
336 thumbnailSizeSlider->setRange(20, 80);
337
338 thumbnailSizeSlider->setValue(cfg.layerThumbnailSize(false)); // grab this from the kritarc
339
340 thumbnailSizeSlider->setMinimumHeight(20);
341 thumbnailSizeSlider->setMinimumWidth(40);
342 thumbnailSizeSlider->setTickInterval(5);
343 m_nodeModel->setPreferredThumnalSize(cfg.layerThumbnailSize() * m_wdgLayerBox->listLayers->devicePixelRatioF());
344
345 QWidgetAction *sliderAction= new QWidgetAction(this);
346 sliderAction->setDefaultWidget(thumbnailSizeSlider);
347 configureMenu->addAction(sliderAction);
348
349
350 connect(thumbnailSizeSlider, SIGNAL(valueChanged(int)), &m_thumbnailSizeCompressor, SLOT(start()));
351 connect(&m_thumbnailSizeCompressor, SIGNAL(timeout()), SLOT(slotUpdateThumbnailIconSize()));
352
353 configureMenu->addSection(i18nc("@item:inmenu Layers Docker settings, slider", "Tree Indentation"));
354
355 // add horizontal slider
356 indentationSlider = new QSlider(Qt::Horizontal, this);
357 indentationSlider->setRange(20, 100);
358 indentationSlider->setMinimumSize(40, 20);
359 indentationSlider->setSingleStep(5);
360 indentationSlider->setPageStep(20);
362
363
364 sliderAction= new QWidgetAction(this);
365 sliderAction->setDefaultWidget(indentationSlider);
366 configureMenu->addAction(sliderAction);
367
368 // NOTE: if KisConfig would just compress its file sync events, we wouldn't need
369 // this extra compressor that juggles between slow UI and disk thrashing
370 connect(indentationSlider, SIGNAL(valueChanged(int)), &m_treeIndentationCompressor, SLOT(start()));
371 connect(&m_treeIndentationCompressor, SIGNAL(timeout()), SLOT(slotUpdateTreeIndentation()));
372
373
374 // Layer info-text settings:
375 // blending info-text style combobox
376 configureMenu->addSection(i18nc("@item:inmenu Layers Docker settings, combobox", "Blending Info Style"));
377 infoTextCombobox = new QComboBox(this);
378 infoTextCombobox->setToolTip(i18nc("@item:tooltip", "None: Show nothing.\n"
379 "Simple: Show changed opacities or blending modes.\n"
380 "Balanced: Show both opacity and blending mode if either are changed.\n"
381 "Detailed: Show both opacity and blending mode even if unchanged."));
382 infoTextCombobox->insertItems(0, QStringList ({
383 i18nc("@item:inlistbox Layer Docker blending info style", "None"),
384 i18nc("@item:inlistbox Layer Docker blending info style", "Simple"),
385 i18nc("@item:inlistbox Layer Docker blending info style", "Balanced"),
386 i18nc("@item:inlistbox Layer Docker blending info style", "Detailed"),
387 }));
388 infoTextCombobox->setCurrentIndex((int)cfg.layerInfoTextStyle());
389
390 QWidgetAction *cmbboxAction = new QWidgetAction(this);
391 cmbboxAction->setDefaultWidget(infoTextCombobox);
392 configureMenu->addAction(cmbboxAction);
393 connect(infoTextCombobox, SIGNAL(currentIndexChanged(int)), SLOT(slotUpdateLayerInfoTextStyle()));
394
395 // info-text opacity slider
398 i18nc("{n} is the number value, % is the percent sign", "Opacity: {n}%"));
399 infoTextOpacitySlider->setToolTip(i18nc("@item:tooltip", "Blending info text opacity"));
400 // 55% is the opacity of nonvisible layer text
402 infoTextOpacitySlider->setMinimumSize(40, 20);
403 infoTextOpacitySlider->setSingleStep(5);
406 if (infoTextCombobox->currentIndex() == 0) {
407 infoTextOpacitySlider->setDisabled(true);
408 }
409
410 sliderAction= new QWidgetAction(this);
411 sliderAction->setDefaultWidget(infoTextOpacitySlider);
412 configureMenu->addAction(sliderAction);
413 connect(infoTextOpacitySlider, SIGNAL(valueChanged(int)), &m_infoTextOpacityCompressor, SLOT(start()));
414 connect(&m_infoTextOpacityCompressor, SIGNAL(timeout()), SLOT(slotUpdateLayerInfoTextOpacity()));
415
416 // info-text inline checkbox
417 infoTextInlineChkbox = new QCheckBox(i18nc("@item:inmenu Layers Docker settings, checkbox", "Inline"), this);
419 infoTextInlineChkbox->setToolTip(i18nc("@item:tooltip", "If enabled, show blending info beside layer names.\n"
420 "If disabled, show below layer names (when enough space)."));
421 if (infoTextCombobox->currentIndex() == 0) {
422 infoTextInlineChkbox->setDisabled(true);
423 }
424
425 QWidgetAction *chkboxAction = new QWidgetAction(this);
426 chkboxAction->setDefaultWidget(infoTextInlineChkbox);
427 configureMenu->addAction(chkboxAction);
428 connect(infoTextInlineChkbox, SIGNAL(stateChanged(int)), SLOT(slotUpdateUseInlineLayerInfoText()));
429
430 layerSelectionCheckBox = new QCheckBox(
431 i18nc("@item:inmenu Layers Docker settings, checkbox", "Checkbox for Selecting Layers"), this);
432 layerSelectionCheckBox->setToolTip(i18nc("@item:tooltip", "Show checkbox to select/unselect layers."));
434
435 QWidgetAction *layerSelectionAction = new QWidgetAction(this);
436 layerSelectionAction->setDefaultWidget(layerSelectionCheckBox);
437 configureMenu->addAction(layerSelectionAction);
438 connect(layerSelectionCheckBox, SIGNAL(stateChanged(int)), SLOT(slotUpdateUseLayerSelectionCheckbox()));
439
443}
444
446{
447 delete m_wdgLayerBox;
448}
449
450
452{
453 if (!root) return;
454 if (filteringModel.isNull()) return;
455 if (!nodeView) return;
456
457 nodeView->blockSignals(true);
458
459 KisNodeSP node = root->firstChild();
460 while (node) {
461 QModelIndex idx = filteringModel->indexFromNode(node);
462 if (idx.isValid()) {
463 nodeView->setExpanded(idx, !node->collapsed());
464 }
465 if (!node->collapsed() && node->childCount() > 0) {
466 expandNodesRecursively(node, filteringModel, nodeView);
467 }
468 node = node->nextSibling();
469 }
470 nodeView->blockSignals(false);
471}
472
474{
475 if (m_canvas) {
476 KisNodeList nodes = m_nodeManager->selectedNodes();
477
478 if (nodes.size() == 1) {
479 KisAction *action = m_canvas->viewManager()->actionManager()->actionByName("add_new_paint_layer");
480 action->trigger();
481 } else {
482 KisAction *action = m_canvas->viewManager()->actionManager()->actionByName("create_quick_group");
483 action->trigger();
484 }
485 }
486}
487
489{
490 m_nodeManager = kisview->nodeManager();
491
492 if (m_nodeManager) {
493 connect(m_nodeManager, SIGNAL(sigNodeActivated(KisNodeSP)), SLOT(slotForgetAboutSavedNodeBeforeEditSelectionMode()));
494 }
495
496 kisview->actionManager()->
497 addAction(m_showGlobalSelectionMask->objectName(),
499
500 connect(m_wdgLayerBox->bnAdd, SIGNAL(clicked()), this, SLOT(slotAddLayerBnClicked()));
501
502 connectActionToButton(kisview, m_wdgLayerBox->bnDuplicate, "duplicatelayer");
503
504 KisActionManager *actionManager = kisview->actionManager();
505
506 KisAction *action = actionManager->createAction("RenameCurrentLayer");
507 Q_ASSERT(action);
508 connect(action, SIGNAL(triggered()), this, SLOT(slotRenameCurrentNode()));
509
510 m_propertiesAction = actionManager->createAction("layer_properties");
511 Q_ASSERT(m_propertiesAction);
512 new SyncButtonAndAction(m_propertiesAction, m_wdgLayerBox->bnProperties, this);
513 connect(m_propertiesAction, SIGNAL(triggered()), this, SLOT(slotPropertiesClicked()));
514
515 connect(m_opLayerMenu, SIGNAL(aboutToShow()), this, SLOT(slotLayerOpMenuOpened()));
516
517 // It's necessary to clear the layer operations menu when it closes, else
518 // the color selector can't be shared with the right-click context menu
519 connect(m_opLayerMenu, SIGNAL(aboutToHide()), this, SLOT(slotLayerOpMenuClosed()));
520
521 m_removeAction = actionManager->createAction("remove_layer");
522 Q_ASSERT(m_removeAction);
524 connect(m_removeAction, SIGNAL(triggered()), this, SLOT(slotRmClicked()));
525
526 action = actionManager->createAction("move_layer_up");
527 Q_ASSERT(action);
528 new SyncButtonAndAction(action, m_wdgLayerBox->bnRaise, this);
529 connect(action, SIGNAL(triggered()), this, SLOT(slotRaiseClicked()));
530
531 action = actionManager->createAction("move_layer_down");
532 Q_ASSERT(action);
533 new SyncButtonAndAction(action, m_wdgLayerBox->bnLower, this);
534 connect(action, SIGNAL(triggered()), this, SLOT(slotLowerClicked()));
535
536 m_changeCloneSourceAction = actionManager->createAction("set-copy-from");
538 connect(m_changeCloneSourceAction, &KisAction::triggered,
540
541 m_layerToggleSolo = actionManager->createAction("toggle_layer_soloing");
542 connect(m_layerToggleSolo, SIGNAL(triggered(bool)), this, SLOT(toggleActiveLayerSolo()));
543}
544
546{
547 if (m_canvas == canvas)
548 return;
549
550 setEnabled(canvas != 0);
551
552 if (m_canvas) {
553 m_canvas->disconnectCanvasObserver(this);
554 m_nodeModel->setIdleTaskManager(0);
555 m_nodeModel->setDummiesFacade(0, 0, 0, 0, 0);
557
558 if (m_image) {
560 animation->disconnect(this);
561 }
562
563 disconnect(m_image, 0, this, 0);
564 disconnect(m_nodeManager, 0, this, 0);
565 disconnect(m_nodeModel, 0, m_nodeManager, 0);
566 m_nodeManager->slotSetSelectedNodes(KisNodeList());
567 }
568
569 m_canvas = dynamic_cast<KisCanvas2*>(canvas);
570
571 if (m_canvas) {
572 m_image = m_canvas->image();
573 Q_EMIT imageChanged();
574
575 KisDocument* doc = static_cast<KisDocument*>(m_canvas->imageView()->document());
576 KisShapeController *kritaShapeController =
577 dynamic_cast<KisShapeController*>(doc->shapeController());
578 KisDummiesFacadeBase *kritaDummiesFacade =
579 static_cast<KisDummiesFacadeBase*>(kritaShapeController);
580
581
582 m_selectionActionsAdapter.reset(new KisSelectionActionsAdapter(m_canvas->viewManager()->selectionManager()));
583 m_nodeModel->setDummiesFacade(kritaDummiesFacade,
584 m_image,
585 kritaShapeController,
588
589 if (isVisible()) {
590 m_nodeModel->setIdleTaskManager(m_canvas->viewManager()->idleTasksManager());
591 }
592
593 connect(m_image, SIGNAL(sigAboutToBeDeleted()), SLOT(notifyImageDeleted()));
594 connect(m_image, SIGNAL(sigNodeCollapsedChanged()), SLOT(slotNodeCollapsedChanged()));
595
596 // cold start
597 if (m_nodeManager) {
598 setCurrentNode(m_nodeManager->activeNode());
599 // Connection KisNodeManager -> LayerBox
600 connect(m_nodeManager, SIGNAL(sigUiNeedChangeActiveNode(KisNodeSP)),
601 this, SLOT(setCurrentNode(KisNodeSP)));
602
603 connect(m_nodeManager,
604 SIGNAL(sigUiNeedChangeSelectedNodes(QList<KisNodeSP>)),
606 }
607 else {
608 setCurrentNode(m_canvas->imageView()->currentNode());
609 }
610
611 // Connection LayerBox -> KisNodeManager (isolate layer)
612 connect(m_nodeModel, SIGNAL(toggleIsolateActiveNode()),
613 m_nodeManager, SLOT(toggleIsolateActiveNode()));
614
617
619 m_wdgLayerBox->listLayers->scrollTo(m_wdgLayerBox->listLayers->currentIndex());
621
622 addActionToMenu(m_newLayerMenu, "add_new_paint_layer");
623 addActionToMenu(m_newLayerMenu, "add_new_group_layer");
624 addActionToMenu(m_newLayerMenu, "add_new_clone_layer");
625 addActionToMenu(m_newLayerMenu, "add_new_shape_layer");
626 addActionToMenu(m_newLayerMenu, "add_new_adjustment_layer");
627 addActionToMenu(m_newLayerMenu, "add_new_fill_layer");
628 addActionToMenu(m_newLayerMenu, "add_new_file_layer");
629 m_newLayerMenu->addSeparator();
630 addActionToMenu(m_newLayerMenu, "add_new_transparency_mask");
631 addActionToMenu(m_newLayerMenu, "add_new_filter_mask");
632 addActionToMenu(m_newLayerMenu, "add_new_fast_color_overlay_mask");
633 addActionToMenu(m_newLayerMenu, "add_new_colorize_mask");
634 addActionToMenu(m_newLayerMenu, "add_new_transform_mask");
635 addActionToMenu(m_newLayerMenu, "add_new_selection_mask");
636 }
637}
638
639
641{
642 setEnabled(false);
643 if (m_canvas) {
644 m_newLayerMenu->clear();
645 }
646
647 m_filteringModel->unsetDummiesFacade();
648 disconnect(m_image, 0, this, 0);
649 disconnect(m_nodeManager, 0, this, 0);
650 disconnect(m_nodeModel, 0, m_nodeManager, 0);
651 m_nodeManager->slotSetSelectedNodes(KisNodeList());
652
653 m_canvas = 0;
654}
655
656void LayerBox::showEvent(QShowEvent *event)
657{
658 QDockWidget::showEvent(event);
659
660 if (m_canvas) {
661 m_nodeModel->setIdleTaskManager(m_canvas->viewManager()->idleTasksManager());
662 }
663}
664
665void LayerBox::hideEvent(QHideEvent *event)
666{
667 QDockWidget::hideEvent(event);
668 m_nodeModel->setIdleTaskManager(0);
669}
670
675
677{
678 if (!m_canvas) return;
679 if (!m_nodeManager) return;
680
681 KisNodeSP activeNode = m_nodeManager->activeNode();
682
683 if (activeNode != m_activeNode) {
685 m_activeNode = activeNode;
686
687 if (activeNode) {
688 KisPaintDeviceSP parentLayerDevice = activeNode->parent() ? activeNode->parent()->original() : 0;
689 if (parentLayerDevice) {
690 // update blending modes availability
692 parentLayerDevice, SIGNAL(colorSpaceChanged(const KoColorSpace*)),
693 this, SLOT(updateUI()));
694 }
695
697 activeNode, SIGNAL(opacityChanged(quint8)),
698 this, SLOT(slotUpdateOpacitySlider(quint8)));
699 }
700 }
701
702 m_wdgLayerBox->bnRaise->setEnabled(activeNode && activeNode->isEditable(false) && (activeNode->nextSibling()
703 || (activeNode->parent() && activeNode->parent() != m_image->root())));
704 m_wdgLayerBox->bnLower->setEnabled(activeNode && activeNode->isEditable(false) && (activeNode->prevSibling()
705 || (activeNode->parent() && activeNode->parent() != m_image->root())));
706
707 m_wdgLayerBox->doubleOpacity->setEnabled(activeNode && activeNode->isEditable(false));
708
709 m_wdgLayerBox->cmbComposite->setEnabled(activeNode && activeNode->isEditable(false));
710
711 if (activeNode) {
712 if (activeNode->inherits("KisColorizeMask") || activeNode->inherits("KisLayer")) {
713
714 m_wdgLayerBox->doubleOpacity->setEnabled(true);
715
716 if (!m_wdgLayerBox->doubleOpacity->isDragging()) {
717 slotSetOpacity(activeNode->opacity() * 100.0 / 255);
718 }
719
720 const KoCompositeOp* compositeOp = activeNode->compositeOp();
721 if (compositeOp) {
724 m_wdgLayerBox->cmbComposite->validate(compositeOp->colorSpace());
725 slotSetCompositeOp(compositeOp);
726 } else {
727 m_wdgLayerBox->cmbComposite->setEnabled(false);
728 }
729
730 const KisGroupLayer *group = qobject_cast<const KisGroupLayer*>(activeNode.data());
731 bool compositeSelectionActive = !(group && group->passThroughMode());
732
733 m_wdgLayerBox->cmbComposite->setEnabled(compositeSelectionActive);
734 } else if (activeNode->inherits("KisMask")) {
735 m_wdgLayerBox->cmbComposite->setEnabled(false);
736 m_wdgLayerBox->doubleOpacity->setEnabled(false);
737 }
738 }
739}
740
741
747{
758 if (node && m_image && node->graphListener() != m_image.data()) {
759 return;
760 }
761
762 m_filteringModel->setActiveNode(node);
763
764 QModelIndex index = node ? m_filteringModel->indexFromNode(node) : QModelIndex();
765 m_filteringModel->setData(index, true, KisNodeModel::ActiveRole);
766 updateUI();
767}
768
770{
771 if(m_nodeModel->hasDummiesFacade()) {
772 QItemSelection selection;
773 Q_FOREACH (const KisNodeSP node, m_nodeManager->selectedNodes()) {
774 const QModelIndex &idx = m_filteringModel->indexFromNode(node);
775 if(idx.isValid()){
776 QItemSelectionRange selectionRange(idx);
777 selection << selectionRange;
778 }
779 }
780
781 m_wdgLayerBox->listLayers->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect);
782 }
783
784 updateUI();
785}
786
788{
789 KoID opId = KoCompositeOpRegistry::instance().getKoID(compositeOp->id());
790
791 m_wdgLayerBox->cmbComposite->blockSignals(true);
792 m_wdgLayerBox->cmbComposite->selectCompositeOp(opId);
793 m_wdgLayerBox->cmbComposite->blockSignals(false);
794}
795
796// range: 0-100
797void LayerBox::slotSetOpacity(double opacity)
798{
799 Q_ASSERT(opacity >= 0 && opacity <= 100);
800 m_wdgLayerBox->doubleOpacity->blockSignals(true);
801 m_wdgLayerBox->doubleOpacity->setValue(opacity);
802 m_wdgLayerBox->doubleOpacity->blockSignals(false);
803}
804
806 double percentage = value * 100.0 / 255.0;
807
808 m_wdgLayerBox->doubleOpacity->blockSignals(true);
809 m_wdgLayerBox->doubleOpacity->setValue(percentage);
810 m_wdgLayerBox->doubleOpacity->blockSignals(false);
811}
812
813void LayerBox::slotContextMenuRequested(const QPoint &pos, const QModelIndex &index)
814{
815 KisNodeList nodes = m_nodeManager->selectedNodes();
816 KisNodeSP activeNode = m_nodeManager->activeNode();
817 if (nodes.isEmpty() || !activeNode) return;
818
819 if (m_canvas) {
820 QMenu menu;
821 updateLayerOpMenu(index, menu);
822 menu.exec(pos);
823 }
824}
825
827{
828 if (!m_canvas) return;
829 m_nodeManager->removeNode();
830}
831
833{
834 if (!m_canvas) return;
835 m_nodeManager->raiseNode();
836}
837
839{
840 if (!m_canvas) return;
841 m_nodeManager->lowerNode();
842}
843
845{
846 if (!m_canvas) return;
847 if (KisNodeSP active = m_nodeManager->activeNode()) {
848 m_nodeManager->nodeProperties(active);
849 }
850}
851
853{
854 if (!m_canvas) return;
855 updateLayerOpMenu(m_wdgLayerBox->listLayers->currentIndex(), *m_opLayerMenu);
856}
857
859{
860 if (!m_canvas) return;
861 m_opLayerMenu->clear();
862}
863
865{
866 if (!m_canvas) return;
867 m_nodeManager->changeCloneSource();
868}
869
871{
872 Q_UNUSED(index);
873 if (!m_canvas) return;
874
875 QString compositeOp = m_wdgLayerBox->cmbComposite->selectedCompositeOp().id();
876 m_nodeManager->nodeCompositeOpChanged(m_nodeManager->activeColorSpace()->compositeOp(compositeOp));
877}
878
884
891
892void LayerBox::slotCollapsed(const QModelIndex &index)
893{
894 KisNodeSP node = m_filteringModel->nodeFromIndex(index);
895 if (node) {
896 node->setCollapsed(true);
897 }
898}
899
900void LayerBox::slotExpanded(const QModelIndex &index)
901{
902 KisNodeSP node = m_filteringModel->nodeFromIndex(index);
903 if (node) {
904 node->setCollapsed(false);
905 }
906}
907
909{
910 if (!m_canvas) return;
911 QAction *action = m_canvas->viewManager()->actionManager()->actionByName("selectopaque");
912 if (action) {
913 action->trigger();
914 }
915}
916
918{
919 if (m_nodeModel->hasDummiesFacade()) {
921 }
922}
923
924inline bool isSelectionMask(KisNodeSP node)
925{
926 return dynamic_cast<KisSelectionMask*>(node.data());
927}
928
930{
931 if (KisNodeManager::isNodeHidden(startNode, true) &&
932 startNode->parent() &&
933 !startNode->parent()->parent()) {
934
935
936 KisNodeSP node = startNode->prevSibling();
937 while (node && KisNodeManager::isNodeHidden(node, true)) {
938 node = node->prevSibling();
939 }
940
941 if (!node) {
942 node = startNode->nextSibling();
943 while (node && KisNodeManager::isNodeHidden(node, true)) {
944 node = node->nextSibling();
945 }
946 }
947
948 if (!node) {
949 node = m_image->root()->lastChild();
950 while (node && KisNodeManager::isNodeHidden(node, true)) {
951 node = node->prevSibling();
952 }
953 }
954
955 KIS_ASSERT_RECOVER_NOOP(node && "cannot activate any node!");
956 startNode = node;
957 }
958
959 return startNode;
960}
961
962void LayerBox::slotEditGlobalSelection(bool showSelections)
963{
964 KisNodeSP lastActiveNode = m_nodeManager->activeNode();
965 KisNodeSP activateNode = lastActiveNode;
966 KisSelectionMaskSP globalSelectionMask;
967
968 if (!showSelections) {
969 activateNode =
972 findNonHidableNode(activateNode);
973 }
974
975 m_nodeModel->setShowGlobalSelection(showSelections);
976
977 globalSelectionMask = m_image->rootLayer()->selectionMask();
978
979 // try to find deactivated, but visible masks
980 if (!globalSelectionMask) {
981 KoProperties properties;
982 properties.setProperty("visible", true);
983 QList<KisNodeSP> masks = m_image->rootLayer()->childNodes(QStringList("KisSelectionMask"), properties);
984 if (!masks.isEmpty()) {
985 globalSelectionMask = dynamic_cast<KisSelectionMask*>(masks.first().data());
986 }
987 }
988
989 // try to find at least any selection mask
990 if (!globalSelectionMask) {
991 KoProperties properties;
992 QList<KisNodeSP> masks = m_image->rootLayer()->childNodes(QStringList("KisSelectionMask"), properties);
993 if (!masks.isEmpty()) {
994 globalSelectionMask = dynamic_cast<KisSelectionMask*>(masks.first().data());
995 }
996 }
997
998 if (globalSelectionMask) {
999 if (showSelections) {
1000 activateNode = globalSelectionMask;
1001 }
1002 }
1003
1004 if (activateNode != lastActiveNode) {
1005 m_nodeManager->slotNonUiActivatedNode(activateNode);
1006 } else if (lastActiveNode) {
1007 setCurrentNode(lastActiveNode);
1008 }
1009
1010 if (showSelections && !globalSelectionMask) {
1011 KisProcessingApplicator applicator(m_image, 0,
1014 kundo2_i18n("Quick Selection Mask"));
1015
1016 applicator.applyCommand(
1018 m_nodeManager->selectedNodes(), KisNodeList(),
1019 lastActiveNode, 0, m_image, false),
1027
1028 applicator.end();
1029 } else if (!showSelections &&
1030 globalSelectionMask &&
1031 globalSelectionMask->selection()->selectedRect().isEmpty()) {
1032
1033 KisProcessingApplicator applicator(m_image, 0,
1036 kundo2_i18n("Cancel Quick Selection Mask"));
1038 applicator.end();
1039 }
1040
1041 if (showSelections) {
1042 m_savedNodeBeforeEditSelectionMode = lastActiveNode;
1043 }
1044}
1045
1047{
1048 if (!m_nodeManager) return;
1049
1055 if (selection.isEmpty() && m_nodeManager->activeNode()) {
1056 QModelIndex selectedIndex =
1057 m_filteringModel->indexFromNode(m_nodeManager->activeNode());
1058
1059 m_wdgLayerBox->listLayers->selectionModel()->
1060 setCurrentIndex(selectedIndex, QItemSelectionModel::ClearAndSelect);
1061 return;
1062 }
1063
1064 QList<KisNodeSP> selectedNodes;
1065 Q_FOREACH (const QModelIndex &idx, selection) {
1066 // Precaution because node manager doesn't like duplicates in that list.
1067 // NodeView Selection behavior is SelectRows, although currently only column 0 allows selections.
1068 if (idx.column() != 0) {
1069 continue;
1070 }
1071 selectedNodes << m_filteringModel->nodeFromIndex(idx);
1072 }
1073
1074 m_nodeManager->slotSetSelectedNodes(selectedNodes);
1075 updateUI();
1076}
1077
1078void LayerBox::slotAdjustCurrentBeforeRemoveRows(const QModelIndex &parent, int start, int end)
1079{
1093 QModelIndex currentIndex = m_wdgLayerBox->listLayers->currentIndex();
1094 QAbstractItemModel *model = m_filteringModel;
1095
1096 if (currentIndex.isValid() && parent == currentIndex.parent()
1097 && currentIndex.row() >= start && currentIndex.row() <= end) {
1098 QModelIndex old = currentIndex;
1099
1100 if (model && end < model->rowCount(parent) - 1) // there are rows left below the change
1101 currentIndex = model->index(end + 1, old.column(), parent);
1102 else if (model && start > 0) // there are rows left above the change
1103 currentIndex = model->index(start - 1, old.column(), parent);
1104 else // there are no rows left in the table
1105 currentIndex = QModelIndex();
1106
1107 if (currentIndex.isValid() && currentIndex != old) {
1108 m_wdgLayerBox->listLayers->setCurrentIndex(currentIndex);
1109 }
1110 }
1111}
1112
1114{
1115 if (!m_nodeManager) return;
1116
1117 QModelIndexList newSelection;
1118 Q_FOREACH(KisNodeSP node, nodes) {
1119 newSelection << m_filteringModel->indexFromNode(node);
1120 }
1121
1122 QItemSelectionModel *model = m_wdgLayerBox->listLayers->selectionModel();
1123
1124 if (KritaUtils::compareListsUnordered(newSelection, model->selectedRows())) {
1125 return;
1126 }
1127
1128 QItemSelection selection;
1129 Q_FOREACH(const QModelIndex &idx, newSelection) {
1130 selection.select(idx, idx);
1131 }
1132
1133 model->select(selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
1134}
1135
1137{
1138 m_wdgLayerBox->listLayers->edit(m_wdgLayerBox->listLayers->currentIndex());
1139}
1140
1142{
1143 KisNodeList selectedNodes = m_nodeManager->selectedNodes();
1144
1145 Q_FOREACH(KisNodeSP selectedNode, selectedNodes) {
1146 //Always apply label to selected nodes..
1147 selectedNode->setColorLabelIndex(label);
1148
1149 //Apply label only to unlabelled children..
1150 KisNodeList children = selectedNode->childNodes(QStringList(), KoProperties());
1151
1152 auto applyLabelFunc =
1153 [label](KisNodeSP child) {
1154 if (child->colorLabelIndex() == 0) {
1155 child->setColorLabelIndex(label);
1156 }
1157 };
1158
1159 Q_FOREACH(KisNodeSP child, children) {
1160 KisLayerUtils::recursiveApplyNodes(child, applyLabelFunc);
1161 }
1162 }
1163}
1164
1170
1176
1178{
1179 Q_UNUSED(time);
1180 updateUI();
1181}
1182
1183void LayerBox::updateLayerOpMenu(const QModelIndex &index, QMenu &menu) {
1184
1185 KisNodeList nodes = m_nodeManager->selectedNodes();
1186 KisNodeSP activeNode = m_nodeManager->activeNode();
1187 const bool singleNode = nodes.size() == 1;
1188
1189 if (index.isValid()) {
1190 menu.addAction(m_propertiesAction);
1191
1192 KisLayerSP singleLayer = dynamic_cast<KisLayer*>(activeNode.data());
1193
1194 if (singleLayer) {
1195 addActionToMenu(&menu, "layer_style");
1196
1197 if (singleLayer->layerStyle()) {
1198 addActionToMenu(&menu, "copy_layer_style");
1199 }
1200
1201 if (KisClipboard::instance()->hasLayerStyles()) {
1202 addActionToMenu(&menu, "paste_layer_style");
1203 }
1204 }
1205
1206 Q_FOREACH(KisNodeSP node, nodes) {
1207 if (node && node->inherits("KisCloneLayer")) {
1208 menu.addAction(m_changeCloneSourceAction);
1209 break;
1210 }
1211 }
1212
1213 {
1214 KisSignalsBlocker b(m_colorSelector->colorLabelSelector());
1215 m_colorSelector->colorLabelSelector()->setCurrentIndex(singleNode ? activeNode->colorLabelIndex() : -1);
1216 }
1217
1218 menu.addAction(m_colorSelectorAction);
1219
1220 menu.addSeparator();
1221
1222 addActionToMenu(&menu, "cut_layer_clipboard");
1223 addActionToMenu(&menu, "copy_layer_clipboard");
1224 addActionToMenu(&menu, "paste_layer_from_clipboard");
1225 menu.addAction(m_removeAction);
1226 addActionToMenu(&menu, "duplicatelayer");
1227 addActionToMenu(&menu, "merge_layer");
1228 addActionToMenu(&menu, "new_from_visible");
1229
1230 if (singleNode) {
1231 addActionToMenu(&menu, "flatten_image");
1232 addActionToMenu(&menu, "flatten_layer");
1233 }
1234
1235 menu.addSeparator();
1236 QMenu *selectMenu = menu.addMenu(i18n("&Select"));
1237 addActionToMenu(selectMenu, "select_all_layers");
1238 addActionToMenu(selectMenu, "select_visible_layers");
1239 addActionToMenu(selectMenu, "select_invisible_layers");
1240 addActionToMenu(selectMenu, "select_locked_layers");
1241 addActionToMenu(selectMenu, "select_unlocked_layers");
1242 QMenu *groupMenu = menu.addMenu(i18nc("A group of layers", "&Group"));
1243 addActionToMenu(groupMenu, "create_quick_group");
1244 addActionToMenu(groupMenu, "create_quick_clipping_group");
1245 addActionToMenu(groupMenu, "quick_ungroup");
1246 QMenu *locksMenu = menu.addMenu(i18n("&Toggle Locks && Visibility"));
1247 addActionToMenu(locksMenu, "toggle_layer_visibility");
1248 addActionToMenu(locksMenu, "toggle_layer_lock");
1249 addActionToMenu(locksMenu, "toggle_layer_inherit_alpha");
1250 addActionToMenu(locksMenu, "toggle_layer_alpha_lock");
1251
1252 if (singleNode) {
1253 QMenu *addLayerMenu = menu.addMenu(i18n("&Add"));
1254 addActionToMenu(addLayerMenu, "add_new_transparency_mask");
1255 addActionToMenu(addLayerMenu, "add_new_filter_mask");
1256 addActionToMenu(addLayerMenu, "add_new_fast_color_overlay_mask");
1257 addActionToMenu(addLayerMenu, "add_new_colorize_mask");
1258 addActionToMenu(addLayerMenu, "add_new_transform_mask");
1259 addActionToMenu(addLayerMenu, "add_new_selection_mask");
1260 addLayerMenu->addSeparator();
1261 addActionToMenu(addLayerMenu, "add_new_clone_layer");
1262
1263 QMenu *convertToMenu = menu.addMenu(i18n("&Convert"));
1264 addActionToMenu(convertToMenu, "convert_to_paint_layer");
1265 addActionToMenu(convertToMenu, "convert_to_transparency_mask");
1266 addActionToMenu(convertToMenu, "convert_to_filter_mask");
1267 addActionToMenu(convertToMenu, "convert_to_selection_mask");
1268 addActionToMenu(convertToMenu, "convert_to_file_layer");
1269 addActionToMenu(convertToMenu, "convert_group_to_animated");
1270 addActionToMenu(convertToMenu, "layercolorspaceconversion");
1271
1272 QMenu *splitAlphaMenu = menu.addMenu(i18n("S&plit Alpha"));
1273 addActionToMenu(splitAlphaMenu, "split_alpha_into_mask");
1274 addActionToMenu(splitAlphaMenu, "split_alpha_write");
1275 addActionToMenu(splitAlphaMenu, "split_alpha_save_merged");
1276 } else {
1277 QMenu *addLayerMenu = menu.addMenu(i18n("&Add"));
1278 addActionToMenu(addLayerMenu, "add_new_clone_layer");
1279 }
1280
1281 menu.addSeparator();
1282
1283 addActionToMenu(&menu, "pin_to_timeline");
1284
1285
1286 if (singleNode) {
1287 KisNodeSP node = m_filteringModel->nodeFromIndex(index);
1288 if (node && !node->inherits("KisTransformMask")) {
1289 addActionToMenu(&menu, "isolate_active_layer");
1290 addActionToMenu(&menu, "isolate_active_group");
1291 }
1292
1293 addActionToMenu(&menu, "selectopaque");
1294
1295 }
1296 }
1297}
1298
1303
1305 m_wdgLayerBox->bnAdd->setIcon(KisIconUtils::loadIcon("addlayer"));
1306 m_wdgLayerBox->bnRaise->setIcon(KisIconUtils::loadIcon("arrowup"));
1307 m_wdgLayerBox->bnDelete->setIcon(KisIconUtils::loadIcon("deletelayer"));
1308 m_wdgLayerBox->bnLower->setIcon(KisIconUtils::loadIcon("arrowdown"));
1309 m_wdgLayerBox->bnProperties->setIcon(KisIconUtils::loadIcon("properties"));
1310 m_wdgLayerBox->bnDuplicate->setIcon(KisIconUtils::loadIcon("duplicatelayer"));
1311 m_wdgLayerBox->configureLayerDockerToolbar->setIcon(KisIconUtils::loadIcon("view-choose"));
1312
1313 // call child function about needing to update icons
1314 m_wdgLayerBox->listLayers->slotUpdateIcons();
1315}
1316
1318 NodeView* view = m_wdgLayerBox->listLayers;
1319 if (!view)
1320 return;
1321
1322 KisNodeSP node = m_nodeManager->activeNode();
1323 if (!node)
1324 return;
1325
1326 QModelIndex index = m_filteringModel->indexFromNode(node);
1327 if (!index.isValid())
1328 return;
1329
1330 view->toggleSolo(index);
1331}
1332
1334{
1335 KisConfig cfg(false);
1337
1338 m_nodeModel->setPreferredThumnalSize(thumbnailSizeSlider->value() * m_wdgLayerBox->listLayers->devicePixelRatioF());
1339 m_wdgLayerBox->listLayers->slotConfigurationChanged();
1340}
1341
1343{
1344 m_nodeModel->setPreferredThumnalSize(thumbnailSizeSlider->value() * m_wdgLayerBox->listLayers->devicePixelRatioF());
1345}
1346
1348{
1349 KisConfig cfg(false);
1350 if (indentationSlider->value() == cfg.layerTreeIndentation()) {
1351 return;
1352 }
1354 m_wdgLayerBox->listLayers->slotConfigurationChanged();
1355}
1356
1358{
1359 KisConfig cfg(false);
1360 if (infoTextCombobox->currentIndex() == cfg.layerInfoTextStyle()) {
1361 return;
1362 }
1364 m_wdgLayerBox->listLayers->slotConfigurationChanged();
1365 m_wdgLayerBox->listLayers->viewport()->update();
1366 if (infoTextCombobox->currentIndex() == 0) {
1367 infoTextOpacitySlider->setDisabled(true);
1368 infoTextInlineChkbox->setDisabled(true);
1369 }
1370 else {
1371 infoTextOpacitySlider->setDisabled(false);
1372 infoTextInlineChkbox->setDisabled(false);
1373 }
1374}
1375
1377{
1378 KisConfig cfg(false);
1379 if (infoTextOpacitySlider->value() == cfg.layerInfoTextOpacity()) {
1380 return;
1381 }
1383 m_wdgLayerBox->listLayers->slotConfigurationChanged();
1384 m_wdgLayerBox->listLayers->viewport()->update();
1385}
1386
1388{
1389 KisConfig cfg(false);
1390 if (infoTextInlineChkbox->isChecked() == cfg.useInlineLayerInfoText()) {
1391 return;
1392 }
1394 m_wdgLayerBox->listLayers->slotConfigurationChanged();
1395 m_wdgLayerBox->listLayers->viewport()->update();
1396}
1397
1398
1400{
1401 KisConfig cfg(false);
1402 if (layerSelectionCheckBox->isChecked() == cfg.useLayerSelectionCheckbox()) {
1403 return;
1404 }
1406 m_wdgLayerBox->listLayers->slotConfigurationChanged();
1407 m_wdgLayerBox->listLayers->viewport()->update();
1408}
1409
1410#include "moc_LayerBox.cpp"
float value(const T *src, size_t ch)
QVector< KisImageSignalType > KisImageSignalVector
QList< QString > QStringList
bool isSelectionMask(KisNodeSP node)
Definition LayerBox.cpp:924
void expandNodesRecursively(KisNodeSP root, QPointer< KisNodeFilterProxyModel > filteringModel, NodeView *nodeView)
Definition LayerBox.cpp:451
A KisActionManager class keeps track of KisActions. These actions are always associated with the GUI....
KisAction * createAction(const QString &name)
KisAction * actionByName(const QString &name) const
void setActivationFlags(ActivationFlags flags)
@ ACTIVE_IMAGE
Activate if there is at least one image.
Definition kis_action.h:43
static KisClipboard * instance()
LayerInfoTextStyle layerInfoTextStyle(bool defaultValue=false) const
bool showGlobalSelection(bool defaultValue=false) const
bool useInlineLayerInfoText(bool defaultValue=false) const
void setUseInlineLayerInfoText(bool value)
int layerThumbnailSize(bool defaultValue=false) const
void setUseLayerSelectionCheckbox(bool value)
bool useLayerSelectionCheckbox(bool defaultValue=false) const
bool sliderLabels(bool defaultValue=false) const
int layerTreeIndentation(bool defaultValue=false) const
void setLayerThumbnailSize(int size)
void setLayerInfoTextOpacity(int value)
void setLayerInfoTextStyle(LayerInfoTextStyle value)
void setLayerTreeIndentation(int percentage)
int layerInfoTextOpacity(bool defaultValue=false) const
KisShapeController * shapeController
void sigUiTimeChanged(int newTime)
KisGroupLayerSP rootLayer() const
KisImageAnimationInterface * animationInterface() const
QSet< int > getActiveColors() const
void filteringOptionsChanged()
void updateColorLabels(KisNodeSP root)
void sigBeforeBeginRemoveRows(const QModelIndex &parent, int start, int end)
static bool isNodeHidden(KisNodeSP node, bool isGlobalSelectionHidden)
@ ActiveRole
Whether the section is the active one.
void applyCommand(KUndo2Command *command, KisStrokeJobData::Sequentiality sequentiality=KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::Exclusivity exclusivity=KisStrokeJobData::NORMAL)
void sigScreenOrResolutionChanged(QScreen *screen)
void addConnection(Sender sender, Signal signal, Receiver receiver, Method method, Qt::ConnectionType type=Qt::AutoConnection)
This class is a spinbox in which you can click and drag to set the value. A slider like bar is displa...
void setValue(int newValue)
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 ...
void setPageStep(int newPageStep)
Does nothing currently.
KisActionManager * actionManager() const
KisNodeManager * nodeManager() const
The node manager handles everything about nodes.
QWidget * mainWindowAsQWidget() const
static const KoCompositeOpRegistry & instance()
KoID getKoID(const QString &compositeOpID) const
Definition KoID.h:30
void setProperty(const QString &name, const QVariant &value)
LayerBoxStyle(QStyle *baseStyle=0)
Definition LayerBox.cpp:98
void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const override
Definition LayerBox.cpp:100
void slotForgetAboutSavedNodeBeforeEditSelectionMode()
void slotRmClicked()
Definition LayerBox.cpp:826
QComboBox * infoTextCombobox
Definition LayerBox.h:183
void showEvent(QShowEvent *event) override
Definition LayerBox.cpp:656
void slotUpdateOpacitySlider(quint8 value)
Definition LayerBox.cpp:805
void slotImageTimeChanged(int time)
KisNodeSP m_activeNode
Definition LayerBox.h:188
~LayerBox() override
Definition LayerBox.cpp:445
void updateAvailableLabels()
qint32 convertOpacityToInt(qreal opacity)
Definition LayerBox.cpp:150
void imageChanged()
void addActionToMenu(QMenu *menu, const QString &id)
Definition LayerBox.cpp:143
KisAction * m_changeCloneSourceAction
Definition LayerBox.h:171
void slotOpacitySliderMoved(qreal opacity)
Definition LayerBox.cpp:885
void slotCollapsed(const QModelIndex &index)
Definition LayerBox.cpp:892
void slotCompositeOpChanged(int index)
Definition LayerBox.cpp:870
KisSignalCompressor m_colorLabelCompressor
Definition LayerBox.h:174
void slotContextMenuRequested(const QPoint &pos, const QModelIndex &index)
Definition LayerBox.cpp:813
void slotRaiseClicked()
Definition LayerBox.cpp:832
KisLayerFilterWidget * layerFilterWidget
Definition LayerBox.h:180
void slotSyncThumbnailIconSize()
void connectActionToButton(KisViewManager *view, QAbstractButton *button, const QString &id)
Definition LayerBox.cpp:130
void selectionChanged(const QModelIndexList &selection)
KisNodeSP m_changedOpacityNode
Definition LayerBox.h:167
void slotUpdateThumbnailIconSize()
QSlider * thumbnailSizeSlider
Definition LayerBox.h:181
KisSignalCompressor m_thumbnailSizeCompressor
Definition LayerBox.h:175
void toggleActiveLayerSolo()
QCheckBox * infoTextInlineChkbox
Definition LayerBox.h:185
int m_newOpacity
Definition LayerBox.h:166
KisAction * m_layerToggleSolo
Definition LayerBox.h:172
void slotLayerOpMenuOpened()
Definition LayerBox.cpp:852
void slotUpdateLayerInfoTextStyle()
void slotSetCompositeOp(const KoCompositeOp *compositeOp)
Definition LayerBox.cpp:787
KisAction * m_propertiesAction
Definition LayerBox.h:170
void slotUpdateUseInlineLayerInfoText()
QScopedPointer< KisScreenMigrationTracker > m_screenMigrationTracker
Definition LayerBox.h:191
void updateUI()
Definition LayerBox.cpp:676
void slotLowerClicked()
Definition LayerBox.cpp:838
void hideEvent(QHideEvent *event) override
Definition LayerBox.cpp:665
QSlider * indentationSlider
Definition LayerBox.h:182
void slotModelReset()
Definition LayerBox.cpp:769
void slotAddLayerBnClicked()
Definition LayerBox.cpp:473
KisImageWSP m_image
Definition LayerBox.h:159
KisSignalAutoConnectionsStore m_activeNodeConnections
Definition LayerBox.h:190
void slotNodeManagerChangedSelection(const QList< KisNodeSP > &nodes)
void slotPropertiesClicked()
Definition LayerBox.cpp:844
void slotRenameCurrentNode()
void slotEditGlobalSelection(bool showSelections)
Definition LayerBox.cpp:962
void slotUpdateIcons()
void slotExpanded(const QModelIndex &index)
Definition LayerBox.cpp:900
KisSignalCompressor m_infoTextOpacityCompressor
Definition LayerBox.h:177
void unsetCanvas() override
Definition LayerBox.cpp:640
KisAction * m_showGlobalSelectionMask
Definition LayerBox.h:173
KisSignalCompressor m_nodeOpacityCompressor
Definition LayerBox.h:178
void setViewManager(KisViewManager *kisview) override
reimplemented from KisMainwindowObserver
Definition LayerBox.cpp:488
void slotChangeCloneSourceClicked()
Definition LayerBox.cpp:864
void updateLayerFiltering()
void slotOpacityChanged()
Definition LayerBox.cpp:879
QPointer< KisNodeManager > m_nodeManager
Definition LayerBox.h:162
QScopedPointer< KisSelectionActionsAdapter > m_selectionActionsAdapter
Definition LayerBox.h:156
KisNodeSP findNonHidableNode(KisNodeSP startNode)
Definition LayerBox.cpp:929
KisSliderSpinBox * infoTextOpacitySlider
Definition LayerBox.h:184
Ui_WdgLayerBox * m_wdgLayerBox
Definition LayerBox.h:165
QMenu * m_newLayerMenu
Definition LayerBox.h:157
void updateLayerOpMenu(const QModelIndex &index, QMenu &menu)
QPointer< KisNodeFilterProxyModel > m_filteringModel
Definition LayerBox.h:161
void slotUpdateTreeIndentation()
void slotSelectOpaque()
Definition LayerBox.cpp:908
QPointer< QWidgetAction > m_colorSelectorAction
Definition LayerBox.h:164
QPointer< KisColorLabelSelectorWidgetMenuWrapper > m_colorSelector
Definition LayerBox.h:163
void slotUpdateUseLayerSelectionCheckbox()
KisAction * m_removeAction
Definition LayerBox.h:169
void slotUpdateLayerInfoTextOpacity()
void slotColorLabelChanged(int index)
void slotSetOpacity(double opacity)
Definition LayerBox.cpp:797
QMenu * m_opLayerMenu
Definition LayerBox.h:158
void setCurrentNode(KisNodeSP node)
Definition LayerBox.cpp:746
void setCanvas(KoCanvasBase *canvas) override
Definition LayerBox.cpp:545
void notifyImageDeleted()
Definition LayerBox.cpp:671
void slotNodeCollapsedChanged()
Definition LayerBox.cpp:917
QPointer< KisNodeModel > m_nodeModel
Definition LayerBox.h:160
KisNodeWSP m_savedNodeBeforeEditSelectionMode
Definition LayerBox.h:189
void slotAdjustCurrentBeforeRemoveRows(const QModelIndex &parent, int first, int last)
QCheckBox * layerSelectionCheckBox
Definition LayerBox.h:186
QPointer< KisCanvas2 > m_canvas
Definition LayerBox.h:155
KisSignalCompressor m_treeIndentationCompressor
Definition LayerBox.h:176
void slotLayerOpMenuClosed()
Definition LayerBox.cpp:858
void toggleSolo(const QModelIndex &index)
Definition NodeView.cpp:158
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
QString button(const QWheelEvent &ev)
QList< KisNodeSP > KisNodeList
Definition kis_types.h:264
KisSharedPtr< KisNode > KisNodeSP
Definition kis_types.h:86
KUndo2MagicString kundo2_i18n(const char *text)
QIcon loadIcon(const QString &name)
void recursiveApplyNodes(NodePointer node, Functor func)
void setText(QSpinBox *spinBox, const QStringView textTemplate)
bool compareListsUnordered(const QList< T > &a, const QList< T > &b)
bool isEditable(bool checkVisibility=true) const
virtual KisPaintDeviceSP original() const =0
void setColorLabelIndex(int index)
void setCollapsed(bool collapsed)
QString compositeOp
int colorLabelIndex() const
quint8 opacity() const
virtual KisSelectionMaskSP selectionMask() const
Definition kis_layer.cc:504
KisPSDLayerStyleSP layerStyle
Definition kis_layer.cc:171
KisSelectionSP selection
Definition kis_mask.cc:44
KisNodeSP prevSibling() const
Definition kis_node.cpp:402
KisNodeSP firstChild() const
Definition kis_node.cpp:361
QList< KisNodeSP > childNodes(const QStringList &nodeTypes, const KoProperties &properties) const
Definition kis_node.cpp:439
quint32 childCount() const
Definition kis_node.cpp:414
KisNodeWSP parent
Definition kis_node.cpp:86
KisNodeSP lastChild() const
Definition kis_node.cpp:367
KisNodeSP nextSibling() const
Definition kis_node.cpp:408
KisNodeGraphListener * graphListener
Definition kis_node.cpp:87
QRect selectedRect() const
const KoColorSpace * colorSpace