File indexing completed on 2024-12-22 04:12:42
0001 /* This file is part of the KDE project 0002 * SPDX-FileCopyrightText: 2012 Arjen Hiemstra <ahiemstra@heimr.nl> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_select_layer_action.h" 0008 0009 #include <kis_debug.h> 0010 #include <QMouseEvent> 0011 #include <QApplication> 0012 #include <QMenu> 0013 0014 #include <klocalizedstring.h> 0015 0016 #include <kis_canvas2.h> 0017 #include <kis_image.h> 0018 #include <KisViewManager.h> 0019 #include <kis_node_manager.h> 0020 #include <kis_cursor.h> 0021 0022 #include "kis_input_manager.h" 0023 #include "kis_tool_utils.h" 0024 #include <kis_group_layer.h> 0025 0026 #include <kis_assert.h> 0027 0028 class KisSelectLayerAction::Private 0029 { 0030 public: 0031 KisSelectLayerAction *q {nullptr}; 0032 int shortcut {makeShortcut(LayerSelectionMode_TopLayer, SelectionOverrideMode_Replace)}; 0033 0034 Private(KisSelectLayerAction *q) 0035 : q(q) 0036 {} 0037 0038 static int makeShortcut(LayerSelectionMode layerSelectionMode, SelectionOverrideMode selectionOverrideMode) 0039 { 0040 // Store the layer selection mode on the second byte and the selection override mode on the first one 0041 return (layerSelectionMode << 8) | selectionOverrideMode; 0042 } 0043 0044 static int layerSelectionMode(int shortcut) 0045 { 0046 // Get the layer selection mode from the second byte 0047 return (shortcut >> 8) & 0xFF; 0048 } 0049 0050 static int selectionOverrideMode(int shortcut) 0051 { 0052 // Get the selection override mode from the first byte 0053 return shortcut & 0xFF; 0054 } 0055 0056 void selectNodes(const KisNodeList &nodesToSelect, int selectionOverrideMode, bool includeGroups) const 0057 { 0058 KisNodeManager *nodeManager = q->inputManager()->canvas()->viewManager()->nodeManager(); 0059 KisNodeSP activeNode = nodeManager->activeNode(); 0060 KisNodeList finalSelectedNodes; 0061 0062 // Make the final list of nodes to select, excluding the group layers, 0063 // if needed 0064 if (includeGroups) { 0065 finalSelectedNodes = nodesToSelect; 0066 } else { 0067 Q_FOREACH(KisNodeSP node, nodesToSelect) { 0068 if (!dynamic_cast<KisGroupLayer*>(node.data())) { 0069 finalSelectedNodes.append(node); 0070 } 0071 } 0072 } 0073 0074 // Expand the group layers that contain newly selected nodes 0075 Q_FOREACH(KisNodeSP node, finalSelectedNodes) { 0076 KisNodeSP tmpNode = node->parent(); 0077 while (tmpNode) { 0078 if (dynamic_cast<KisGroupLayer*>(tmpNode.data())) { 0079 tmpNode->setCollapsed(false); 0080 } 0081 tmpNode = tmpNode->parent(); 0082 } 0083 } 0084 0085 // Combine the list of nodes with the current selection 0086 if (selectionOverrideMode == SelectionOverrideMode_Add) { 0087 KisNodeList currentlySelectedNodes = nodeManager->selectedNodes(); 0088 Q_FOREACH(KisNodeSP node, currentlySelectedNodes) { 0089 if (!finalSelectedNodes.contains(node)) { 0090 finalSelectedNodes.append(node); 0091 } 0092 } 0093 } 0094 0095 // Try to retain the previously selected node or select the top one otherwise 0096 if (!finalSelectedNodes.contains(activeNode)) { 0097 activeNode = finalSelectedNodes.last(); 0098 } 0099 0100 // Select 0101 nodeManager->slotImageRequestNodeReselection(activeNode, finalSelectedNodes); 0102 } 0103 0104 void selectNode(KisNodeSP node, int selectionOverrideMode) const 0105 { 0106 KisNodeList nodesToSelect; 0107 nodesToSelect.append(node); 0108 selectNodes(nodesToSelect, selectionOverrideMode, true); 0109 } 0110 }; 0111 0112 KisSelectLayerAction::KisSelectLayerAction() 0113 : KisAbstractInputAction("Select Layer") 0114 , d(new Private(this)) 0115 { 0116 setName(i18n("Select Layer")); 0117 setDescription(i18n("Select layers under the cursor position")); 0118 0119 QHash<QString, int> shortcuts; 0120 shortcuts.insert(i18n("Select Top Layer (Replace Selection)"), 0121 d->makeShortcut(LayerSelectionMode_TopLayer, SelectionOverrideMode_Replace)); 0122 shortcuts.insert(i18n("Select All Layers (Replace Selection)"), 0123 d->makeShortcut(LayerSelectionMode_AllLayers, SelectionOverrideMode_Replace)); 0124 shortcuts.insert(i18n("Select from Menu (Replace Selection)"), 0125 d->makeShortcut(LayerSelectionMode_Ask, SelectionOverrideMode_Replace)); 0126 shortcuts.insert(i18n("Select Top Layer (Add to Selection)"), 0127 d->makeShortcut(LayerSelectionMode_TopLayer, SelectionOverrideMode_Add)); 0128 shortcuts.insert(i18n("Select All Layers (Add to Selection)"), 0129 d->makeShortcut(LayerSelectionMode_AllLayers, SelectionOverrideMode_Add)); 0130 shortcuts.insert(i18n("Select from Menu (Add to Selection)"), 0131 d->makeShortcut(LayerSelectionMode_Ask, SelectionOverrideMode_Add)); 0132 setShortcutIndexes(shortcuts); 0133 } 0134 0135 KisSelectLayerAction::~KisSelectLayerAction() 0136 { 0137 delete d; 0138 } 0139 0140 int KisSelectLayerAction::priority() const 0141 { 0142 return 5; 0143 } 0144 0145 void KisSelectLayerAction::activate(int shortcut) 0146 { 0147 Q_UNUSED(shortcut); 0148 QApplication::setOverrideCursor(KisCursor::pickLayerCursor()); 0149 } 0150 0151 void KisSelectLayerAction::deactivate(int shortcut) 0152 { 0153 Q_UNUSED(shortcut); 0154 QApplication::restoreOverrideCursor(); 0155 } 0156 0157 void KisSelectLayerAction::begin(int shortcut, QEvent *event) 0158 { 0159 KisAbstractInputAction::begin(shortcut, event); 0160 0161 d->shortcut = shortcut; 0162 inputEvent(event); 0163 } 0164 0165 void KisSelectLayerAction::inputEvent(QEvent *event) 0166 { 0167 // Event not recognized 0168 if (!event || (event->type() != QEvent::MouseMove && event->type() != QEvent::TabletMove && 0169 event->type() != QTouchEvent::TouchUpdate && event->type() != QEvent::MouseButtonPress && 0170 event->type() != QEvent::TabletPress && event->type() != QTouchEvent::TouchBegin)) { 0171 return; 0172 } 0173 0174 const int layerSelectionMode = d->layerSelectionMode(d->shortcut); 0175 const int selectionOverrideMode = d->selectionOverrideMode(d->shortcut); 0176 0177 // Shortcut not recognized 0178 KIS_SAFE_ASSERT_RECOVER_RETURN( 0179 (layerSelectionMode == LayerSelectionMode_TopLayer || 0180 layerSelectionMode == LayerSelectionMode_AllLayers || 0181 layerSelectionMode == LayerSelectionMode_Ask) && 0182 (selectionOverrideMode == SelectionOverrideMode_Replace || 0183 selectionOverrideMode == SelectionOverrideMode_Add) 0184 ); 0185 0186 QPoint pos = 0187 inputManager()->canvas()-> 0188 coordinatesConverter()->widgetToImage(eventPosF(event)).toPoint(); 0189 0190 // First make a list with the nodes to be selected 0191 KisNodeList nodesToSelect; 0192 0193 if (layerSelectionMode == LayerSelectionMode_TopLayer) { 0194 KisNodeSP foundNode = KisToolUtils::findNode(inputManager()->canvas()->image()->root(), pos, false); 0195 if (!foundNode) { 0196 return; 0197 } 0198 nodesToSelect.append(foundNode); 0199 } else { 0200 // Retrieve group nodes only if the mode is LayerSelectionMode_Ask 0201 const KisNodeList foundNodes = KisToolUtils::findNodes( 0202 inputManager()->canvas()->image()->root()->firstChild(), 0203 pos, false, layerSelectionMode == LayerSelectionMode_Ask); 0204 0205 if (foundNodes.isEmpty()) { 0206 return; 0207 } 0208 0209 if (layerSelectionMode == LayerSelectionMode_AllLayers) { 0210 nodesToSelect = foundNodes; 0211 } else { //LayerSelectionMode_Ask 0212 QWidget *canvasWidget = inputManager()->canvas()->canvasWidget(); 0213 QMenu *menu = new QMenu(canvasWidget); 0214 menu->setAttribute(Qt::WA_DeleteOnClose); 0215 int numberOfLayers = 0; 0216 0217 // Traverse the list in reverse order so that the menu entries order 0218 // resembles that of the layer stack 0219 for (int i = foundNodes.size() - 1; i >= 0; --i) { 0220 KisNodeSP node = foundNodes[i]; 0221 int indentation = -1; 0222 { 0223 KisNodeSP tempNode = node; 0224 while (tempNode->parent()) { 0225 ++indentation; 0226 tempNode = tempNode->parent(); 0227 } 0228 } 0229 QAction *action = menu->addAction(QString(4 * indentation, ' ') + node->name()); 0230 QObject::connect(action, &QAction::triggered, 0231 [this, node, selectionOverrideMode]() 0232 { 0233 d->selectNode(node, selectionOverrideMode); 0234 } 0235 ); 0236 if (!dynamic_cast<KisGroupLayer*>(node.data())) { 0237 ++numberOfLayers; 0238 } 0239 } 0240 0241 // Add separator 0242 menu->addSeparator(); 0243 0244 // Add "select all layers" menu item 0245 { 0246 QAction *action = menu->addAction(i18nc("Menu entry for the select layer under cursor canvas input action", 0247 "Select all layers")); 0248 action->setVisible(numberOfLayers > 1); 0249 QObject::connect(action, &QAction::triggered, 0250 [this, foundNodes, selectionOverrideMode]() 0251 { 0252 d->selectNodes(foundNodes, selectionOverrideMode, false); 0253 } 0254 ); 0255 } 0256 0257 menu->popup(canvasWidget->mapToGlobal(eventPos(event))); 0258 return; 0259 } 0260 } 0261 0262 // Now select the nodes 0263 d->selectNodes(nodesToSelect, selectionOverrideMode, true); 0264 }