File indexing completed on 2024-04-21 04:52:24
0001 /* 0002 SPDX-FileCopyrightText: 2008 Marco Gittler <g.marco@freenet.de> 0003 SPDX-FileCopyrightText: 2008 Jean-Baptiste Mardelle <jb@kdenlive.org> 0004 0005 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "graphicsscenerectmove.h" 0009 #include "kdenlivesettings.h" 0010 #include "titler/gradientwidget.h" 0011 #include "titler/titledocument.h" 0012 0013 #include "kdenlive_debug.h" 0014 #include <QApplication> 0015 #include <QCursor> 0016 #include <QGraphicsRectItem> 0017 #include <QGraphicsSceneMouseEvent> 0018 #include <QGraphicsView> 0019 #include <QKeyEvent> 0020 #include <QList> 0021 #include <QScrollBar> 0022 #include <QTextBlock> 0023 #include <QTextCursor> 0024 #include <QTextDocument> 0025 #include <utility> 0026 0027 static int TITLERVERSION = 0; 0028 0029 MyQGraphicsEffect::MyQGraphicsEffect(QObject *parent) 0030 : QGraphicsEffect(parent) 0031 0032 { 0033 } 0034 0035 void MyQGraphicsEffect::setShadow(const QImage &image) 0036 { 0037 m_shadow = image; 0038 } 0039 0040 void MyQGraphicsEffect::setOffset(int xOffset, int yOffset, int blur) 0041 { 0042 m_xOffset = xOffset; 0043 m_yOffset = yOffset; 0044 m_blur = blur; 0045 updateBoundingRect(); 0046 } 0047 0048 void MyQGraphicsEffect::draw(QPainter *painter) 0049 { 0050 painter->fillRect(boundingRect(), Qt::transparent); 0051 painter->drawImage(-2 * m_blur + m_xOffset, -2 * m_blur + m_yOffset, m_shadow); 0052 drawSource(painter); 0053 } 0054 0055 MyTextItem::MyTextItem(const QString &txt, QGraphicsItem *parent) 0056 : QGraphicsTextItem(txt, parent) 0057 , m_alignment(QFlags<Qt::AlignmentFlag>()) 0058 { 0059 // Disabled because cache makes text cursor invisible and borders ugly 0060 // setCacheMode(QGraphicsItem::ItemCoordinateCache); 0061 setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); 0062 document()->setDocumentMargin(0); 0063 m_shadowEffect = new MyQGraphicsEffect(this); 0064 m_shadowEffect->setEnabled(false); 0065 setGraphicsEffect(m_shadowEffect); 0066 updateGeometry(); 0067 connect(document(), &QTextDocument::contentsChange, this, &MyTextItem::doUpdateGeometry); 0068 updateTW(false, 2, 1, 0, 0); 0069 } 0070 0071 Qt::Alignment MyTextItem::alignment() const 0072 { 0073 return m_alignment; 0074 } 0075 0076 void MyTextItem::updateShadow(bool enabled, int blur, int xoffset, int yoffset, QColor color) 0077 { 0078 m_shadowOffset = QPoint(xoffset, yoffset); 0079 m_shadowBlur = blur; 0080 m_shadowColor = std::move(color); 0081 m_shadowEffect->setEnabled(enabled); 0082 m_shadowEffect->setOffset(xoffset, yoffset, blur); 0083 if (enabled) { 0084 updateShadow(); 0085 } 0086 update(); 0087 } 0088 0089 void MyTextItem::setTextColor(const QColor &col) 0090 { 0091 setDefaultTextColor(col); 0092 refreshFormat(); 0093 } 0094 0095 QStringList MyTextItem::shadowInfo() const 0096 { 0097 QStringList info; 0098 info << QString::number(static_cast<int>(m_shadowEffect->isEnabled())) << m_shadowColor.name(QColor::HexArgb) << QString::number(m_shadowBlur) 0099 << QString::number(m_shadowOffset.x()) << QString::number(m_shadowOffset.y()); 0100 return info; 0101 } 0102 0103 void MyTextItem::loadShadow(const QStringList &info) 0104 { 0105 if (info.count() < 5) { 0106 return; 0107 } 0108 updateShadow((static_cast<bool>(info.at(0).toInt())), info.at(2).toInt(), info.at(3).toInt(), info.at(4).toInt(), QColor(info.at(1))); 0109 } 0110 0111 void MyTextItem::setAlignment(Qt::Alignment alignment) 0112 { 0113 m_alignment = alignment; 0114 QTextBlockFormat format; 0115 format.setAlignment(alignment); 0116 QTextCursor cursor = textCursor(); // save cursor position 0117 int position = textCursor().position(); 0118 cursor.select(QTextCursor::Document); 0119 cursor.mergeBlockFormat(format); 0120 cursor.clearSelection(); 0121 cursor.setPosition(position); // restore cursor position 0122 setTextCursor(cursor); 0123 } 0124 0125 void MyTextItem::refreshFormat() 0126 { 0127 QString gradientData = data(TitleDocument::Gradient).toString(); 0128 QTextCursor cursor = textCursor(); 0129 QTextCharFormat cformat; 0130 cursor.select(QTextCursor::Document); 0131 int position = textCursor().position(); 0132 0133 // Formatting can be lost on paste, since our QTextCursor gets overwritten, so re-apply all formatting here 0134 QColor fgColor = defaultTextColor(); 0135 cformat.setForeground(fgColor); 0136 cformat.setFont(font()); 0137 0138 if (!gradientData.isEmpty()) { 0139 QRectF rect = boundingRect(); 0140 QLinearGradient gr = GradientWidget::gradientFromString(gradientData, int(rect.width()), int(rect.height())); 0141 cformat.setForeground(QBrush(gr)); 0142 } 0143 0144 // Apply 0145 cursor.mergeCharFormat(cformat); 0146 // restore cursor position 0147 cursor.clearSelection(); 0148 cursor.setPosition(position); 0149 setTextCursor(cursor); 0150 } 0151 0152 void MyTextItem::doUpdateGeometry() 0153 { 0154 updateGeometry(); 0155 // update gradient if necessary 0156 refreshFormat(); 0157 0158 QString text = toPlainText(); 0159 m_path = QPainterPath(); 0160 m_path.setFillRule(Qt::WindingFill); 0161 if (text.isEmpty()) { 0162 // 0163 } else { 0164 QFontMetrics metrics(font()); 0165 double lineSpacing = data(TitleDocument::LineSpacing).toInt() + metrics.lineSpacing(); 0166 0167 // Calculate line width 0168 const QStringList lines = text.split(QLatin1Char('\n')); 0169 double linePos = metrics.ascent(); 0170 QRectF bounding = boundingRect(); 0171 /*if (lines.count() > 0) { 0172 lineSpacing = bounding.height() / lines.count(); 0173 if (lineSpacing != data(TitleDocument::LineSpacing).toInt() + metrics.lineSpacing()) { 0174 linePos = 2 * lineSpacing - metrics.descent() - metrics.height(); 0175 } 0176 }*/ 0177 0178 for (const QString &line : lines) { 0179 QPainterPath linePath; 0180 linePath.addText(0, linePos, font(), line); 0181 linePos += lineSpacing; 0182 if (m_alignment == Qt::AlignHCenter) { 0183 double offset = (bounding.width() - metrics.horizontalAdvance(line)) / 2; 0184 linePath.translate(offset, 0); 0185 } else if (m_alignment == Qt::AlignRight) { 0186 double offset = bounding.width() - metrics.horizontalAdvance(line); 0187 linePath.translate(offset, 0); 0188 } 0189 m_path.addPath(linePath); 0190 } 0191 } 0192 0193 if (m_shadowEffect->isEnabled()) { 0194 updateShadow(); 0195 } 0196 update(); 0197 } 0198 0199 void MyTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *w) 0200 { 0201 if ((textInteractionFlags() & static_cast<int>((Qt::TextEditable) != 0)) != 0) { 0202 document()->setDocumentMargin(0); 0203 QGraphicsTextItem::paint(painter, option, w); 0204 } else { 0205 painter->setRenderHint(QPainter::Antialiasing); 0206 int outline = data(TitleDocument::OutlineWidth).toInt(); 0207 QString gradientData = data(TitleDocument::Gradient).toString(); 0208 QTextCursor cursor(document()); 0209 cursor.select(QTextCursor::Document); 0210 QBrush paintBrush; 0211 if (gradientData.isEmpty()) { 0212 paintBrush = QBrush(cursor.charFormat().foreground().color()); 0213 } else { 0214 QRectF rect = boundingRect(); 0215 paintBrush = QBrush(GradientWidget::gradientFromString(gradientData, int(rect.width()), int(rect.height()))); 0216 } 0217 if (TITLERVERSION < 300) { 0218 painter->fillPath(m_path, paintBrush); 0219 } 0220 if (outline > 0) { 0221 QVariant variant = data(TitleDocument::OutlineColor); 0222 QColor outlineColor = variant.value<QColor>(); 0223 QPen pen(outlineColor); 0224 pen.setWidthF(outline); 0225 painter->strokePath(m_path.simplified(), pen); 0226 } 0227 if (TITLERVERSION >= 300) { 0228 painter->fillPath(m_path, paintBrush); 0229 } 0230 document()->setDocumentMargin(toPlainText().isEmpty() ? 6 : 0); 0231 if (isSelected() || toPlainText().isEmpty()) { 0232 QPen pen(isSelected() ? Qt::red : Qt::blue); 0233 pen.setStyle(Qt::DashLine); 0234 painter->setPen(pen); 0235 painter->drawRect(boundingRect()); 0236 } 0237 } 0238 } 0239 0240 void MyTextItem::updateTW(bool enabled, int step, int mode, int sigma, int seed) 0241 { 0242 m_tw_enabled = enabled; 0243 m_tw_step = step; 0244 m_tw_mode = mode; 0245 m_tw_sigma = sigma; 0246 m_tw_seed = seed; 0247 } 0248 0249 void MyTextItem::loadTW(const QStringList &info) 0250 { 0251 if (info.count() < 5) { 0252 return; 0253 } 0254 updateTW((static_cast<bool>(info.at(0).toInt())), info.at(1).toInt(), info.at(2).toInt(), info.at(3).toInt(), info.at(4).toInt()); 0255 } 0256 0257 QStringList MyTextItem::twInfo() const 0258 { 0259 QStringList info; 0260 info << QString::number(int(m_tw_enabled)) << QString::number(m_tw_step) << QString::number(m_tw_mode) << QString::number(m_tw_sigma) 0261 << QString::number(m_tw_seed); 0262 return info; 0263 } 0264 0265 void MyTextItem::updateShadow() 0266 { 0267 QString text = toPlainText(); 0268 if (text.isEmpty()) { 0269 m_shadowEffect->setShadow(QImage()); 0270 return; 0271 } 0272 QRectF bounding = boundingRect(); 0273 QPainterPath path = m_path; 0274 // Calculate position of text in parent item 0275 path.translate(QPointF(2 * m_shadowBlur, 2 * m_shadowBlur)); 0276 QRectF fullSize = bounding.united(path.boundingRect()); 0277 QImage shadow(int(fullSize.width()) + qAbs(m_shadowOffset.x()) + 4 * m_shadowBlur, int(fullSize.height()) + qAbs(m_shadowOffset.y()) + 4 * m_shadowBlur, 0278 QImage::Format_ARGB32_Premultiplied); 0279 shadow.fill(Qt::transparent); 0280 0281 QPainter painter(&shadow); 0282 int outline = data(TitleDocument::OutlineWidth).toInt(); 0283 if (outline > 0) { 0284 QPainterPathStroker strokePath; 0285 strokePath.setWidth(outline); 0286 QPainterPath stroke = strokePath.createStroke(path); 0287 path.addPath(stroke); 0288 } 0289 painter.fillPath(path, QBrush(m_shadowColor)); 0290 painter.end(); 0291 if (m_shadowBlur > 0) { 0292 blurShadow(shadow, m_shadowBlur); 0293 } 0294 m_shadowEffect->setShadow(shadow); 0295 } 0296 0297 void MyTextItem::blurShadow(QImage &result, int radius) 0298 { 0299 int tab[] = {14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2}; 0300 int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius - 1]; 0301 0302 int r1 = 0; 0303 int r2 = result.height() - 1; 0304 int c1 = 0; 0305 int c2 = result.width() - 1; 0306 0307 int bpl = result.bytesPerLine(); 0308 int rgba[4]; 0309 unsigned char *p; 0310 0311 int i1 = 0; 0312 int i2 = 3; 0313 0314 for (int col = c1; col <= c2; col++) { 0315 p = result.scanLine(r1) + col * 4; 0316 for (int i = i1; i <= i2; i++) { 0317 rgba[i] = p[i] << 4; 0318 } 0319 0320 p += bpl; 0321 for (int j = r1; j < r2; j++, p += bpl) 0322 for (int i = i1; i <= i2; i++) { 0323 p[i] = uchar((rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4); 0324 } 0325 } 0326 0327 for (int row = r1; row <= r2; row++) { 0328 p = result.scanLine(row) + c1 * 4; 0329 for (int i = i1; i <= i2; i++) { 0330 rgba[i] = p[i] << 4; 0331 } 0332 0333 p += 4; 0334 for (int j = c1; j < c2; j++, p += 4) 0335 for (int i = i1; i <= i2; i++) { 0336 p[i] = uchar((rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4); 0337 } 0338 } 0339 0340 for (int col = c1; col <= c2; col++) { 0341 p = result.scanLine(r2) + col * 4; 0342 for (int i = i1; i <= i2; i++) { 0343 rgba[i] = p[i] << 4; 0344 } 0345 0346 p -= bpl; 0347 for (int j = r1; j < r2; j++, p -= bpl) 0348 for (int i = i1; i <= i2; i++) { 0349 p[i] = uchar((rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4); 0350 } 0351 } 0352 0353 for (int row = r1; row <= r2; row++) { 0354 p = result.scanLine(row) + c2 * 4; 0355 for (int i = i1; i <= i2; i++) { 0356 rgba[i] = p[i] << 4; 0357 } 0358 0359 p -= 4; 0360 for (int j = c1; j < c2; j++, p -= 4) 0361 for (int i = i1; i <= i2; i++) { 0362 p[i] = uchar((rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4); 0363 } 0364 } 0365 } 0366 0367 void MyTextItem::updateGeometry() 0368 { 0369 QPointF topRightPrev = boundingRect().topRight(); 0370 setTextWidth(-1); 0371 setTextWidth(boundingRect().width()); 0372 setAlignment(m_alignment); 0373 QPointF topRight = boundingRect().topRight(); 0374 0375 // if the text is right-aligned, then shift the container leftwards by the 0376 // same amount it grew to maintain right-alignment 0377 if (m_alignment & Qt::AlignRight) { 0378 setPos(pos() + (topRightPrev - topRight)); 0379 } 0380 // likewise, shift it halfway if we're center-aligned 0381 else if (m_alignment & Qt::AlignHCenter) { 0382 setPos(pos() + (topRightPrev - topRight) / 2); 0383 } 0384 } 0385 0386 QRectF MyTextItem::baseBoundingRect() const 0387 { 0388 // Ensure text document layout is updated 0389 document()->documentLayout(); 0390 QRectF base = QGraphicsTextItem::boundingRect(); 0391 QTextCursor cur(document()); 0392 cur.select(QTextCursor::Document); 0393 QTextBlockFormat format = cur.blockFormat(); 0394 int lineHeight = int(format.lineHeight()); 0395 int lineHeight2 = QFontMetrics(font()).lineSpacing(); 0396 int blkCount = document()->blockCount(); 0397 int lines = 0; 0398 for (int i = 0; i < blkCount; i++) { 0399 QTextBlock block = document()->findBlockByNumber(i); 0400 lines += block.layout()->lineCount(); 0401 } 0402 if (lines > 1) { 0403 base.setHeight(lines * lineHeight2 + lineHeight * (lines - 1)); 0404 } 0405 return base; 0406 } 0407 0408 QRectF MyTextItem::boundingRect() const 0409 { 0410 QRectF base = baseBoundingRect(); 0411 if (m_shadowEffect->isEnabled() && m_shadowOffset.x() > 0) { 0412 base.setRight(base.right() + m_shadowOffset.x()); 0413 } 0414 if (m_shadowEffect->isEnabled() && m_shadowOffset.y() > 0) { 0415 base.setBottom(base.bottom() + m_shadowOffset.y()); 0416 } 0417 return base; 0418 } 0419 0420 QVariant MyTextItem::itemChange(GraphicsItemChange change, const QVariant &value) 0421 { 0422 if (change == ItemPositionChange && (scene() != nullptr)) { 0423 QPoint newPos = value.toPoint(); 0424 if (QApplication::mouseButtons() == Qt::LeftButton && (qobject_cast<GraphicsSceneRectMove *>(scene()) != nullptr)) { 0425 auto *customScene = qobject_cast<GraphicsSceneRectMove *>(scene()); 0426 int gridSize = customScene->gridSize(); 0427 int xV = (newPos.x() / gridSize) * gridSize; 0428 int yV = (newPos.y() / gridSize) * gridSize; 0429 if (QApplication::keyboardModifiers() == Qt::ShiftModifier) { 0430 xV = pos().x(); 0431 } 0432 if (QApplication::keyboardModifiers() == (Qt::ShiftModifier | Qt::AltModifier)) { 0433 yV = pos().y(); 0434 } 0435 newPos = QPoint(xV, yV); 0436 } 0437 return newPos; 0438 } 0439 if (change == QGraphicsItem::ItemSelectedHasChanged) { 0440 if (!value.toBool()) { 0441 // Make sure to deselect text when item loses focus 0442 QTextCursor cur(document()); 0443 cur.clearSelection(); 0444 setTextCursor(cur); 0445 } 0446 } 0447 return QGraphicsItem::itemChange(change, value); 0448 } 0449 0450 void MyTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *evt) 0451 { 0452 if (textInteractionFlags() == Qt::TextEditorInteraction) { 0453 // if editor mode is already on: pass double click events on to the editor: 0454 QGraphicsTextItem::mouseDoubleClickEvent(evt); 0455 return; 0456 } 0457 // if editor mode is off: 0458 // 1. turn editor mode on and set selected and focused: 0459 // SetTextInteraction(true); 0460 setTextInteractionFlags(Qt::TextEditorInteraction); 0461 setFocus(Qt::MouseFocusReason); 0462 setCursor(QCursor(Qt::IBeamCursor)); 0463 // 2. send a single click to this QGraphicsTextItem (this will set the cursor to the mouse position): 0464 // create a new mouse event with the same parameters as evt 0465 auto *click = new QGraphicsSceneMouseEvent(QEvent::GraphicsSceneMousePress); 0466 click->setButton(evt->button()); 0467 click->setPos(evt->pos()); 0468 QGraphicsTextItem::mousePressEvent(click); 0469 delete click; // don't forget to delete the event 0470 } 0471 0472 MyRectItem::MyRectItem(QGraphicsItem *parent) 0473 : QGraphicsRectItem(parent) 0474 { 0475 // Disabled because cache makes text cursor invisible and borders ugly 0476 // setCacheMode(QGraphicsItem::ItemCoordinateCache); 0477 setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); 0478 } 0479 0480 void MyRectItem::setRect(const QRectF &rectangle) 0481 { 0482 QGraphicsRectItem::setRect(rectangle); 0483 if (m_rect != rectangle && !data(TitleDocument::Gradient).isNull()) { 0484 m_rect = rectangle; 0485 QLinearGradient gr = GradientWidget::gradientFromString(data(TitleDocument::Gradient).toString(), int(m_rect.width()), int(m_rect.height())); 0486 setBrush(QBrush(gr)); 0487 } 0488 } 0489 0490 QVariant MyRectItem::itemChange(GraphicsItemChange change, const QVariant &value) 0491 { 0492 if (change == ItemPositionChange && (scene() != nullptr)) { 0493 QPoint newPos = value.toPoint(); 0494 if (QApplication::mouseButtons() == Qt::LeftButton && (qobject_cast<GraphicsSceneRectMove *>(scene()) != nullptr)) { 0495 auto *customScene = qobject_cast<GraphicsSceneRectMove *>(scene()); 0496 int gridSize = customScene->gridSize(); 0497 int xV = (newPos.x() / gridSize) * gridSize; 0498 int yV = (newPos.y() / gridSize) * gridSize; 0499 if (QApplication::keyboardModifiers() == Qt::ShiftModifier) { 0500 xV = pos().x(); 0501 } 0502 if (QApplication::keyboardModifiers() == (Qt::ShiftModifier | Qt::AltModifier)) { 0503 yV = pos().y(); 0504 } 0505 newPos = QPoint(xV, yV); 0506 } 0507 return newPos; 0508 } 0509 return QGraphicsItem::itemChange(change, value); 0510 } 0511 0512 MyEllipseItem::MyEllipseItem(QGraphicsItem *parent) 0513 : QGraphicsEllipseItem(parent) 0514 { 0515 // Disabled because cache makes text cursor invisible and borders ugly 0516 // setCacheMode(QGraphicsItem::ItemCoordinateCache); 0517 setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); 0518 } 0519 0520 void MyEllipseItem::setRect(const QRectF &rectangle) 0521 { 0522 QGraphicsEllipseItem::setRect(rectangle); 0523 if (m_ellipse != rectangle && !data(TitleDocument::Gradient).isNull()) { 0524 m_ellipse = rectangle; 0525 QLinearGradient gr = GradientWidget::gradientFromString(data(TitleDocument::Gradient).toString(), int(m_ellipse.width()), int(m_ellipse.height())); 0526 setBrush(QBrush(gr)); 0527 } 0528 } 0529 0530 QVariant MyEllipseItem::itemChange(GraphicsItemChange change, const QVariant &value) 0531 { 0532 if (change == ItemPositionChange && (scene() != nullptr)) { 0533 QPoint newPos = value.toPoint(); 0534 if (QApplication::mouseButtons() == Qt::LeftButton && (qobject_cast<GraphicsSceneRectMove *>(scene()) != nullptr)) { 0535 auto *customScene = qobject_cast<GraphicsSceneRectMove *>(scene()); 0536 int gridSize = customScene->gridSize(); 0537 int xV = (newPos.x() / gridSize) * gridSize; 0538 int yV = (newPos.y() / gridSize) * gridSize; 0539 if (QApplication::keyboardModifiers() == Qt::ShiftModifier) { 0540 xV = pos().x(); 0541 } 0542 if (QApplication::keyboardModifiers() == (Qt::ShiftModifier | Qt::AltModifier)) { 0543 yV = pos().y(); 0544 } 0545 newPos = QPoint(xV, yV); 0546 } 0547 return newPos; 0548 } 0549 return QGraphicsItem::itemChange(change, value); 0550 } 0551 0552 MyPixmapItem::MyPixmapItem(const QPixmap &pixmap, QGraphicsItem *parent) 0553 : QGraphicsPixmapItem(pixmap, parent) 0554 { 0555 // Disabled because cache makes text cursor invisible and borders ugly 0556 // setCacheMode(QGraphicsItem::ItemCoordinateCache); 0557 setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); 0558 } 0559 0560 QVariant MyPixmapItem::itemChange(GraphicsItemChange change, const QVariant &value) 0561 { 0562 if (change == ItemPositionChange && (scene() != nullptr)) { 0563 QPoint newPos = value.toPoint(); 0564 if (QApplication::mouseButtons() == Qt::LeftButton && (qobject_cast<GraphicsSceneRectMove *>(scene()) != nullptr)) { 0565 auto *customScene = qobject_cast<GraphicsSceneRectMove *>(scene()); 0566 int gridSize = customScene->gridSize(); 0567 int xV = (newPos.x() / gridSize) * gridSize; 0568 int yV = (newPos.y() / gridSize) * gridSize; 0569 if (QApplication::keyboardModifiers() == Qt::ShiftModifier) { 0570 xV = pos().x(); 0571 } 0572 if (QApplication::keyboardModifiers() == (Qt::ShiftModifier | Qt::AltModifier)) { 0573 yV = pos().y(); 0574 } 0575 newPos = QPoint(xV, yV); 0576 } 0577 return newPos; 0578 } 0579 return QGraphicsItem::itemChange(change, value); 0580 } 0581 0582 MySvgItem::MySvgItem(const QString &fileName, QGraphicsItem *parent) 0583 : QGraphicsSvgItem(fileName, parent) 0584 { 0585 // Disabled because cache makes text cursor invisible and borders ugly 0586 // setCacheMode(QGraphicsItem::ItemCoordinateCache); 0587 setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); 0588 } 0589 0590 QVariant MySvgItem::itemChange(GraphicsItemChange change, const QVariant &value) 0591 { 0592 if (change == ItemPositionChange && (scene() != nullptr)) { 0593 QPoint newPos = value.toPoint(); 0594 if (QApplication::mouseButtons() == Qt::LeftButton && (qobject_cast<GraphicsSceneRectMove *>(scene()) != nullptr)) { 0595 auto *customScene = qobject_cast<GraphicsSceneRectMove *>(scene()); 0596 int gridSize = customScene->gridSize(); 0597 int xV = (newPos.x() / gridSize) * gridSize; 0598 int yV = (newPos.y() / gridSize) * gridSize; 0599 if (QApplication::keyboardModifiers() == Qt::ShiftModifier) { 0600 xV = pos().x(); 0601 } 0602 if (QApplication::keyboardModifiers() == (Qt::ShiftModifier | Qt::AltModifier)) { 0603 yV = pos().y(); 0604 } 0605 newPos = QPoint(xV, yV); 0606 } 0607 return newPos; 0608 } 0609 return QGraphicsItem::itemChange(change, value); 0610 } 0611 GraphicsSceneRectMove::GraphicsSceneRectMove(int titlerVersion, QObject *parent) 0612 : QGraphicsScene(parent) 0613 0614 { 0615 // grabMouse(); 0616 TITLERVERSION = titlerVersion; 0617 m_zoom = 1.0; 0618 setBackgroundBrush(QBrush(Qt::transparent)); 0619 m_fontSize = 0; 0620 } 0621 0622 void GraphicsSceneRectMove::contextMenuEvent(QGraphicsSceneContextMenuEvent *) 0623 { 0624 // Disable QGraphicsScene standard context menu that was crashing 0625 } 0626 0627 void GraphicsSceneRectMove::setSelectedItem(QGraphicsItem *item) 0628 { 0629 clearSelection(); 0630 m_selectedItem = item; 0631 item->setSelected(true); 0632 update(); 0633 } 0634 0635 TITLETOOL GraphicsSceneRectMove::tool() const 0636 { 0637 return m_tool; 0638 } 0639 0640 void GraphicsSceneRectMove::setTool(TITLETOOL tool) 0641 { 0642 m_tool = tool; 0643 switch (m_tool) { 0644 case TITLE_ELLIPSE: 0645 case TITLE_RECTANGLE: 0646 setCursor(Qt::CrossCursor); 0647 break; 0648 case TITLE_TEXT: 0649 setCursor(Qt::IBeamCursor); 0650 break; 0651 default: 0652 setCursor(Qt::ArrowCursor); 0653 } 0654 } 0655 0656 void GraphicsSceneRectMove::keyPressEvent(QKeyEvent *keyEvent) 0657 { 0658 if (m_selectedItem == nullptr || !(m_selectedItem->flags() & QGraphicsItem::ItemIsMovable)) { 0659 QGraphicsScene::keyPressEvent(keyEvent); 0660 return; 0661 } 0662 if (m_selectedItem->type() == QGraphicsTextItem::Type) { 0663 auto *t = static_cast<MyTextItem *>(m_selectedItem); 0664 if ((t->textInteractionFlags() & static_cast<int>((Qt::TextEditorInteraction) != 0)) != 0) { 0665 QGraphicsScene::keyPressEvent(keyEvent); 0666 return; 0667 } 0668 } 0669 int diff = m_gridSize; 0670 if ((keyEvent->modifiers() & Qt::ControlModifier) != 0u) { 0671 diff = m_gridSize * 5; 0672 } 0673 switch (keyEvent->key()) { 0674 case Qt::Key_Left: 0675 for (QGraphicsItem *qgi : selectedItems()) { 0676 qgi->moveBy(-diff, 0); 0677 } 0678 Q_EMIT itemMoved(); 0679 break; 0680 case Qt::Key_Right: 0681 for (QGraphicsItem *qgi : selectedItems()) { 0682 qgi->moveBy(diff, 0); 0683 } 0684 Q_EMIT itemMoved(); 0685 break; 0686 case Qt::Key_Up: 0687 for (QGraphicsItem *qgi : selectedItems()) { 0688 qgi->moveBy(0, -diff); 0689 } 0690 Q_EMIT itemMoved(); 0691 break; 0692 case Qt::Key_Down: 0693 for (QGraphicsItem *qgi : selectedItems()) { 0694 qgi->moveBy(0, diff); 0695 } 0696 Q_EMIT itemMoved(); 0697 break; 0698 case Qt::Key_Delete: 0699 case Qt::Key_Backspace: 0700 for (QGraphicsItem *qgi : selectedItems()) { 0701 if (qgi->data(-1).toInt() == -1) { 0702 continue; 0703 } 0704 removeItem(qgi); 0705 delete qgi; 0706 } 0707 m_selectedItem = nullptr; 0708 Q_EMIT selectionChanged(); 0709 break; 0710 default: 0711 QGraphicsScene::keyPressEvent(keyEvent); 0712 } 0713 Q_EMIT actionFinished(); 0714 } 0715 0716 void GraphicsSceneRectMove::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e) 0717 { 0718 QPointF p = e->scenePos(); 0719 p += QPoint(-2, -2); 0720 m_resizeMode = NoResize; 0721 m_selectedItem = nullptr; 0722 0723 // http://web.archive.org/web/20140728070013/http://www.kdenlive.org/mantis/view.php?id=1035 0724 QList<QGraphicsItem *> i = items(QRectF(p, QSizeF(4, 4)).toRect()); 0725 if (i.isEmpty()) { 0726 return; 0727 } 0728 0729 int ix = 1; 0730 QGraphicsItem *g = i.constFirst(); 0731 while (!(g->flags() & QGraphicsItem::ItemIsSelectable) && ix < i.count()) { 0732 g = i.at(ix); 0733 ix++; 0734 } 0735 if ((g != nullptr) && g->type() == QGraphicsTextItem::Type && (((g->flags() & static_cast<int>((QGraphicsItem::ItemIsSelectable) != 0))) != 0)) { 0736 m_selectedItem = g; 0737 } else { 0738 Q_EMIT doubleClickEvent(); 0739 } 0740 QGraphicsScene::mouseDoubleClickEvent(e); 0741 } 0742 0743 void GraphicsSceneRectMove::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) 0744 { 0745 m_pan = false; 0746 if (m_tool == TITLE_RECTANGLE && (m_selectedItem != nullptr)) { 0747 setSelectedItem(m_selectedItem); 0748 } 0749 if (m_createdText && m_selectedItem) { 0750 m_selectedItem->setSelected(true); 0751 auto *newText = static_cast<MyTextItem *>(m_selectedItem); 0752 QTextCursor cur(newText->document()); 0753 cur.select(QTextCursor::Document); 0754 newText->setTextCursor(cur); 0755 m_createdText = false; 0756 } 0757 if ((e->modifiers() & Qt::ShiftModifier) != 0u) { 0758 e->accept(); 0759 } else { 0760 QGraphicsScene::mouseReleaseEvent(e); 0761 } 0762 QList<QGraphicsView *> viewlist = views(); 0763 if (!viewlist.isEmpty()) { 0764 viewlist.constFirst()->setDragMode(QGraphicsView::RubberBandDrag); 0765 } 0766 Q_EMIT actionFinished(); 0767 } 0768 0769 void GraphicsSceneRectMove::mousePressEvent(QGraphicsSceneMouseEvent *e) 0770 { 0771 if ((e->buttons() & Qt::MiddleButton) != 0u) { 0772 clearTextSelection(); 0773 QList<QGraphicsView *> viewlist = views(); 0774 if (!viewlist.isEmpty()) { 0775 viewlist.constFirst()->setDragMode(QGraphicsView::ScrollHandDrag); 0776 m_pan = true; 0777 e->accept(); 0778 QGraphicsScene::mousePressEvent(e); 0779 return; 0780 } 0781 } 0782 int xPos = (int(e->scenePos().x()) / m_gridSize) * m_gridSize; 0783 int yPos = (int(e->scenePos().y()) / m_gridSize) * m_gridSize; 0784 m_moveStarted = false; 0785 m_clickPoint = e->scenePos(); 0786 m_resizeMode = m_possibleAction; 0787 const QList<QGraphicsItem *> list = items(e->scenePos()); 0788 QGraphicsItem *item = nullptr; 0789 if (m_tool == TITLE_SELECT) { 0790 QList<QGraphicsView *> viewlist = views(); 0791 if ((e->modifiers() & Qt::ControlModifier) != 0u) { 0792 clearTextSelection(); 0793 if (!viewlist.isEmpty()) { 0794 viewlist.constFirst()->setDragMode(QGraphicsView::ScrollHandDrag); 0795 e->ignore(); 0796 // QGraphicsScene::mousePressEvent(e); 0797 return; 0798 } 0799 } else { 0800 if (!viewlist.isEmpty()) { 0801 viewlist.constFirst()->setRubberBandSelectionMode(Qt::IntersectsItemShape); 0802 } 0803 } 0804 bool alreadySelected = false; 0805 for (QGraphicsItem *g : list) { 0806 // qDebug() << " - - CHECKING ITEM Z:" << g->zValue() << ", TYPE: " << g->type(); 0807 // check is there is a selected item in list 0808 if (!(g->flags() & QGraphicsItem::ItemIsSelectable)) { 0809 continue; 0810 } 0811 if (g->zValue() > -1000 /* && g->isSelected()*/) { 0812 alreadySelected = g->isSelected(); 0813 if (!alreadySelected) { 0814 g->setSelected(true); 0815 } 0816 item = g; 0817 break; 0818 } 0819 } 0820 if (item == nullptr || (e->modifiers() != Qt::ShiftModifier && !alreadySelected)) { 0821 clearTextSelection(); 0822 } else if ((e->modifiers() & Qt::ShiftModifier) != 0u) { 0823 clearTextSelection(false); 0824 } 0825 if ((item != nullptr) && ((item->flags() & QGraphicsItem::ItemIsMovable) != 0)) { 0826 m_sceneClickPoint = e->scenePos(); 0827 m_selectedItem = item; 0828 // qCDebug(KDENLIVE_LOG) << "///////// ITEM TYPE: " << item->type(); 0829 if (item->type() == QGraphicsTextItem::Type) { 0830 auto *t = static_cast<MyTextItem *>(item); 0831 if (t->textInteractionFlags() == Qt::TextEditorInteraction) { 0832 QGraphicsScene::mousePressEvent(e); 0833 return; 0834 } 0835 t->setTextInteractionFlags(Qt::NoTextInteraction); 0836 t->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); 0837 setCursor(Qt::ClosedHandCursor); 0838 } else if (item->type() == QGraphicsRectItem::Type || item->type() == QGraphicsEllipseItem::Type || item->type() == QGraphicsSvgItem::Type || 0839 item->type() == QGraphicsPixmapItem::Type) { 0840 QRectF r1; 0841 if (m_selectedItem->type() == QGraphicsRectItem::Type) { 0842 r1 = static_cast<QGraphicsRectItem *>(m_selectedItem)->rect().normalized(); 0843 } else { 0844 r1 = m_selectedItem->boundingRect().normalized(); 0845 } 0846 0847 r1.translate(m_selectedItem->scenePos()); 0848 switch (m_resizeMode) { 0849 case BottomRight: 0850 case Right: 0851 case Down: 0852 m_clickPoint = r1.topLeft(); 0853 e->accept(); 0854 break; 0855 case TopLeft: 0856 case Left: 0857 case Up: 0858 m_clickPoint = r1.bottomRight(); 0859 e->accept(); 0860 break; 0861 case TopRight: 0862 m_clickPoint = r1.bottomLeft(); 0863 e->accept(); 0864 break; 0865 case BottomLeft: 0866 m_clickPoint = r1.topRight(); 0867 e->accept(); 0868 break; 0869 default: 0870 break; 0871 } 0872 } 0873 } 0874 QGraphicsScene::mousePressEvent(e); 0875 } else if (m_tool == TITLE_RECTANGLE || m_tool == TITLE_ELLIPSE) { 0876 clearTextSelection(); 0877 m_sceneClickPoint = QPointF(xPos, yPos); 0878 m_selectedItem = nullptr; 0879 e->ignore(); 0880 } else if (m_tool == TITLE_TEXT) { 0881 if (e->button() == Qt::LeftButton) { 0882 clearTextSelection(); 0883 MyTextItem *textItem = new MyTextItem(i18n("Text"), nullptr); 0884 yPos = ((int(e->scenePos().y()) - (m_fontSize / 2)) / m_gridSize) * m_gridSize; 0885 textItem->setPos(xPos, yPos); 0886 addItem(textItem); 0887 textItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); 0888 textItem->setTextInteractionFlags(Qt::TextEditorInteraction); 0889 textItem->setFocus(Qt::MouseFocusReason); 0890 textItem->setAlignment(QFlags<Qt::AlignmentFlag>(KdenliveSettings::titlerAlign())); 0891 Q_EMIT newText(textItem); 0892 m_selectedItem = textItem; 0893 m_selectedItem->setSelected(true); 0894 m_createdText = true; 0895 } else { 0896 QGraphicsScene::mousePressEvent(e); 0897 } 0898 } 0899 // qCDebug(KDENLIVE_LOG) << "////// MOUSE CLICK, RESIZE MODE: " << m_resizeMode; 0900 } 0901 0902 void GraphicsSceneRectMove::clearTextSelection(bool reset) 0903 { 0904 if ((m_selectedItem != nullptr) && m_selectedItem->type() == QGraphicsTextItem::Type) { 0905 // disable text editing 0906 auto *t = static_cast<MyTextItem *>(m_selectedItem); 0907 t->textCursor().setPosition(0); 0908 QTextBlock cur = t->textCursor().block(); 0909 t->setTextCursor(QTextCursor(cur)); 0910 t->setTextInteractionFlags(Qt::NoTextInteraction); 0911 t->unsetCursor(); 0912 } 0913 if (reset) { 0914 m_selectedItem = nullptr; 0915 clearSelection(); 0916 } 0917 } 0918 0919 void GraphicsSceneRectMove::mouseMoveEvent(QGraphicsSceneMouseEvent *e) 0920 { 0921 QList<QGraphicsView *> viewlist = views(); 0922 if (viewlist.isEmpty()) { 0923 e->ignore(); 0924 return; 0925 } 0926 QGraphicsView *view = viewlist.constFirst(); 0927 if (m_pan) { 0928 QPoint diff = e->lastScreenPos() - e->screenPos(); 0929 view->horizontalScrollBar()->setValue(view->horizontalScrollBar()->value() + diff.x()); 0930 view->verticalScrollBar()->setValue(view->verticalScrollBar()->value() + diff.y()); 0931 e->accept(); 0932 QGraphicsScene::mouseMoveEvent(e); 0933 return; 0934 } 0935 if (e->buttons() != Qt::NoButton && !m_moveStarted) { 0936 if ((view->mapFromScene(e->scenePos()) - view->mapFromScene(m_clickPoint)).manhattanLength() < QApplication::startDragDistance()) { 0937 e->ignore(); 0938 return; 0939 } 0940 m_moveStarted = true; 0941 } 0942 if ((m_selectedItem != nullptr) && ((e->buttons() & Qt::LeftButton) != 0u)) { 0943 if (m_selectedItem->type() == QGraphicsRectItem::Type || m_selectedItem->type() == QGraphicsEllipseItem::Type || 0944 m_selectedItem->type() == QGraphicsSvgItem::Type || m_selectedItem->type() == QGraphicsPixmapItem::Type) { 0945 QRectF newrect; 0946 if (m_selectedItem->type() == QGraphicsRectItem::Type) { 0947 newrect = static_cast<QGraphicsRectItem *>(m_selectedItem)->rect(); 0948 } else { 0949 newrect = m_selectedItem->boundingRect(); 0950 } 0951 int xPos = (int(e->scenePos().x()) / m_gridSize) * m_gridSize; 0952 int yPos = (int(e->scenePos().y()) / m_gridSize) * m_gridSize; 0953 QPointF newpoint(xPos, yPos); 0954 switch (m_resizeMode) { 0955 case BottomRight: 0956 case BottomLeft: 0957 case TopRight: 0958 case TopLeft: 0959 newrect = QRectF(m_clickPoint, newpoint).normalized(); 0960 break; 0961 case Up: 0962 newrect = QRectF(m_clickPoint, QPointF(m_clickPoint.x() - newrect.width(), newpoint.y())).normalized(); 0963 break; 0964 case Down: 0965 newrect = QRectF(m_clickPoint, QPointF(newrect.width() + m_clickPoint.x(), newpoint.y())).normalized(); 0966 break; 0967 case Right: 0968 newrect = QRectF(m_clickPoint, QPointF(newpoint.x(), m_clickPoint.y() + newrect.height())).normalized(); 0969 break; 0970 case Left: 0971 newrect = QRectF(m_clickPoint, QPointF(newpoint.x(), m_clickPoint.y() - newrect.height())).normalized(); 0972 break; 0973 default: 0974 break; 0975 } 0976 0977 if (m_selectedItem->type() == QGraphicsRectItem::Type && m_resizeMode != NoResize) { 0978 auto *gi = static_cast<MyRectItem *>(m_selectedItem); 0979 // Resize using aspect ratio 0980 if (!m_selectedItem->data(0).isNull()) { 0981 // we want to keep aspect ratio 0982 double hRatio = newrect.width() / m_selectedItem->data(0).toInt(); 0983 double vRatio = newrect.height() / m_selectedItem->data(1).toInt(); 0984 if (hRatio < vRatio) { 0985 newrect.setHeight(m_selectedItem->data(1).toInt() * hRatio); 0986 } else { 0987 newrect.setWidth(m_selectedItem->data(0).toInt() * vRatio); 0988 } 0989 } 0990 gi->setPos(newrect.topLeft()); 0991 gi->setRect(QRectF(QPointF(), newrect.bottomRight() - newrect.topLeft())); 0992 return; 0993 } 0994 if (m_selectedItem->type() == QGraphicsEllipseItem::Type && m_resizeMode != NoResize) { 0995 auto *gi = static_cast<MyEllipseItem *>(m_selectedItem); 0996 // Resize using aspect ratio 0997 if (!m_selectedItem->data(0).isNull()) { 0998 // we want to keep aspect ratio 0999 double hRatio = newrect.width() / m_selectedItem->data(0).toInt(); 1000 double vRatio = newrect.height() / m_selectedItem->data(1).toInt(); 1001 if (hRatio < vRatio) { 1002 newrect.setHeight(m_selectedItem->data(1).toInt() * hRatio); 1003 } else { 1004 newrect.setWidth(m_selectedItem->data(0).toInt() * vRatio); 1005 } 1006 } 1007 gi->setPos(newrect.topLeft()); 1008 gi->setRect(QRectF(QPointF(), newrect.bottomRight() - newrect.topLeft())); 1009 return; 1010 } 1011 QGraphicsScene::mouseMoveEvent(e); 1012 } else if (m_selectedItem->type() == QGraphicsTextItem::Type) { 1013 auto *t = static_cast<MyTextItem *>(m_selectedItem); 1014 if ((t->textInteractionFlags() & static_cast<int>((Qt::TextEditorInteraction) != 0)) != 0) { 1015 QGraphicsScene::mouseMoveEvent(e); 1016 return; 1017 } 1018 QGraphicsScene::mouseMoveEvent(e); 1019 m_sceneClickPoint = e->scenePos(); 1020 } 1021 Q_EMIT itemMoved(); 1022 } else if (m_tool == TITLE_SELECT) { 1023 QPointF p = e->scenePos(); 1024 p += QPoint(-2, -2); 1025 m_resizeMode = NoResize; 1026 bool itemFound = false; 1027 QList<QGraphicsItem *> list = items(QRectF(p, QSizeF(4, 4)).toRect()); 1028 for (const QGraphicsItem *g : qAsConst(list)) { 1029 if (!(g->flags() & QGraphicsItem::ItemIsSelectable)) { 1030 continue; 1031 } 1032 if ((g->type() == QGraphicsSvgItem::Type || g->type() == QGraphicsPixmapItem::Type) && g->zValue() > -1000) { 1033 // image or svg item 1034 setCursor(Qt::OpenHandCursor); 1035 itemFound = true; 1036 break; 1037 } else if ((g->type() == QGraphicsRectItem::Type || g->type() == QGraphicsEllipseItem::Type) && g->zValue() > -1000) { 1038 if (view == nullptr) { 1039 continue; 1040 } 1041 QRectF r1; 1042 if (g->type() == QGraphicsRectItem::Type) { 1043 r1 = static_cast<const QGraphicsRectItem *>(g)->rect().normalized(); 1044 } else { 1045 r1 = static_cast<const QGraphicsEllipseItem *>(g)->rect().normalized(); 1046 } 1047 itemFound = true; 1048 1049 // Item mapped coordinates 1050 QPolygon r = g->deviceTransform(view->viewportTransform()).map(r1).toPolygon(); 1051 QPainterPath top(r.point(0)); 1052 top.lineTo(r.point(1)); 1053 QPainterPath bottom(r.point(2)); 1054 bottom.lineTo(r.point(3)); 1055 QPainterPath left(r.point(0)); 1056 left.lineTo(r.point(3)); 1057 QPainterPath right(r.point(1)); 1058 right.lineTo(r.point(2)); 1059 1060 // The area interested by the mouse pointer 1061 QPoint viewPos = view->mapFromScene(e->scenePos()); 1062 QPainterPath mouseArea; 1063 QFontMetrics metrics(font()); 1064 int box = metrics.lineSpacing() / 2; 1065 mouseArea.addRect(viewPos.x() - box, viewPos.y() - box, 2 * box, 2 * box); 1066 1067 // Check for collisions between the mouse and the borders 1068 if (mouseArea.contains(r.point(0))) { 1069 m_possibleAction = TopLeft; 1070 setCursor(Qt::SizeFDiagCursor); 1071 } else if (mouseArea.contains(r.point(2))) { 1072 m_possibleAction = BottomRight; 1073 setCursor(Qt::SizeFDiagCursor); 1074 } else if (mouseArea.contains(r.point(1))) { 1075 m_possibleAction = TopRight; 1076 setCursor(Qt::SizeBDiagCursor); 1077 } else if (mouseArea.contains(r.point(3))) { 1078 m_possibleAction = BottomLeft; 1079 setCursor(Qt::SizeBDiagCursor); 1080 } else if (top.intersects(mouseArea)) { 1081 m_possibleAction = Up; 1082 setCursor(Qt::SizeVerCursor); 1083 } else if (bottom.intersects(mouseArea)) { 1084 m_possibleAction = Down; 1085 setCursor(Qt::SizeVerCursor); 1086 } else if (right.intersects(mouseArea)) { 1087 m_possibleAction = Right; 1088 setCursor(Qt::SizeHorCursor); 1089 } else if (left.intersects(mouseArea)) { 1090 m_possibleAction = Left; 1091 setCursor(Qt::SizeHorCursor); 1092 } else { 1093 setCursor(Qt::OpenHandCursor); 1094 m_possibleAction = NoResize; 1095 } 1096 } 1097 break; 1098 } 1099 if (!itemFound) { 1100 m_possibleAction = NoResize; 1101 setCursor(Qt::ArrowCursor); 1102 } 1103 QGraphicsScene::mouseMoveEvent(e); 1104 } else if (m_tool == TITLE_RECTANGLE && ((e->buttons() & Qt::LeftButton) != 0u)) { 1105 if (m_selectedItem == nullptr) { 1106 // create new rect item 1107 QRectF r(0, 0, e->scenePos().x() - m_sceneClickPoint.x(), e->scenePos().y() - m_sceneClickPoint.y()); 1108 r = r.normalized(); 1109 auto *rect = new MyRectItem(); 1110 rect->setRect(QRectF(0, 0, r.width(), r.height())); 1111 addItem(rect); 1112 m_selectedItem = rect; 1113 m_selectedItem->setPos(m_sceneClickPoint); 1114 m_selectedItem->setSelected(true); 1115 Q_EMIT newRect(rect); 1116 m_selectedItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges); 1117 m_resizeMode = BottomRight; 1118 QGraphicsScene::mouseMoveEvent(e); 1119 } 1120 } else if (m_tool == TITLE_ELLIPSE && ((e->buttons() & Qt::LeftButton) != 0u)) { 1121 if (m_selectedItem == nullptr) { 1122 // create new rect item 1123 QRectF r(0, 0, e->scenePos().x() - m_sceneClickPoint.x(), e->scenePos().y() - m_sceneClickPoint.y()); 1124 r = r.normalized(); 1125 auto *ellipse = new MyEllipseItem(); 1126 ellipse->setRect(QRectF(0, 0, r.width(), r.height())); 1127 addItem(ellipse); 1128 m_selectedItem = ellipse; 1129 m_selectedItem->setPos(m_sceneClickPoint); 1130 m_selectedItem->setSelected(true); 1131 Q_EMIT newEllipse(ellipse); 1132 m_selectedItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges); 1133 m_resizeMode = BottomRight; 1134 QGraphicsScene::mouseMoveEvent(e); 1135 } 1136 } 1137 } 1138 1139 void GraphicsSceneRectMove::wheelEvent(QGraphicsSceneWheelEvent *wheelEvent) 1140 { 1141 if (wheelEvent->modifiers() == Qt::ControlModifier) { 1142 QList<QGraphicsView *> viewlist = views(); 1143 ////qCDebug(KDENLIVE_LOG) << wheelEvent->delta() << ' ' << zoom; 1144 if (!viewlist.isEmpty()) { 1145 if (wheelEvent->delta() > 0) { 1146 Q_EMIT sceneZoom(true); 1147 } else { 1148 Q_EMIT sceneZoom(false); 1149 } 1150 } 1151 } else { 1152 wheelEvent->setAccepted(false); 1153 } 1154 } 1155 1156 void GraphicsSceneRectMove::setScale(double s) 1157 { 1158 if (m_zoom < 1.0 / 7.0 && s < 1.0) { 1159 return; 1160 } 1161 if (m_zoom > 10.0 / 7.9 && s > 1.0) { 1162 return; 1163 } 1164 QList<QGraphicsView *> viewlist = views(); 1165 if (!viewlist.isEmpty()) { 1166 viewlist[0]->scale(s, s); 1167 m_zoom = m_zoom * s; 1168 } 1169 ////qCDebug(KDENLIVE_LOG)<<"////////// ZOOM: "<<zoom; 1170 } 1171 1172 void GraphicsSceneRectMove::setZoom(double s) 1173 { 1174 QList<QGraphicsView *> viewlist = views(); 1175 if (!viewlist.isEmpty()) { 1176 viewlist[0]->resetTransform(); 1177 viewlist[0]->scale(s, s); 1178 m_zoom = s; 1179 } 1180 1181 ////qCDebug(KDENLIVE_LOG)<<"////////// ZOOM: "<<zoom; 1182 } 1183 1184 void GraphicsSceneRectMove::setCursor(const QCursor &c) 1185 { 1186 const QList<QGraphicsView *> l = views(); 1187 for (QGraphicsView *v : l) { 1188 v->setCursor(c); 1189 } 1190 } 1191 1192 void GraphicsSceneRectMove::slotUpdateFontSize(int s) 1193 { 1194 m_fontSize = s; 1195 } 1196 1197 void GraphicsSceneRectMove::drawForeground(QPainter *painter, const QRectF &rect) 1198 { 1199 // draw the grid if needed 1200 if (m_gridSize <= 1) { 1201 return; 1202 } 1203 1204 QPen pen(QColor(255, 0, 0, 100)); 1205 painter->setPen(pen); 1206 1207 qreal left = int(rect.left()) - (int(rect.left()) % m_gridSize); 1208 qreal top = int(rect.top()) - (int(rect.top()) % m_gridSize); 1209 QVector<QPointF> points; 1210 for (qreal x = left; x < rect.right(); x += m_gridSize) { 1211 for (qreal y = top; y < rect.bottom(); y += m_gridSize) { 1212 points.append(QPointF(x, y)); 1213 } 1214 } 1215 painter->drawPoints(points.data(), points.size()); 1216 } 1217 1218 int GraphicsSceneRectMove::gridSize() const 1219 { 1220 return m_gridSize; 1221 } 1222 1223 void GraphicsSceneRectMove::slotUseGrid(bool enableGrid) 1224 { 1225 m_gridSize = enableGrid ? 20 : 1; 1226 } 1227 1228 void GraphicsSceneRectMove::addNewItem(QGraphicsItem *item) 1229 { 1230 clearSelection(); 1231 addItem(item); 1232 item->setSelected(true); 1233 m_selectedItem = item; 1234 }