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