File indexing completed on 2024-12-22 04:12:32
0001 /* 0002 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_shape_controller.h" 0008 0009 0010 #include <klocalizedstring.h> 0011 0012 #include <KoShape.h> 0013 #include <KoShapeContainer.h> 0014 #include <KoShapeManager.h> 0015 #include <KoCanvasBase.h> 0016 #include <KoToolManager.h> 0017 #include <KisView.h> 0018 #include <KoSelection.h> 0019 #include <KoShapeLayer.h> 0020 #include <KoPathShape.h> 0021 #include <KoColorSpaceConstants.h> 0022 #include <KoCanvasController.h> 0023 0024 #include "kis_node_manager.h" 0025 #include "kis_shape_selection.h" 0026 #include "kis_selection.h" 0027 #include "kis_selection_component.h" 0028 #include "kis_adjustment_layer.h" 0029 #include "kis_clone_layer.h" 0030 #include "canvas/kis_canvas2.h" 0031 #include "KisDocument.h" 0032 #include "kis_image.h" 0033 #include "kis_group_layer.h" 0034 #include "kis_node_shape.h" 0035 #include "kis_node_shapes_graph.h" 0036 #include "kis_name_server.h" 0037 #include "kis_mask.h" 0038 #include "kis_shape_layer.h" 0039 #include "KisViewManager.h" 0040 #include "kis_node.h" 0041 0042 #include <KoDocumentResourceManager.h> 0043 #include <commands/kis_image_layer_add_command.h> 0044 #include <kis_undo_adapter.h> 0045 #include "KoSelectedShapesProxy.h" 0046 #include "kis_signal_auto_connection.h" 0047 0048 #include "KoAddRemoveShapeCommands.h" 0049 0050 0051 struct KisShapeController::Private 0052 { 0053 public: 0054 KisNameServer *nameServer; 0055 KisSignalAutoConnectionsStore imageConnections; 0056 0057 KisNodeShapesGraph shapesGraph; 0058 }; 0059 0060 KisShapeController::KisShapeController(KisNameServer *nameServer, KUndo2Stack *undoStack, QObject *parent) 0061 : KisDummiesFacadeBase(parent) 0062 , m_d(new Private()) 0063 { 0064 m_d->nameServer = nameServer; 0065 resourceManager()->setUndoStack(undoStack); 0066 } 0067 0068 0069 KisShapeController::~KisShapeController() 0070 { 0071 KisNodeDummy *node = m_d->shapesGraph.rootDummy(); 0072 if (node) { 0073 m_d->shapesGraph.removeNode(node->node()); 0074 } 0075 0076 delete m_d; 0077 } 0078 0079 void KisShapeController::slotUpdateDocumentResolution() 0080 { 0081 KisImageSP image = this->image(); 0082 0083 if (image) { 0084 const qreal pixelsPerInch = image->xRes() * 72.0; 0085 resourceManager()->setResource(KoDocumentResourceManager::DocumentResolution, pixelsPerInch); 0086 } 0087 } 0088 0089 void KisShapeController::slotUpdateDocumentSize() 0090 { 0091 KisImageSP image = this->image(); 0092 0093 if (image) { 0094 resourceManager()->setResource(KoDocumentResourceManager::DocumentRectInPixels, image->bounds()); 0095 } 0096 } 0097 0098 void KisShapeController::addNodeImpl(KisNodeSP node, KisNodeSP parent, KisNodeSP aboveThis) 0099 { 0100 KisNodeShape *newShape = 0101 m_d->shapesGraph.addNode(node, parent, aboveThis); 0102 // XXX: what are we going to do with this shape? 0103 Q_UNUSED(newShape); 0104 0105 KisShapeLayer *shapeLayer = dynamic_cast<KisShapeLayer*>(node.data()); 0106 if (shapeLayer) { 0107 /** 0108 * Forward signals for global shape manager 0109 * \see comment in the constructor of KisCanvas2 0110 */ 0111 connect(shapeLayer, SIGNAL(selectionChanged()), 0112 SIGNAL(selectionChanged())); 0113 connect(shapeLayer->shapeManager(), SIGNAL(selectionContentChanged()), 0114 SIGNAL(selectionContentChanged())); 0115 connect(shapeLayer, SIGNAL(currentLayerChanged(const KoShapeLayer*)), 0116 SIGNAL(currentLayerChanged(const KoShapeLayer*))); 0117 } 0118 } 0119 0120 void KisShapeController::removeNodeImpl(KisNodeSP node) 0121 { 0122 KisShapeLayer *shapeLayer = dynamic_cast<KisShapeLayer*>(node.data()); 0123 if (shapeLayer) { 0124 shapeLayer->disconnect(this); 0125 } 0126 0127 m_d->shapesGraph.removeNode(node); 0128 } 0129 0130 bool KisShapeController::hasDummyForNode(KisNodeSP node) const 0131 { 0132 return m_d->shapesGraph.containsNode(node); 0133 } 0134 0135 KisNodeDummy* KisShapeController::dummyForNode(KisNodeSP node) const 0136 { 0137 return m_d->shapesGraph.nodeToDummy(node); 0138 } 0139 0140 KisNodeDummy* KisShapeController::rootDummy() const 0141 { 0142 return m_d->shapesGraph.rootDummy(); 0143 } 0144 0145 int KisShapeController::dummiesCount() const 0146 { 0147 return m_d->shapesGraph.shapesCount(); 0148 } 0149 static inline bool belongsToShapeSelection(KoShape* shape) { 0150 return dynamic_cast<KisShapeSelectionMarker*>(shape->userData()); 0151 } 0152 0153 KoShapeContainer *KisShapeController::createParentForShapes(const QList<KoShape *> shapes, KUndo2Command *parentCommand) 0154 { 0155 KoShapeContainer *resultParent = 0; 0156 KisCommandUtils::CompositeCommand *resultCommand = 0157 new KisCommandUtils::CompositeCommand(parentCommand); 0158 0159 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!shapes.isEmpty(), resultParent); 0160 Q_FOREACH (KoShape *shape, shapes) { 0161 KIS_SAFE_ASSERT_RECOVER_BREAK(!shape->parent()); 0162 } 0163 0164 KisCanvas2 *canvas = dynamic_cast<KisCanvas2*>(KoToolManager::instance()->activeCanvasController()->canvas()); 0165 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(canvas, resultParent); 0166 0167 const bool baseBelongsToSelection = belongsToShapeSelection(shapes.first()); 0168 bool allSameBelongsToShapeSelection = true; 0169 0170 Q_FOREACH (KoShape *shape, shapes) { 0171 allSameBelongsToShapeSelection &= belongsToShapeSelection(shape) == baseBelongsToSelection; 0172 } 0173 0174 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!baseBelongsToSelection || allSameBelongsToShapeSelection, resultParent); 0175 0176 if (baseBelongsToSelection && allSameBelongsToShapeSelection) { 0177 KisSelectionSP selection = canvas->viewManager()->selection(); 0178 if (selection) { 0179 KisSelectionComponent* shapeSelectionComponent = selection->shapeSelection(); 0180 0181 if (!shapeSelectionComponent) { 0182 shapeSelectionComponent = new KisShapeSelection(this, selection); 0183 resultCommand->addCommand(selection->convertToVectorSelection(shapeSelectionComponent)); 0184 } 0185 0186 KisShapeSelection * shapeSelection = static_cast<KisShapeSelection*>(shapeSelectionComponent); 0187 resultParent = shapeSelection; 0188 } 0189 } else { 0190 KisShapeLayer *shapeLayer = 0191 dynamic_cast<KisShapeLayer*>( 0192 canvas->selectedShapesProxy()->selection()->activeLayer()); 0193 0194 if (!shapeLayer) { 0195 shapeLayer = new KisShapeLayer(this, image(), 0196 i18n("Vector Layer %1", m_d->nameServer->number()), 0197 OPACITY_OPAQUE_U8); 0198 0199 resultCommand->addCommand( 0200 new KisImageLayerAddCommand(image(), 0201 shapeLayer, 0202 image()->rootLayer(), 0203 image()->rootLayer()->childCount())); 0204 } 0205 0206 resultParent = shapeLayer; 0207 } 0208 0209 return resultParent; 0210 } 0211 0212 QRectF KisShapeController::documentRectInPixels() const 0213 { 0214 KisImageSP image = this->image(); 0215 return image ? image->bounds() : QRect(0, 0, 666, 777); 0216 } 0217 0218 qreal KisShapeController::pixelsPerInch() const 0219 { 0220 KisImageSP image = this->image(); 0221 return image ? image->xRes() * 72.0 : 72.0; 0222 } 0223 0224 void KisShapeController::setInitialShapeForCanvas(KisCanvas2 *canvas) 0225 { 0226 if (!image()) return; 0227 0228 KisNodeSP rootNode = image()->root(); 0229 0230 if (m_d->shapesGraph.containsNode(rootNode)) { 0231 Q_ASSERT(canvas); 0232 Q_ASSERT(canvas->shapeManager()); 0233 KoSelection *selection = canvas->shapeManager()->selection(); 0234 if (selection && m_d->shapesGraph.nodeToShape(rootNode)) { 0235 selection->select(m_d->shapesGraph.nodeToShape(rootNode)); 0236 KoToolManager::instance()->switchToolRequested(KoToolManager::instance()->preferredToolForSelection(selection->selectedShapes())); 0237 } 0238 } 0239 } 0240 0241 void KisShapeController::setImage(KisImageWSP image) 0242 { 0243 m_d->imageConnections.clear(); 0244 0245 if (image) { 0246 m_d->imageConnections.addConnection(image, SIGNAL(sigResolutionChanged(double, double)), this, SLOT(slotUpdateDocumentResolution())); 0247 m_d->imageConnections.addConnection(image, SIGNAL(sigSizeChanged(QPointF, QPointF)), this, SLOT(slotUpdateDocumentSize())); 0248 } 0249 0250 KisDummiesFacadeBase::setImage(image); 0251 0252 slotUpdateDocumentResolution(); 0253 slotUpdateDocumentSize(); 0254 } 0255 0256 KoShapeLayer* KisShapeController::shapeForNode(KisNodeSP node) const 0257 { 0258 if (node) { 0259 return m_d->shapesGraph.nodeToShape(node); 0260 } 0261 return 0; 0262 } 0263