File indexing completed on 2024-06-16 04:17:54
0001 /* 0002 * kis_tool_crop.cc -- part of Krita 0003 * 0004 * SPDX-FileCopyrightText: 2004 Boudewijn Rempt <boud@valdyas.org> 0005 * SPDX-FileCopyrightText: 2005 Michael Thaler <michael.thaler@physik.tu-muenchen.de> 0006 * SPDX-FileCopyrightText: 2006 Cyrille Berger <cberger@cberger.net> 0007 * SPDX-FileCopyrightText: 2007 Adrian Page <adrian@pagenet.plus.com> 0008 * 0009 * SPDX-License-Identifier: GPL-2.0-or-later 0010 */ 0011 0012 #include "kis_tool_crop.h" 0013 0014 0015 #include <QCheckBox> 0016 #include <QComboBox> 0017 #include <QObject> 0018 #include <QPainter> 0019 #include <QPen> 0020 #include <QPushButton> 0021 #include <QRect> 0022 #include <QVector> 0023 #include <QMenu> 0024 0025 #include <kis_debug.h> 0026 #include <klocalizedstring.h> 0027 #include <ksharedconfig.h> 0028 0029 #include <KoCanvasBase.h> 0030 #include <kis_global.h> 0031 #include <kis_painter.h> 0032 #include <kis_cursor.h> 0033 #include <kis_image.h> 0034 #include <kis_undo_adapter.h> 0035 #include <KoPointerEvent.h> 0036 #include <kis_selection.h> 0037 #include <kis_layer.h> 0038 #include <kis_canvas2.h> 0039 #include <KisViewManager.h> 0040 #include <kis_floating_message.h> 0041 #include <kis_group_layer.h> 0042 #include <kis_resources_snapshot.h> 0043 0044 #include <kundo2command.h> 0045 #include <kis_crop_saved_extra_data.h> 0046 0047 0048 struct DecorationLine 0049 { 0050 QPointF start; 0051 QPointF end; 0052 enum Relation 0053 { 0054 Width, 0055 Height, 0056 Smallest, 0057 Largest 0058 }; 0059 Relation startXRelation; 0060 Relation startYRelation; 0061 Relation endXRelation; 0062 Relation endYRelation; 0063 }; 0064 0065 DecorationLine decors[20] = 0066 { 0067 //thirds 0068 {QPointF(0.0, 0.3333),QPointF(1.0, 0.3333), DecorationLine::Width, DecorationLine::Height, DecorationLine::Width, DecorationLine::Height}, 0069 {QPointF(0.0, 0.6666),QPointF(1.0, 0.6666), DecorationLine::Width, DecorationLine::Height, DecorationLine::Width, DecorationLine::Height}, 0070 {QPointF(0.3333, 0.0),QPointF(0.3333, 1.0), DecorationLine::Width, DecorationLine::Height, DecorationLine::Width, DecorationLine::Height}, 0071 {QPointF(0.6666, 0.0),QPointF(0.6666, 1.0), DecorationLine::Width, DecorationLine::Height, DecorationLine::Width, DecorationLine::Height}, 0072 0073 //fifths 0074 {QPointF(0.0, 0.2),QPointF(1.0, 0.2), DecorationLine::Width, DecorationLine::Height, DecorationLine::Width, DecorationLine::Height}, 0075 {QPointF(0.0, 0.4),QPointF(1.0, 0.4), DecorationLine::Width, DecorationLine::Height, DecorationLine::Width, DecorationLine::Height}, 0076 {QPointF(0.0, 0.6),QPointF(1.0, 0.6), DecorationLine::Width, DecorationLine::Height, DecorationLine::Width, DecorationLine::Height}, 0077 {QPointF(0.0, 0.8),QPointF(1.0, 0.8), DecorationLine::Width, DecorationLine::Height, DecorationLine::Width, DecorationLine::Height}, 0078 {QPointF(0.2, 0.0),QPointF(0.2, 1.0), DecorationLine::Width, DecorationLine::Height, DecorationLine::Width, DecorationLine::Height}, 0079 {QPointF(0.4, 0.0),QPointF(0.4, 1.0), DecorationLine::Width, DecorationLine::Height, DecorationLine::Width, DecorationLine::Height}, 0080 {QPointF(0.6, 0.0),QPointF(0.6, 1.0), DecorationLine::Width, DecorationLine::Height, DecorationLine::Width, DecorationLine::Height}, 0081 {QPointF(0.8, 0.0),QPointF(0.8, 1.0), DecorationLine::Width, DecorationLine::Height, DecorationLine::Width, DecorationLine::Height}, 0082 0083 // Passport photo 0084 {QPointF(0.0, 0.45/0.35),QPointF(1.0, 0.45/0.35), DecorationLine::Width, DecorationLine::Width, DecorationLine::Width, DecorationLine::Width}, 0085 {QPointF(0.2, 0.05/0.35),QPointF(0.8, 0.05/0.35), DecorationLine::Width, DecorationLine::Width, DecorationLine::Width, DecorationLine::Width}, 0086 {QPointF(0.2, 0.40/0.35),QPointF(0.8, 0.40/0.35), DecorationLine::Width, DecorationLine::Width, DecorationLine::Width, DecorationLine::Width}, 0087 {QPointF(0.25, 0.07/0.35),QPointF(0.75, 0.07/0.35), DecorationLine::Width, DecorationLine::Width, DecorationLine::Width, DecorationLine::Width}, 0088 {QPointF(0.25, 0.38/0.35),QPointF(0.75, 0.38/0.35), DecorationLine::Width, DecorationLine::Width, DecorationLine::Width, DecorationLine::Width}, 0089 {QPointF(0.35/0.45, 0.0),QPointF(0.35/0.45, 1.0), DecorationLine::Height, DecorationLine::Height, DecorationLine::Height, DecorationLine::Height}, 0090 0091 //Crosshair 0092 {QPointF(0.0, 0.5),QPointF(1.0, 0.5), DecorationLine::Width, DecorationLine::Height, DecorationLine::Width, DecorationLine::Height}, 0093 {QPointF(0.5, 0.0),QPointF(0.5, 1.0), DecorationLine::Width, DecorationLine::Height, DecorationLine::Width, DecorationLine::Height} 0094 }; 0095 0096 #define DECORATION_COUNT 5 0097 const int decorsIndex[DECORATION_COUNT] = {0,4,12,18,20}; 0098 0099 KisToolCrop::KisToolCrop(KoCanvasBase * canvas) 0100 : KisTool(canvas, KisCursor::load("tool_crop_cursor.png", 6, 6)) 0101 { 0102 setObjectName("tool_crop"); 0103 m_handleSize = 13; 0104 m_haveCropSelection = false; 0105 m_cropTypeSelectable = false; 0106 m_cropType = ImageCropType; 0107 m_decoration = 1; 0108 0109 connect(&m_finalRect, SIGNAL(sigValuesChanged()), SLOT(slotRectChanged())); 0110 connect(&m_finalRect, SIGNAL(sigLockValuesChanged()), SLOT(slotRectChanged())); 0111 0112 // context menu options (mirrors tool options) 0113 m_contextMenu.reset(new QMenu()); 0114 applyCrop = new KisAction(i18n("Crop")); 0115 0116 centerToggleOption = new KisAction(i18n("Center")); 0117 centerToggleOption->setCheckable(true); 0118 0119 growToggleOption = new KisAction(i18nc("Grow as in crop tool", "Grow")); 0120 growToggleOption->setCheckable(true); 0121 0122 lockWidthToggleOption = new KisAction(i18n("Lock Width")); 0123 lockWidthToggleOption->setCheckable(true); 0124 0125 lockHeightToggleOption = new KisAction(i18n("Lock Height")); 0126 lockHeightToggleOption->setCheckable(true); 0127 0128 lockRatioToggleOption = new KisAction(i18n("Lock Ratio")); 0129 lockRatioToggleOption->setCheckable(true); 0130 } 0131 0132 KisToolCrop::~KisToolCrop() 0133 { 0134 delete applyCrop; 0135 delete centerToggleOption; 0136 delete growToggleOption; 0137 delete lockWidthToggleOption; 0138 delete lockHeightToggleOption; 0139 delete lockRatioToggleOption; 0140 } 0141 0142 void KisToolCrop::activate(const QSet<KoShape*> &shapes) 0143 { 0144 0145 KisTool::activate(shapes); 0146 configGroup = KSharedConfig::openConfig()->group(toolId()); // save settings to kritarc 0147 0148 KisResourcesSnapshotSP resources = 0149 new KisResourcesSnapshot(image(), currentNode(), this->canvas()->resourceManager()); 0150 0151 0152 // load settings from configuration 0153 setGrowCenter(configGroup.readEntry("growCenter", false)); 0154 setAllowGrow(configGroup.readEntry("allowGrow", true)); 0155 0156 // Default: thirds decoration 0157 setDecoration(configGroup.readEntry("decoration", 1)); 0158 0159 // Default: crop the entire image 0160 setCropType(CropToolType(configGroup.readEntry("cropType", 0))); 0161 0162 m_finalRect.setCropRect(image()->bounds()); 0163 0164 KisSelectionSP sel = resources->activeSelection(); 0165 if (sel) { 0166 m_haveCropSelection = true; 0167 m_finalRect.setRectInitial(sel->selectedExactRect()); 0168 } 0169 useCursor(cursor()); 0170 0171 //pixel layer 0172 if(resources->currentNode() && resources->currentNode()->paintDevice()) { 0173 setCropTypeSelectable(true); 0174 } 0175 //vector layer 0176 else { 0177 if (m_cropType != ImageCropType && m_cropType != CanvasCropType) { 0178 setCropType(ImageCropType); 0179 } 0180 setCropTypeSelectable(false); 0181 } 0182 connect(&m_finalRect, SIGNAL(sigValuesChanged()), SLOT(showSizeOnCanvas())); 0183 } 0184 0185 void KisToolCrop::cancelStroke() 0186 { 0187 m_haveCropSelection = false; 0188 useCursor(cursor()); 0189 doCanvasUpdate(image()->bounds()); 0190 } 0191 0192 void KisToolCrop::deactivate() 0193 { 0194 cancelStroke(); 0195 KisTool::deactivate(); 0196 } 0197 0198 void KisToolCrop::requestStrokeEnd() 0199 { 0200 if (m_haveCropSelection) crop(); 0201 } 0202 0203 void KisToolCrop::requestStrokeCancellation() 0204 { 0205 cancelStroke(); 0206 } 0207 0208 void KisToolCrop::requestUndoDuringStroke() 0209 { 0210 cancelStroke(); 0211 } 0212 0213 void KisToolCrop::requestRedoDuringStroke() 0214 { 0215 cancelStroke(); 0216 } 0217 0218 void KisToolCrop::canvasResourceChanged(int key, const QVariant &res) 0219 { 0220 KisTool::canvasResourceChanged(key, res); 0221 0222 //pixel layer 0223 if(currentNode() && currentNode()->paintDevice()) { 0224 setCropTypeSelectable(true); 0225 } 0226 //vector layer 0227 else { 0228 if (m_cropType != ImageCropType && m_cropType != CanvasCropType) { 0229 setCropType(ImageCropType); 0230 } 0231 setCropTypeSelectable(false); 0232 } 0233 } 0234 0235 void KisToolCrop::paint(QPainter &painter, const KoViewConverter &converter) 0236 { 0237 Q_UNUSED(converter); 0238 paintOutlineWithHandles(painter); 0239 } 0240 0241 QMenu *KisToolCrop::popupActionsMenu() 0242 { 0243 if (m_contextMenu) { 0244 // Sync state of context menu toggles with state of Tool Options toggles 0245 centerToggleOption->setChecked(growCenter()); 0246 growToggleOption->setChecked(allowGrow()); 0247 lockWidthToggleOption->setChecked(lockWidth()); 0248 lockHeightToggleOption->setChecked(lockHeight()); 0249 lockRatioToggleOption->setChecked(lockRatio()); 0250 0251 m_contextMenu->clear(); 0252 0253 m_contextMenu->addSection(i18n("Crop Tool Actions")); 0254 m_contextMenu->addSeparator(); 0255 0256 if (m_haveCropSelection) { // can't crop if there is no selection 0257 m_contextMenu->addAction(applyCrop); 0258 m_contextMenu->addSeparator(); 0259 } 0260 0261 m_contextMenu->addAction(centerToggleOption); 0262 m_contextMenu->addAction(growToggleOption); 0263 0264 m_contextMenu->addSeparator(); 0265 0266 m_contextMenu->addAction(lockWidthToggleOption); 0267 m_contextMenu->addAction(lockHeightToggleOption); 0268 m_contextMenu->addAction(lockRatioToggleOption); 0269 } 0270 0271 return m_contextMenu.data(); 0272 } 0273 0274 void KisToolCrop::beginPrimaryAction(KoPointerEvent *event) 0275 { 0276 m_finalRect.setCropRect(image()->bounds()); 0277 setMode(KisTool::PAINT_MODE); 0278 0279 const QPointF imagePoint = convertToPixelCoord(event); 0280 m_mouseOnHandleType = mouseOnHandle(pixelToView(imagePoint)); 0281 0282 if (m_mouseOnHandleType != KisConstrainedRect::None) { 0283 QPointF snapPoint = m_finalRect.handleSnapPoint(KisConstrainedRect::HandleType(m_mouseOnHandleType), imagePoint); 0284 QPointF snapDocPoint = image()->pixelToDocument(snapPoint); 0285 m_dragOffsetDoc = snapDocPoint - event->point; 0286 } else { 0287 m_dragOffsetDoc = QPointF(); 0288 } 0289 0290 QPointF snappedPoint = convertToPixelCoordAndSnap(event, m_dragOffsetDoc); 0291 0292 m_dragStart = snappedPoint.toPoint(); 0293 m_resettingStroke = false; 0294 0295 if (!m_haveCropSelection || m_mouseOnHandleType == None) { 0296 m_lastCanvasUpdateRect = image()->bounds(); 0297 const int initialWidth = m_finalRect.widthLocked() ? m_finalRect.rect().width() : 1; 0298 const int initialHeight = m_finalRect.heightLocked() ? m_finalRect.rect().height() : 1; 0299 const QRect initialRect = QRect(m_dragStart, QSize(initialWidth, initialHeight)); 0300 m_finalRect.setRectInitial(initialRect); 0301 m_initialDragRect = initialRect; 0302 m_mouseOnHandleType = KisConstrainedRect::Creation; 0303 m_resettingStroke = true; 0304 } else { 0305 m_initialDragRect = m_finalRect.rect(); 0306 } 0307 } 0308 0309 void KisToolCrop::continuePrimaryAction(KoPointerEvent *event) 0310 { 0311 CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); 0312 0313 const QPointF pos = convertToPixelCoordAndSnap(event, m_dragOffsetDoc); 0314 const QPoint drag = pos.toPoint() - m_dragStart; 0315 0316 m_finalRect.moveHandle(KisConstrainedRect::HandleType(m_mouseOnHandleType), drag, m_initialDragRect); 0317 } 0318 0319 bool KisToolCrop::tryContinueLastCropAction() 0320 { 0321 bool result = false; 0322 0323 const KUndo2Command *lastCommand = image()->undoAdapter()->presentCommand(); 0324 const KisCropSavedExtraData *data = 0; 0325 0326 if ((lastCommand = image()->undoAdapter()->presentCommand()) && 0327 (data = dynamic_cast<const KisCropSavedExtraData*>(lastCommand->extraData()))) { 0328 0329 bool cropImageConsistent = 0330 m_cropType == ImageCropType && 0331 (data->type() == KisCropSavedExtraData::CROP_IMAGE || 0332 data->type() == KisCropSavedExtraData::RESIZE_IMAGE); 0333 0334 bool cropLayerConsistent = 0335 m_cropType == LayerCropType && 0336 data->type() == KisCropSavedExtraData::CROP_LAYER && 0337 currentNode() == data->cropNode(); 0338 0339 0340 if (cropImageConsistent || cropLayerConsistent) { 0341 image()->undoAdapter()->undoLastCommand(); 0342 image()->waitForDone(); 0343 0344 m_finalRect.setRectInitial(data->cropRect()); 0345 m_haveCropSelection = true; 0346 0347 result = true; 0348 } 0349 } 0350 0351 return result; 0352 } 0353 0354 void KisToolCrop::endPrimaryAction(KoPointerEvent *event) 0355 { 0356 CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); 0357 setMode(KisTool::HOVER_MODE); 0358 0359 QRectF viewCropRect = pixelToView(m_finalRect.rect()); 0360 const bool haveValidRect = 0361 viewCropRect.width() > m_handleSize && 0362 viewCropRect.height() > m_handleSize; 0363 0364 0365 if (!m_haveCropSelection && !haveValidRect) { 0366 if (!tryContinueLastCropAction()) { 0367 m_finalRect.setRectInitial(image()->bounds()); 0368 m_haveCropSelection = true; 0369 } 0370 } else if (m_resettingStroke && !haveValidRect) { 0371 m_lastCanvasUpdateRect = image()->bounds(); 0372 m_haveCropSelection = false; 0373 } else { 0374 m_haveCropSelection = true; 0375 } 0376 0377 m_finalRect.normalize(); 0378 0379 qint32 type = mouseOnHandle(pixelToView(convertToPixelCoordAndSnap(event, m_dragOffsetDoc))); 0380 setMoveResizeCursor(type); 0381 } 0382 0383 void KisToolCrop::mouseMoveEvent(KoPointerEvent *event) 0384 { 0385 QPointF pos = convertToPixelCoordAndSnap(event); 0386 0387 if (m_haveCropSelection) { //if the crop selection is set 0388 //set resize cursor if we are on one of the handles 0389 if(mode() == KisTool::PAINT_MODE) { 0390 //keep the same cursor as the one we clicked with 0391 setMoveResizeCursor(m_mouseOnHandleType); 0392 }else{ 0393 //hovering 0394 qint32 type = mouseOnHandle(pixelToView(pos)); 0395 setMoveResizeCursor(type); 0396 } 0397 } 0398 } 0399 0400 void KisToolCrop::beginPrimaryDoubleClickAction(KoPointerEvent *event) 0401 { 0402 if (m_haveCropSelection) crop(); 0403 0404 // this action will have no continuation 0405 event->ignore(); 0406 } 0407 0408 0409 #define BORDER_LINE_WIDTH 0 0410 #define HALF_BORDER_LINE_WIDTH 0 0411 #define HANDLE_BORDER_LINE_WIDTH 1 0412 0413 QRectF KisToolCrop::borderLineRect() 0414 { 0415 QRectF borderRect = pixelToView(m_finalRect.rect()); 0416 0417 // Draw the border line right next to the crop rectangle perimeter. 0418 borderRect.adjust(-HALF_BORDER_LINE_WIDTH, -HALF_BORDER_LINE_WIDTH, HALF_BORDER_LINE_WIDTH, HALF_BORDER_LINE_WIDTH); 0419 0420 return borderRect; 0421 } 0422 0423 #define OUTSIDE_CROP_ALPHA 200 0424 0425 void KisToolCrop::paintOutlineWithHandles(QPainter& gc) 0426 { 0427 if (canvas() && (mode() == KisTool::PAINT_MODE || m_haveCropSelection)) { 0428 gc.save(); 0429 0430 QRectF wholeImageRect = pixelToView(image()->bounds()); 0431 QRectF borderRect = borderLineRect(); 0432 0433 QPainterPath path; 0434 0435 path.addRect(wholeImageRect); 0436 path.addRect(borderRect); 0437 gc.setPen(Qt::NoPen); 0438 gc.setBrush(QColor(0, 0, 0, OUTSIDE_CROP_ALPHA)); 0439 gc.drawPath(path); 0440 0441 // Handles 0442 QPen pen(Qt::SolidLine); 0443 pen.setWidth(HANDLE_BORDER_LINE_WIDTH * decorationThickness()); 0444 pen.setColor(Qt::black); 0445 pen.setCosmetic(true); 0446 gc.setPen(pen); 0447 gc.setBrush(QColor(200, 200, 200, OUTSIDE_CROP_ALPHA)); 0448 gc.drawPath(handlesPath()); 0449 0450 gc.setClipRect(borderRect, Qt::IntersectClip); 0451 0452 if (m_decoration > 0) { 0453 for (int i = decorsIndex[m_decoration-1]; i<decorsIndex[m_decoration]; i++) { 0454 drawDecorationLine(&gc, &(decors[i]), borderRect); 0455 } 0456 } 0457 gc.restore(); 0458 } 0459 } 0460 0461 void KisToolCrop::crop() 0462 { 0463 KIS_ASSERT_RECOVER_RETURN(currentImage()); 0464 if (m_finalRect.rect().isEmpty()) return; 0465 0466 const bool imageCrop = m_cropType == ImageCropType || m_cropType == CanvasCropType; 0467 0468 if (!imageCrop) { 0469 //Cropping layer 0470 if (!nodeEditable()) { 0471 return; 0472 } 0473 } 0474 0475 m_haveCropSelection = false; 0476 useCursor(cursor()); 0477 0478 QRect cropRect = m_finalRect.rect(); 0479 0480 // The visitor adds the undo steps to the macro 0481 if (imageCrop || !currentNode()->paintDevice()) { 0482 if (m_cropType == CanvasCropType) { 0483 currentImage()->resizeImage(cropRect); 0484 } else { 0485 currentImage()->cropImage(cropRect); 0486 } 0487 } else { 0488 currentImage()->cropNode(currentNode(), cropRect, m_cropType == FrameCropType); 0489 } 0490 } 0491 0492 void KisToolCrop::setCropTypeLegacy(int cropType) 0493 { 0494 setCropType(static_cast<KisToolCrop::CropToolType>(cropType)); 0495 } 0496 0497 void KisToolCrop::setCropType(KisToolCrop::CropToolType cropType) 0498 { 0499 if(m_cropType == cropType) 0500 return; 0501 m_cropType = cropType; 0502 0503 configGroup.writeEntry("cropType", static_cast<int>(cropType)); 0504 0505 emit cropTypeChanged(m_cropType); 0506 } 0507 0508 KisToolCrop::CropToolType KisToolCrop::cropType() const 0509 { 0510 return m_cropType; 0511 } 0512 0513 void KisToolCrop::setCropTypeSelectable(bool selectable) 0514 { 0515 if(selectable == m_cropTypeSelectable) 0516 return; 0517 m_cropTypeSelectable = selectable; 0518 emit cropTypeSelectableChanged(); 0519 } 0520 0521 bool KisToolCrop::cropTypeSelectable() const 0522 { 0523 return m_cropTypeSelectable; 0524 } 0525 0526 int KisToolCrop::decoration() const 0527 { 0528 return m_decoration; 0529 } 0530 0531 void KisToolCrop::setDecoration(int i) 0532 { 0533 // This shouldn't happen, but safety first 0534 if(i < 0 || i > DECORATION_COUNT) 0535 return; 0536 m_decoration = i; 0537 emit decorationChanged(decoration()); 0538 updateCanvasViewRect(boundingRect()); 0539 0540 configGroup.writeEntry("decoration", i); 0541 } 0542 0543 void KisToolCrop::doCanvasUpdate(const QRect &updateRect) 0544 { 0545 updateCanvasViewRect(updateRect | m_lastCanvasUpdateRect); 0546 m_lastCanvasUpdateRect = updateRect; 0547 } 0548 0549 void KisToolCrop::slotRectChanged() 0550 { 0551 emit cropHeightChanged(cropHeight()); 0552 emit cropWidthChanged(cropWidth()); 0553 emit cropXChanged(cropX()); 0554 emit cropYChanged(cropY()); 0555 emit ratioChanged(ratio()); 0556 emit lockHeightChanged(lockHeight()); 0557 emit lockWidthChanged(lockWidth()); 0558 emit lockRatioChanged(lockRatio()); 0559 0560 emit canGrowChanged(allowGrow()); 0561 emit isCenteredChanged(growCenter()); 0562 0563 doCanvasUpdate(boundingRect().toAlignedRect()); 0564 } 0565 0566 void KisToolCrop::setCropX(int x) 0567 { 0568 if(x == m_finalRect.rect().x()) 0569 return; 0570 0571 if (!m_haveCropSelection) { 0572 m_haveCropSelection = true; 0573 m_finalRect.setRectInitial(image()->bounds()); 0574 } 0575 0576 QPoint offset = m_finalRect.rect().topLeft(); 0577 offset.setX(x); 0578 m_finalRect.setOffset(offset); 0579 } 0580 0581 int KisToolCrop::cropX() const 0582 { 0583 return m_finalRect.rect().x(); 0584 } 0585 0586 void KisToolCrop::setCropY(int y) 0587 { 0588 if(y == m_finalRect.rect().y()) 0589 return; 0590 0591 if (!m_haveCropSelection) { 0592 m_haveCropSelection = true; 0593 m_finalRect.setRectInitial(image()->bounds()); 0594 } 0595 0596 QPoint offset = m_finalRect.rect().topLeft(); 0597 offset.setY(y); 0598 m_finalRect.setOffset(offset); 0599 } 0600 0601 int KisToolCrop::cropY() const 0602 { 0603 return m_finalRect.rect().y(); 0604 } 0605 0606 void KisToolCrop::setCropWidth(int w) 0607 { 0608 if(w == m_finalRect.rect().width()) 0609 return; 0610 0611 if (!m_haveCropSelection) { 0612 m_haveCropSelection = true; 0613 m_finalRect.setRectInitial(image()->bounds()); 0614 } 0615 0616 m_finalRect.setWidth(w); 0617 } 0618 0619 int KisToolCrop::cropWidth() const 0620 { 0621 return m_finalRect.rect().width(); 0622 } 0623 0624 void KisToolCrop::setLockWidth(bool lock) 0625 { 0626 m_finalRect.setWidthLocked(lock); 0627 } 0628 0629 bool KisToolCrop::lockWidth() const 0630 { 0631 return m_finalRect.widthLocked(); 0632 } 0633 0634 void KisToolCrop::setCropHeight(int h) 0635 { 0636 if(h == m_finalRect.rect().height()) 0637 return; 0638 0639 if (!m_haveCropSelection) { 0640 m_haveCropSelection = true; 0641 m_finalRect.setRectInitial(image()->bounds()); 0642 } 0643 0644 m_finalRect.setHeight(h); 0645 } 0646 0647 int KisToolCrop::cropHeight() const 0648 { 0649 return m_finalRect.rect().height(); 0650 } 0651 0652 void KisToolCrop::setLockHeight(bool lock) 0653 { 0654 m_finalRect.setHeightLocked(lock); 0655 } 0656 0657 bool KisToolCrop::lockHeight() const 0658 { 0659 return m_finalRect.heightLocked(); 0660 } 0661 0662 void KisToolCrop::setAllowGrow(bool g) 0663 { 0664 m_finalRect.setCanGrow(g); 0665 m_finalRect.setCropRect(image()->bounds()); 0666 configGroup.writeEntry("allowGrow", g); 0667 0668 emit canGrowChanged(g); 0669 } 0670 0671 bool KisToolCrop::allowGrow() const 0672 { 0673 return m_finalRect.canGrow(); 0674 } 0675 0676 void KisToolCrop::setGrowCenter(bool value) 0677 { 0678 m_finalRect.setCentered(value); 0679 0680 0681 configGroup.writeEntry("growCenter", value); 0682 0683 emit isCenteredChanged(value); 0684 } 0685 0686 bool KisToolCrop::growCenter() const 0687 { 0688 return m_finalRect.centered(); 0689 } 0690 0691 void KisToolCrop::setRatio(double ratio) 0692 { 0693 if(ratio == m_finalRect.ratio()) 0694 return; 0695 0696 if (!m_haveCropSelection) { 0697 m_haveCropSelection = true; 0698 m_finalRect.setRectInitial(image()->bounds()); 0699 } 0700 0701 m_finalRect.setRatio(ratio); 0702 } 0703 0704 double KisToolCrop::ratio() const 0705 { 0706 return m_finalRect.ratio(); 0707 } 0708 0709 void KisToolCrop::setLockRatio(bool lock) 0710 { 0711 m_finalRect.setRatioLocked(lock); 0712 } 0713 0714 bool KisToolCrop::lockRatio() const 0715 { 0716 return m_finalRect.ratioLocked(); 0717 } 0718 0719 void KisToolCrop::showSizeOnCanvas() 0720 { 0721 KisCanvas2 *kisCanvas =dynamic_cast<KisCanvas2*>(canvas()); 0722 Q_ASSERT(kisCanvas); 0723 if(m_mouseOnHandleType == 9) { 0724 kisCanvas->viewManager()->showFloatingMessage(i18n("X: %1\nY: %2" 0725 , optionsWidget->intX->text(), optionsWidget->intY->text()) 0726 , QIcon(), 1000, KisFloatingMessage::High, Qt::AlignLeft | Qt::TextWordWrap | Qt::AlignVCenter); 0727 } 0728 else { 0729 kisCanvas->viewManager()->showFloatingMessage(i18n("Width: %1\nHeight: %2" 0730 , optionsWidget->intWidth->text(), optionsWidget->intHeight->text()) 0731 , QIcon(), 1000, KisFloatingMessage::High, Qt::AlignLeft | Qt::TextWordWrap | Qt::AlignVCenter); 0732 } 0733 } 0734 0735 QWidget* KisToolCrop::createOptionWidget() 0736 { 0737 optionsWidget = new KisToolCropConfigWidget(0, this); 0738 // See https://bugs.kde.org/show_bug.cgi?id=316896 0739 QWidget *specialSpacer = new QWidget(optionsWidget); 0740 specialSpacer->setObjectName("SpecialSpacer"); 0741 specialSpacer->setFixedSize(0, 0); 0742 optionsWidget->layout()->addWidget(specialSpacer); 0743 0744 Q_CHECK_PTR(optionsWidget); 0745 optionsWidget->setObjectName(toolId() + " option widget"); 0746 0747 connect(optionsWidget->bnCrop, SIGNAL(clicked()), this, SLOT(crop())); 0748 0749 connect(optionsWidget, SIGNAL(cropTypeChanged(int)), this, SLOT(setCropTypeLegacy(int))); 0750 connect(optionsWidget, SIGNAL(cropXChanged(int)), this, SLOT(setCropX(int))); 0751 connect(optionsWidget, SIGNAL(cropYChanged(int)), this, SLOT(setCropY(int))); 0752 connect(optionsWidget, SIGNAL(cropHeightChanged(int)), this, SLOT(setCropHeight(int))); 0753 connect(optionsWidget, SIGNAL(lockHeightChanged(bool)), this, SLOT(setLockHeight(bool))); 0754 connect(optionsWidget, SIGNAL(cropWidthChanged(int)), this, SLOT(setCropWidth(int))); 0755 connect(optionsWidget, SIGNAL(lockWidthChanged(bool)), this, SLOT(setLockWidth(bool))); 0756 connect(optionsWidget, SIGNAL(ratioChanged(double)), this, SLOT(setRatio(double))); 0757 connect(optionsWidget, SIGNAL(lockRatioChanged(bool)), this, SLOT(setLockRatio(bool))); 0758 connect(optionsWidget, SIGNAL(decorationChanged(int)), this, SLOT(setDecoration(int))); 0759 connect(optionsWidget, SIGNAL(allowGrowChanged(bool)), this, SLOT(setAllowGrow(bool))); 0760 connect(optionsWidget, SIGNAL(growCenterChanged(bool)), this, SLOT(setGrowCenter(bool))); 0761 0762 optionsWidget->setFixedHeight(optionsWidget->sizeHint().height()); 0763 0764 connect(applyCrop, SIGNAL(triggered(bool)), this, SLOT(crop())); 0765 connect(centerToggleOption, SIGNAL(triggered(bool)), this, SLOT(setGrowCenter(bool))); 0766 connect(growToggleOption, SIGNAL(triggered(bool)), this, SLOT(setAllowGrow(bool))); 0767 connect(lockWidthToggleOption, SIGNAL(triggered(bool)), this, SLOT(setLockWidth(bool))); 0768 connect(lockHeightToggleOption, SIGNAL(triggered(bool)), this, SLOT(setLockHeight(bool))); 0769 connect(lockRatioToggleOption, SIGNAL(triggered(bool)), this, SLOT(setLockRatio(bool))); 0770 0771 return optionsWidget; 0772 } 0773 0774 QRectF KisToolCrop::lowerRightHandleRect(QRectF cropBorderRect) 0775 { 0776 return QRectF(cropBorderRect.right() - m_handleSize / 2.0, cropBorderRect.bottom() - m_handleSize / 2.0, m_handleSize, m_handleSize); 0777 } 0778 0779 QRectF KisToolCrop::upperRightHandleRect(QRectF cropBorderRect) 0780 { 0781 return QRectF(cropBorderRect.right() - m_handleSize / 2.0 , cropBorderRect.top() - m_handleSize / 2.0, m_handleSize, m_handleSize); 0782 } 0783 0784 QRectF KisToolCrop::lowerLeftHandleRect(QRectF cropBorderRect) 0785 { 0786 return QRectF(cropBorderRect.left() - m_handleSize / 2.0 , cropBorderRect.bottom() - m_handleSize / 2.0, m_handleSize, m_handleSize); 0787 } 0788 0789 QRectF KisToolCrop::upperLeftHandleRect(QRectF cropBorderRect) 0790 { 0791 return QRectF(cropBorderRect.left() - m_handleSize / 2.0, cropBorderRect.top() - m_handleSize / 2.0, m_handleSize, m_handleSize); 0792 } 0793 0794 QRectF KisToolCrop::lowerHandleRect(QRectF cropBorderRect) 0795 { 0796 return QRectF(cropBorderRect.left() + (cropBorderRect.width() - m_handleSize) / 2.0 , cropBorderRect.bottom() - m_handleSize / 2.0, m_handleSize, m_handleSize); 0797 } 0798 0799 QRectF KisToolCrop::rightHandleRect(QRectF cropBorderRect) 0800 { 0801 return QRectF(cropBorderRect.right() - m_handleSize / 2.0 , cropBorderRect.top() + (cropBorderRect.height() - m_handleSize) / 2.0, m_handleSize, m_handleSize); 0802 } 0803 0804 QRectF KisToolCrop::upperHandleRect(QRectF cropBorderRect) 0805 { 0806 return QRectF(cropBorderRect.left() + (cropBorderRect.width() - m_handleSize) / 2.0 , cropBorderRect.top() - m_handleSize / 2.0, m_handleSize, m_handleSize); 0807 } 0808 0809 QRectF KisToolCrop::leftHandleRect(QRectF cropBorderRect) 0810 { 0811 return QRectF(cropBorderRect.left() - m_handleSize / 2.0, cropBorderRect.top() + (cropBorderRect.height() - m_handleSize) / 2.0, m_handleSize, m_handleSize); 0812 } 0813 0814 QPainterPath KisToolCrop::handlesPath() 0815 { 0816 QRectF cropBorderRect = borderLineRect(); 0817 QPainterPath path; 0818 0819 path.addRect(upperLeftHandleRect(cropBorderRect)); 0820 path.addRect(upperRightHandleRect(cropBorderRect)); 0821 path.addRect(lowerLeftHandleRect(cropBorderRect)); 0822 path.addRect(lowerRightHandleRect(cropBorderRect)); 0823 path.addRect(upperHandleRect(cropBorderRect)); 0824 path.addRect(lowerHandleRect(cropBorderRect)); 0825 path.addRect(leftHandleRect(cropBorderRect)); 0826 path.addRect(rightHandleRect(cropBorderRect)); 0827 0828 return path; 0829 } 0830 0831 qint32 KisToolCrop::mouseOnHandle(QPointF currentViewPoint) 0832 { 0833 QRectF borderRect = borderLineRect(); 0834 qint32 handleType = None; 0835 0836 if (!m_haveCropSelection) { 0837 return None; 0838 } 0839 0840 if (upperLeftHandleRect(borderRect).contains(currentViewPoint)) { 0841 handleType = UpperLeft; 0842 } else if (lowerLeftHandleRect(borderRect).contains(currentViewPoint)) { 0843 handleType = LowerLeft; 0844 } else if (upperRightHandleRect(borderRect).contains(currentViewPoint)) { 0845 handleType = UpperRight; 0846 } else if (lowerRightHandleRect(borderRect).contains(currentViewPoint)) { 0847 handleType = LowerRight; 0848 } else if (upperHandleRect(borderRect).contains(currentViewPoint)) { 0849 handleType = Upper; 0850 } else if (lowerHandleRect(borderRect).contains(currentViewPoint)) { 0851 handleType = Lower; 0852 } else if (leftHandleRect(borderRect).contains(currentViewPoint)) { 0853 handleType = Left; 0854 } else if (rightHandleRect(borderRect).contains(currentViewPoint)) { 0855 handleType = Right; 0856 } else if (borderRect.contains(currentViewPoint)) { 0857 handleType = Inside; 0858 } 0859 0860 return handleType; 0861 } 0862 0863 void KisToolCrop::setMoveResizeCursor(qint32 handle) 0864 { 0865 QCursor cursorType; 0866 0867 switch (handle) { 0868 case(UpperLeft): 0869 case(LowerRight): 0870 cursorType = KisCursor::sizeFDiagCursor(); 0871 break; 0872 case(LowerLeft): 0873 case(UpperRight): 0874 cursorType = KisCursor::sizeBDiagCursor(); 0875 break; 0876 case(Upper): 0877 case(Lower): 0878 cursorType = KisCursor::sizeVerCursor(); 0879 break; 0880 case(Left): 0881 case(Right): 0882 cursorType = KisCursor::sizeHorCursor(); 0883 break; 0884 case(Inside): 0885 cursorType = KisCursor::sizeAllCursor(); 0886 break; 0887 default: 0888 if (m_haveCropSelection) { 0889 cursorType = KisCursor::arrowCursor(); 0890 } else { 0891 cursorType = cursor(); 0892 } 0893 break; 0894 } 0895 useCursor(cursorType); 0896 } 0897 0898 QRectF KisToolCrop::boundingRect() 0899 { 0900 QRectF rect = handlesPath().boundingRect(); 0901 rect.adjust(-HANDLE_BORDER_LINE_WIDTH, -HANDLE_BORDER_LINE_WIDTH, HANDLE_BORDER_LINE_WIDTH, HANDLE_BORDER_LINE_WIDTH); 0902 return rect; 0903 } 0904 0905 void KisToolCrop::drawDecorationLine(QPainter *p, DecorationLine *decorLine, const QRectF rect) 0906 { 0907 QPointF start = rect.topLeft(); 0908 QPointF end = rect.topLeft(); 0909 qreal small = qMin(rect.width(), rect.height()); 0910 qreal large = qMax(rect.width(), rect.height()); 0911 0912 switch (decorLine->startXRelation) { 0913 case DecorationLine::Width: 0914 start.setX(start.x() + decorLine->start.x() * rect.width()); 0915 break; 0916 case DecorationLine::Height: 0917 start.setX(start.x() + decorLine->start.x() * rect.height()); 0918 break; 0919 case DecorationLine::Smallest: 0920 start.setX(start.x() + decorLine->start.x() * small); 0921 break; 0922 case DecorationLine::Largest: 0923 start.setX(start.x() + decorLine->start.x() * large); 0924 break; 0925 } 0926 0927 switch (decorLine->startYRelation) { 0928 case DecorationLine::Width: 0929 start.setY(start.y() + decorLine->start.y() * rect.width()); 0930 break; 0931 case DecorationLine::Height: 0932 start.setY(start.y() + decorLine->start.y() * rect.height()); 0933 break; 0934 case DecorationLine::Smallest: 0935 start.setY(start.y() + decorLine->start.y() * small); 0936 break; 0937 case DecorationLine::Largest: 0938 start.setY(start.y() + decorLine->start.y() * large); 0939 break; 0940 } 0941 0942 switch (decorLine->endXRelation) { 0943 case DecorationLine::Width: 0944 end.setX(end.x() + decorLine->end.x() * rect.width()); 0945 break; 0946 case DecorationLine::Height: 0947 end.setX(end.x() + decorLine->end.x() * rect.height()); 0948 break; 0949 case DecorationLine::Smallest: 0950 end.setX(end.x() + decorLine->end.x() * small); 0951 break; 0952 case DecorationLine::Largest: 0953 end.setX(end.x() + decorLine->end.x() * large); 0954 break; 0955 } 0956 0957 switch (decorLine->endYRelation) { 0958 case DecorationLine::Width: 0959 end.setY(end.y() + decorLine->end.y() * rect.width()); 0960 break; 0961 case DecorationLine::Height: 0962 end.setY(end.y() + decorLine->end.y() * rect.height()); 0963 break; 0964 case DecorationLine::Smallest: 0965 end.setY(end.y() + decorLine->end.y() * small); 0966 break; 0967 case DecorationLine::Largest: 0968 end.setY(end.y() + decorLine->end.y() * large); 0969 break; 0970 } 0971 0972 p->drawLine(start, end); 0973 }