1 /*
2 SPDX-FileCopyrightText: 2008 Marco Gittler <g.marco@freenet.de>
3 SPDX-FileCopyrightText: 2008 Jean-Baptiste Mardelle <jb@kdenlive.org>
4
5 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
6 */
7
8 #include "graphicsscenerectmove.h"
9 #include "titler/gradientwidget.h"
10 #include "titler/titledocument.h"
11
12 #include "kdenlive_debug.h"
13 #include <QApplication>
14 #include <QCursor>
15 #include <QGraphicsRectItem>
16 #include <QGraphicsSceneMouseEvent>
17 #include <QGraphicsSvgItem>
18 #include <QGraphicsView>
19 #include <QKeyEvent>
20 #include <QList>
21 #include <QScrollBar>
22 #include <QTextBlock>
23 #include <QTextCursor>
24 #include <QTextDocument>
25 #include <utility>
26
MyQGraphicsEffect(QObject * parent)27 MyQGraphicsEffect::MyQGraphicsEffect(QObject *parent)
28 : QGraphicsEffect(parent)
29
30 {
31 }
32
setShadow(const QImage & image)33 void MyQGraphicsEffect::setShadow(const QImage &image)
34 {
35 m_shadow = image;
36 }
37
setOffset(int xOffset,int yOffset,int blur)38 void MyQGraphicsEffect::setOffset(int xOffset, int yOffset, int blur)
39 {
40 m_xOffset = xOffset;
41 m_yOffset = yOffset;
42 m_blur = blur;
43 updateBoundingRect();
44 }
45
draw(QPainter * painter)46 void MyQGraphicsEffect::draw(QPainter *painter)
47 {
48 painter->fillRect(boundingRect(), Qt::transparent);
49 painter->drawImage(-2 * m_blur + m_xOffset, -2 * m_blur + m_yOffset, m_shadow);
50 drawSource(painter);
51 }
52
MyTextItem(const QString & txt,QGraphicsItem * parent)53 MyTextItem::MyTextItem(const QString &txt, QGraphicsItem *parent)
54 : QGraphicsTextItem(txt, parent)
55 , m_alignment(qApp->isLeftToRight() ? Qt::AlignRight : Qt::AlignLeft)
56 {
57 //Disabled because cache makes text cursor invisible and borders ugly
58 //setCacheMode(QGraphicsItem::ItemCoordinateCache);
59 setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
60 document()->setDocumentMargin(0);
61 m_shadowEffect = new MyQGraphicsEffect(this);
62 m_shadowEffect->setEnabled(false);
63 setGraphicsEffect(m_shadowEffect);
64 updateGeometry();
65 connect(document(), SIGNAL(contentsChange(int,int,int)), this, SLOT(updateGeometry(int,int,int)));
66 updateTW(false, 2, 1, 0, 0);
67 }
68
alignment() const69 Qt::Alignment MyTextItem::alignment() const
70 {
71 return m_alignment;
72 }
73
updateShadow(bool enabled,int blur,int xoffset,int yoffset,QColor color)74 void MyTextItem::updateShadow(bool enabled, int blur, int xoffset, int yoffset, QColor color)
75 {
76 m_shadowOffset = QPoint(xoffset, yoffset);
77 m_shadowBlur = blur;
78 m_shadowColor = std::move(color);
79 m_shadowEffect->setEnabled(enabled);
80 m_shadowEffect->setOffset(xoffset, yoffset, blur);
81 if (enabled) {
82 updateShadow();
83 }
84 update();
85 }
86
setTextColor(const QColor & col)87 void MyTextItem::setTextColor(const QColor &col)
88 {
89 setDefaultTextColor(col);
90 refreshFormat();
91 }
92
shadowInfo() const93 QStringList MyTextItem::shadowInfo() const
94 {
95 QStringList info;
96 info << QString::number(static_cast<int>(m_shadowEffect->isEnabled())) << m_shadowColor.name(QColor::HexArgb) << QString::number(m_shadowBlur)
97 << QString::number(m_shadowOffset.x()) << QString::number(m_shadowOffset.y());
98 return info;
99 }
100
loadShadow(const QStringList & info)101 void MyTextItem::loadShadow(const QStringList &info)
102 {
103 if (info.count() < 5) {
104 return;
105 }
106 updateShadow((static_cast<bool>(info.at(0).toInt())), info.at(2).toInt(), info.at(3).toInt(), info.at(4).toInt(), QColor(info.at(1)));
107 }
108
setAlignment(Qt::Alignment alignment)109 void MyTextItem::setAlignment(Qt::Alignment alignment)
110 {
111 m_alignment = alignment;
112 QTextBlockFormat format;
113 format.setAlignment(alignment);
114 QTextCursor cursor = textCursor(); // save cursor position
115 int position = textCursor().position();
116 cursor.select(QTextCursor::Document);
117 cursor.mergeBlockFormat(format);
118 cursor.clearSelection();
119 cursor.setPosition(position); // restore cursor position
120 setTextCursor(cursor);
121 }
122
refreshFormat()123 void MyTextItem::refreshFormat()
124 {
125 QString gradientData = data(TitleDocument::Gradient).toString();
126 QTextCursor cursor = textCursor();
127 QTextCharFormat cformat;
128 cursor.select(QTextCursor::Document);
129 int position = textCursor().position();
130
131 // Formatting can be lost on paste, since our QTextCursor gets overwritten, so re-apply all formatting here
132 QColor fgColor = defaultTextColor();
133 cformat.setForeground(fgColor);
134 cformat.setFont(font());
135
136 if (!gradientData.isEmpty()) {
137 QRectF rect = boundingRect();
138 QLinearGradient gr = GradientWidget::gradientFromString(gradientData, int(rect.width()), int(rect.height()));
139 cformat.setForeground(QBrush(gr));
140 }
141
142 // Apply
143 cursor.mergeCharFormat(cformat);
144 // restore cursor position
145 cursor.clearSelection();
146 cursor.setPosition(position);
147 setTextCursor(cursor);
148 }
149
updateGeometry(int,int,int)150 void MyTextItem::updateGeometry(int, int, int)
151 {
152 updateGeometry();
153 // update gradient if necessary
154 refreshFormat();
155
156 QString text = toPlainText();
157 m_path = QPainterPath();
158 m_path.setFillRule(Qt::WindingFill);
159 if (text.isEmpty()) {
160 //
161 } else {
162 QFontMetrics metrics(font());
163 double lineSpacing = data(TitleDocument::LineSpacing).toInt() + metrics.lineSpacing();
164
165 // Calculate line width
166 const QStringList lines = text.split(QLatin1Char('\n'));
167 double linePos = metrics.ascent();
168 QRectF bounding = boundingRect();
169 /*if (lines.count() > 0) {
170 lineSpacing = bounding.height() / lines.count();
171 if (lineSpacing != data(TitleDocument::LineSpacing).toInt() + metrics.lineSpacing()) {
172 linePos = 2 * lineSpacing - metrics.descent() - metrics.height();
173 }
174 }*/
175
176 for (const QString &line : lines) {
177 QPainterPath linePath;
178 linePath.addText(0, linePos, font(), line);
179 linePos += lineSpacing;
180 if (m_alignment == Qt::AlignHCenter) {
181 double offset = (bounding.width() - metrics.horizontalAdvance(line)) / 2;
182 linePath.translate(offset, 0);
183 } else if (m_alignment == Qt::AlignRight) {
184 double offset = bounding.width() - metrics.horizontalAdvance(line);
185 linePath.translate(offset, 0);
186 }
187 m_path.addPath(linePath);
188 }
189 }
190
191 if (m_shadowEffect->isEnabled()) {
192 updateShadow();
193 }
194 update();
195 }
196
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * w)197 void MyTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *w)
198 {
199 if ((textInteractionFlags() & static_cast<int>((Qt::TextEditable) != 0)) != 0) {
200 document()->setDocumentMargin(0);
201 QGraphicsTextItem::paint(painter, option, w);
202 } else {
203 painter->setRenderHint(QPainter::Antialiasing);
204 int outline = data(TitleDocument::OutlineWidth).toInt();
205 QString gradientData = data(TitleDocument::Gradient).toString();
206 QTextCursor cursor(document());
207 cursor.select(QTextCursor::Document);
208 QBrush paintBrush;
209 if (gradientData.isEmpty()) {
210 paintBrush = QBrush(cursor.charFormat().foreground().color());
211 } else {
212 QRectF rect = boundingRect();
213 paintBrush = QBrush(GradientWidget::gradientFromString(gradientData, int(rect.width()), int(rect.height())));
214 }
215 painter->fillPath(m_path, paintBrush);
216 if (outline > 0) {
217 QVariant variant = data(TitleDocument::OutlineColor);
218 QColor outlineColor = variant.value<QColor>();
219 QPen pen(outlineColor);
220 pen.setWidthF(outline);
221 painter->strokePath(m_path, pen);
222 }
223 document()->setDocumentMargin(toPlainText().isEmpty() ? 6 : 0);
224 if (isSelected() || toPlainText().isEmpty()) {
225 QPen pen(isSelected() ? Qt::red : Qt::blue);
226 pen.setStyle(Qt::DashLine);
227 painter->setPen(pen);
228 painter->drawRect(boundingRect());
229 }
230 }
231 }
232
updateTW(bool enabled,int step,int mode,int sigma,int seed)233 void MyTextItem::updateTW(bool enabled, int step, int mode, int sigma, int seed)
234 {
235 tw_enabled = enabled;
236 tw_step = step;
237 tw_mode = mode;
238 tw_sigma = sigma;
239 tw_seed = seed;
240 }
241
loadTW(const QStringList & info)242 void MyTextItem::loadTW(const QStringList &info)
243 {
244 if (info.count() < 5) {
245 return;
246 }
247 updateTW((static_cast<bool>(info.at(0).toInt())), info.at(1).toInt(),
248 info.at(2).toInt(), info.at(3).toInt(), info.at(4).toInt());
249 }
250
twInfo() const251 QStringList MyTextItem::twInfo() const
252 {
253 QStringList info;
254 info << QString::number(tw_enabled) << QString::number(tw_step)
255 << QString::number(tw_mode)
256 << QString::number(tw_sigma) << QString::number(tw_seed);
257 return info;
258 }
259
updateShadow()260 void MyTextItem::updateShadow()
261 {
262 QString text = toPlainText();
263 if (text.isEmpty()) {
264 m_shadowEffect->setShadow(QImage());
265 return;
266 }
267 QRectF bounding = boundingRect();
268 QPainterPath path = m_path;
269 // Calculate position of text in parent item
270 path.translate(QPointF(2 * m_shadowBlur, 2 * m_shadowBlur));
271 QRectF fullSize = bounding.united(path.boundingRect());
272 QImage shadow(int(fullSize.width()) + qAbs(m_shadowOffset.x()) + 4 * m_shadowBlur, int(fullSize.height()) + qAbs(m_shadowOffset.y()) + 4 * m_shadowBlur,
273 QImage::Format_ARGB32_Premultiplied);
274 shadow.fill(Qt::transparent);
275 QPainter painter(&shadow);
276 painter.fillPath(path, QBrush(m_shadowColor));
277 painter.end();
278 if (m_shadowBlur > 0) {
279 blurShadow(shadow, m_shadowBlur);
280 }
281 m_shadowEffect->setShadow(shadow);
282 }
283
blurShadow(QImage & result,int radius)284 void MyTextItem::blurShadow(QImage &result, int radius)
285 {
286 int tab[] = {14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2};
287 int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius - 1];
288
289 int r1 = 0;
290 int r2 = result.height() - 1;
291 int c1 = 0;
292 int c2 = result.width() - 1;
293
294 int bpl = result.bytesPerLine();
295 int rgba[4];
296 unsigned char *p;
297
298 int i1 = 0;
299 int i2 = 3;
300
301 for (int col = c1; col <= c2; col++) {
302 p = result.scanLine(r1) + col * 4;
303 for (int i = i1; i <= i2; i++) {
304 rgba[i] = p[i] << 4;
305 }
306
307 p += bpl;
308 for (int j = r1; j < r2; j++, p += bpl)
309 for (int i = i1; i <= i2; i++) {
310 p[i] = uchar((rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4);
311 }
312 }
313
314 for (int row = r1; row <= r2; row++) {
315 p = result.scanLine(row) + c1 * 4;
316 for (int i = i1; i <= i2; i++) {
317 rgba[i] = p[i] << 4;
318 }
319
320 p += 4;
321 for (int j = c1; j < c2; j++, p += 4)
322 for (int i = i1; i <= i2; i++) {
323 p[i] = uchar((rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4);
324 }
325 }
326
327 for (int col = c1; col <= c2; col++) {
328 p = result.scanLine(r2) + col * 4;
329 for (int i = i1; i <= i2; i++) {
330 rgba[i] = p[i] << 4;
331 }
332
333 p -= bpl;
334 for (int j = r1; j < r2; j++, p -= bpl)
335 for (int i = i1; i <= i2; i++) {
336 p[i] = uchar((rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4);
337 }
338 }
339
340 for (int row = r1; row <= r2; row++) {
341 p = result.scanLine(row) + c2 * 4;
342 for (int i = i1; i <= i2; i++) {
343 rgba[i] = p[i] << 4;
344 }
345
346 p -= 4;
347 for (int j = c1; j < c2; j++, p -= 4)
348 for (int i = i1; i <= i2; i++) {
349 p[i] = uchar((rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4);
350 }
351 }
352 }
353
updateGeometry()354 void MyTextItem::updateGeometry()
355 {
356 QPointF topRightPrev = boundingRect().topRight();
357 setTextWidth(-1);
358 setTextWidth(boundingRect().width());
359 setAlignment(m_alignment);
360 QPointF topRight = boundingRect().topRight();
361
362 if ((m_alignment & static_cast<int>((Qt::AlignRight) != 0)) != 0) {
363 setPos(pos() + (topRightPrev - topRight));
364 }
365 }
366
baseBoundingRect() const367 QRectF MyTextItem::baseBoundingRect() const
368 {
369 QRectF base = QGraphicsTextItem::boundingRect();
370 QTextCursor cur(document());
371 cur.select(QTextCursor::Document);
372 QTextBlockFormat format = cur.blockFormat();
373 int lineHeight = int(format.lineHeight());
374 int lineHeight2 = QFontMetrics(font()).lineSpacing();
375 int lines = document()->lineCount();
376 if (lines > 1) {
377 base.setHeight(lines * lineHeight2 + lineHeight * (lines - 1));
378 }
379 return base;
380 }
381
boundingRect() const382 QRectF MyTextItem::boundingRect() const
383 {
384 QRectF base = baseBoundingRect();
385 if (m_shadowEffect->isEnabled() && m_shadowOffset.x() > 0) {
386 base.setRight(base.right() + m_shadowOffset.x());
387 }
388 if (m_shadowEffect->isEnabled() && m_shadowOffset.y() > 0) {
389 base.setBottom(base.bottom() + m_shadowOffset.y());
390 }
391 return base;
392 }
393
itemChange(GraphicsItemChange change,const QVariant & value)394 QVariant MyTextItem::itemChange(GraphicsItemChange change, const QVariant &value)
395 {
396 if (change == ItemPositionChange && (scene() != nullptr)) {
397 QPoint newPos = value.toPoint();
398 if (QApplication::mouseButtons() == Qt::LeftButton && (qobject_cast<GraphicsSceneRectMove *>(scene()) != nullptr)) {
399 auto *customScene = qobject_cast<GraphicsSceneRectMove *>(scene());
400 int gridSize = customScene->gridSize();
401 int xV = (newPos.x() / gridSize) * gridSize;
402 int yV = (newPos.y() / gridSize) * gridSize;
403 if (QApplication::keyboardModifiers() == Qt::ShiftModifier) {
404 xV = pos().x();
405 }
406 if (QApplication::keyboardModifiers() == (Qt::ShiftModifier | Qt::AltModifier)) {
407 yV = pos().y();
408 }
409 newPos = QPoint(xV, yV);
410 }
411 return newPos;
412 }
413 if (change == QGraphicsItem::ItemSelectedHasChanged) {
414 if (!value.toBool()) {
415 // Make sure to deselect text when item loses focus
416 QTextCursor cur(document());
417 cur.clearSelection();
418 setTextCursor(cur);
419 }
420 }
421 return QGraphicsItem::itemChange(change, value);
422 }
423
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * evt)424 void MyTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *evt)
425 {
426 if (textInteractionFlags() == Qt::TextEditorInteraction) {
427 // if editor mode is already on: pass double click events on to the editor:
428 QGraphicsTextItem::mouseDoubleClickEvent(evt);
429 return;
430 }
431 // if editor mode is off:
432 // 1. turn editor mode on and set selected and focused:
433 // SetTextInteraction(true);
434 setTextInteractionFlags(Qt::TextEditorInteraction);
435 setFocus(Qt::MouseFocusReason);
436 setCursor(QCursor(Qt::IBeamCursor));
437 // 2. send a single click to this QGraphicsTextItem (this will set the cursor to the mouse position):
438 // create a new mouse event with the same parameters as evt
439 auto *click = new QGraphicsSceneMouseEvent(QEvent::GraphicsSceneMousePress);
440 click->setButton(evt->button());
441 click->setPos(evt->pos());
442 QGraphicsTextItem::mousePressEvent(click);
443 delete click; // don't forget to delete the event
444 }
445
MyRectItem(QGraphicsItem * parent)446 MyRectItem::MyRectItem(QGraphicsItem *parent)
447 : QGraphicsRectItem(parent)
448 {
449 //Disabled because cache makes text cursor invisible and borders ugly
450 //setCacheMode(QGraphicsItem::ItemCoordinateCache);
451 setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
452 }
453
setRect(const QRectF & rectangle)454 void MyRectItem::setRect(const QRectF &rectangle)
455 {
456 QGraphicsRectItem::setRect(rectangle);
457 if (m_rect != rectangle && !data(TitleDocument::Gradient).isNull()) {
458 m_rect = rectangle;
459 QLinearGradient gr = GradientWidget::gradientFromString(data(TitleDocument::Gradient).toString(), int(m_rect.width()), int(m_rect.height()));
460 setBrush(QBrush(gr));
461 }
462 }
463
itemChange(GraphicsItemChange change,const QVariant & value)464 QVariant MyRectItem::itemChange(GraphicsItemChange change, const QVariant &value)
465 {
466 if (change == ItemPositionChange && (scene() != nullptr)) {
467 QPoint newPos = value.toPoint();
468 if (QApplication::mouseButtons() == Qt::LeftButton && (qobject_cast<GraphicsSceneRectMove *>(scene()) != nullptr)) {
469 auto *customScene = qobject_cast<GraphicsSceneRectMove *>(scene());
470 int gridSize = customScene->gridSize();
471 int xV = (newPos.x() / gridSize) * gridSize;
472 int yV = (newPos.y() / gridSize) * gridSize;
473 if (QApplication::keyboardModifiers() == Qt::ShiftModifier) {
474 xV = pos().x();
475 }
476 if (QApplication::keyboardModifiers() == (Qt::ShiftModifier | Qt::AltModifier)) {
477 yV = pos().y();
478 }
479 newPos = QPoint(xV, yV);
480 }
481 return newPos;
482 }
483 return QGraphicsItem::itemChange(change, value);
484 }
485
MyEllipseItem(QGraphicsItem * parent)486 MyEllipseItem::MyEllipseItem(QGraphicsItem *parent)
487 : QGraphicsEllipseItem(parent)
488 {
489 //Disabled because cache makes text cursor invisible and borders ugly
490 //setCacheMode(QGraphicsItem::ItemCoordinateCache);
491 setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
492 }
493
setRect(const QRectF & rectangle)494 void MyEllipseItem::setRect(const QRectF &rectangle)
495 {
496 QGraphicsEllipseItem::setRect(rectangle);
497 if (m_ellipse != rectangle && !data(TitleDocument::Gradient).isNull()) {
498 m_ellipse = rectangle;
499 QLinearGradient gr = GradientWidget::gradientFromString(data(TitleDocument::Gradient).toString(), int(m_ellipse.width()), int(m_ellipse.height()));
500 setBrush(QBrush(gr));
501 }
502 }
503
itemChange(GraphicsItemChange change,const QVariant & value)504 QVariant MyEllipseItem::itemChange(GraphicsItemChange change, const QVariant &value)
505 {
506 if (change == ItemPositionChange && (scene() != nullptr)) {
507 QPoint newPos = value.toPoint();
508 if (QApplication::mouseButtons() == Qt::LeftButton && (qobject_cast<GraphicsSceneRectMove *>(scene()) != nullptr)) {
509 auto *customScene = qobject_cast<GraphicsSceneRectMove *>(scene());
510 int gridSize = customScene->gridSize();
511 int xV = (newPos.x() / gridSize) * gridSize;
512 int yV = (newPos.y() / gridSize) * gridSize;
513 if (QApplication::keyboardModifiers() == Qt::ShiftModifier) {
514 xV = pos().x();
515 }
516 if (QApplication::keyboardModifiers() == (Qt::ShiftModifier | Qt::AltModifier)) {
517 yV = pos().y();
518 }
519 newPos = QPoint(xV, yV);
520 }
521 return newPos;
522 }
523 return QGraphicsItem::itemChange(change, value);
524 }
525
MyPixmapItem(const QPixmap & pixmap,QGraphicsItem * parent)526 MyPixmapItem::MyPixmapItem(const QPixmap &pixmap, QGraphicsItem *parent)
527 : QGraphicsPixmapItem(pixmap, parent)
528 {
529 //Disabled because cache makes text cursor invisible and borders ugly
530 //setCacheMode(QGraphicsItem::ItemCoordinateCache);
531 setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
532 }
533
itemChange(GraphicsItemChange change,const QVariant & value)534 QVariant MyPixmapItem::itemChange(GraphicsItemChange change, const QVariant &value)
535 {
536 if (change == ItemPositionChange && (scene() != nullptr)) {
537 QPoint newPos = value.toPoint();
538 if (QApplication::mouseButtons() == Qt::LeftButton && (qobject_cast<GraphicsSceneRectMove *>(scene()) != nullptr)) {
539 auto *customScene = qobject_cast<GraphicsSceneRectMove *>(scene());
540 int gridSize = customScene->gridSize();
541 int xV = (newPos.x() / gridSize) * gridSize;
542 int yV = (newPos.y() / gridSize) * gridSize;
543 if (QApplication::keyboardModifiers() == Qt::ShiftModifier) {
544 xV = pos().x();
545 }
546 if (QApplication::keyboardModifiers() == (Qt::ShiftModifier | Qt::AltModifier)) {
547 yV = pos().y();
548 }
549 newPos = QPoint(xV, yV);
550 }
551 return newPos;
552 }
553 return QGraphicsItem::itemChange(change, value);
554 }
555
MySvgItem(const QString & fileName,QGraphicsItem * parent)556 MySvgItem::MySvgItem(const QString &fileName, QGraphicsItem *parent)
557 : QGraphicsSvgItem(fileName, parent)
558 {
559 //Disabled because cache makes text cursor invisible and borders ugly
560 //setCacheMode(QGraphicsItem::ItemCoordinateCache);
561 setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
562 }
563
itemChange(GraphicsItemChange change,const QVariant & value)564 QVariant MySvgItem::itemChange(GraphicsItemChange change, const QVariant &value)
565 {
566 if (change == ItemPositionChange && (scene() != nullptr)) {
567 QPoint newPos = value.toPoint();
568 if (QApplication::mouseButtons() == Qt::LeftButton && (qobject_cast<GraphicsSceneRectMove *>(scene()) != nullptr)) {
569 auto *customScene = qobject_cast<GraphicsSceneRectMove *>(scene());
570 int gridSize = customScene->gridSize();
571 int xV = (newPos.x() / gridSize) * gridSize;
572 int yV = (newPos.y() / gridSize) * gridSize;
573 if (QApplication::keyboardModifiers() == Qt::ShiftModifier) {
574 xV = pos().x();
575 }
576 if (QApplication::keyboardModifiers() == (Qt::ShiftModifier | Qt::AltModifier)) {
577 yV = pos().y();
578 }
579 newPos = QPoint(xV, yV);
580 }
581 return newPos;
582 }
583 return QGraphicsItem::itemChange(change, value);
584 }
GraphicsSceneRectMove(QObject * parent)585 GraphicsSceneRectMove::GraphicsSceneRectMove(QObject *parent)
586 : QGraphicsScene(parent)
587
588 {
589 // grabMouse();
590 m_zoom = 1.0;
591 setBackgroundBrush(QBrush(Qt::transparent));
592 m_fontSize = 0;
593 }
594
contextMenuEvent(QGraphicsSceneContextMenuEvent *)595 void GraphicsSceneRectMove::contextMenuEvent(QGraphicsSceneContextMenuEvent *)
596 {
597 // Disable QGraphicsScene standard context menu that was crashing
598 }
599
setSelectedItem(QGraphicsItem * item)600 void GraphicsSceneRectMove::setSelectedItem(QGraphicsItem *item)
601 {
602 clearSelection();
603 m_selectedItem = item;
604 item->setSelected(true);
605 update();
606 }
607
tool() const608 TITLETOOL GraphicsSceneRectMove::tool() const
609 {
610 return m_tool;
611 }
612
setTool(TITLETOOL tool)613 void GraphicsSceneRectMove::setTool(TITLETOOL tool)
614 {
615 m_tool = tool;
616 switch (m_tool) {
617 case TITLE_ELLIPSE:
618 case TITLE_RECTANGLE:
619 setCursor(Qt::CrossCursor);
620 break;
621 case TITLE_TEXT:
622 setCursor(Qt::IBeamCursor);
623 break;
624 default:
625 setCursor(Qt::ArrowCursor);
626 }
627 }
628
keyPressEvent(QKeyEvent * keyEvent)629 void GraphicsSceneRectMove::keyPressEvent(QKeyEvent *keyEvent)
630 {
631 if (m_selectedItem == nullptr || !(m_selectedItem->flags() & QGraphicsItem::ItemIsMovable)) {
632 QGraphicsScene::keyPressEvent(keyEvent);
633 return;
634 }
635 if (m_selectedItem->type() == QGraphicsTextItem::Type) {
636 auto *t = static_cast<MyTextItem *>(m_selectedItem);
637 if ((t->textInteractionFlags() & static_cast<int>((Qt::TextEditorInteraction) != 0)) != 0) {
638 QGraphicsScene::keyPressEvent(keyEvent);
639 return;
640 }
641 }
642 int diff = m_gridSize;
643 if ((keyEvent->modifiers() & Qt::ControlModifier) != 0u) {
644 diff = m_gridSize * 5;
645 }
646 switch (keyEvent->key()) {
647 case Qt::Key_Left:
648 foreach (QGraphicsItem *qgi, selectedItems()) {
649 qgi->moveBy(-diff, 0);
650 }
651 emit itemMoved();
652 break;
653 case Qt::Key_Right:
654 foreach (QGraphicsItem *qgi, selectedItems()) {
655 qgi->moveBy(diff, 0);
656 }
657 emit itemMoved();
658 break;
659 case Qt::Key_Up:
660 foreach (QGraphicsItem *qgi, selectedItems()) {
661 qgi->moveBy(0, -diff);
662 }
663 emit itemMoved();
664 break;
665 case Qt::Key_Down:
666 foreach (QGraphicsItem *qgi, selectedItems()) {
667 qgi->moveBy(0, diff);
668 }
669 emit itemMoved();
670 break;
671 case Qt::Key_Delete:
672 case Qt::Key_Backspace:
673 foreach (QGraphicsItem *qgi, selectedItems()) {
674 if (qgi->data(-1).toInt() == -1) {
675 continue;
676 }
677 removeItem(qgi);
678 delete qgi;
679 }
680 m_selectedItem = nullptr;
681 emit selectionChanged();
682 break;
683 default:
684 QGraphicsScene::keyPressEvent(keyEvent);
685 }
686 emit actionFinished();
687 }
688
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * e)689 void GraphicsSceneRectMove::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e)
690 {
691 QPointF p = e->scenePos();
692 p += QPoint(-2, -2);
693 m_resizeMode = NoResize;
694 m_selectedItem = nullptr;
695
696 // http://web.archive.org/web/20140728070013/http://www.kdenlive.org/mantis/view.php?id=1035
697 QList<QGraphicsItem *> i = items(QRectF(p, QSizeF(4, 4)).toRect());
698 if (i.isEmpty()) {
699 return;
700 }
701
702 int ix = 1;
703 QGraphicsItem *g = i.constFirst();
704 while (!(g->flags() & QGraphicsItem::ItemIsSelectable) && ix < i.count()) {
705 g = i.at(ix);
706 ix++;
707 }
708 if ((g != nullptr) && g->type() == QGraphicsTextItem::Type && (((g->flags() & static_cast<int>((QGraphicsItem::ItemIsSelectable) != 0))) != 0)) {
709 m_selectedItem = g;
710 } else {
711 emit doubleClickEvent();
712 }
713 QGraphicsScene::mouseDoubleClickEvent(e);
714 }
715
mouseReleaseEvent(QGraphicsSceneMouseEvent * e)716 void GraphicsSceneRectMove::mouseReleaseEvent(QGraphicsSceneMouseEvent *e)
717 {
718 m_pan = false;
719 if (m_tool == TITLE_RECTANGLE && (m_selectedItem != nullptr)) {
720 setSelectedItem(m_selectedItem);
721 }
722 if (m_createdText && m_selectedItem) {
723 m_selectedItem->setSelected(true);
724 auto *newText = static_cast<MyTextItem *>(m_selectedItem);
725 QTextCursor cur(newText->document());
726 cur.select(QTextCursor::Document);
727 newText->setTextCursor(cur);
728 m_createdText = false;
729 }
730 if ((e->modifiers() & Qt::ShiftModifier) != 0u) {
731 e->accept();
732 } else {
733 QGraphicsScene::mouseReleaseEvent(e);
734 }
735 QList<QGraphicsView *> viewlist = views();
736 if (!viewlist.isEmpty()) {
737 viewlist.constFirst()->setDragMode(QGraphicsView::RubberBandDrag);
738 }
739 emit actionFinished();
740 }
741
mousePressEvent(QGraphicsSceneMouseEvent * e)742 void GraphicsSceneRectMove::mousePressEvent(QGraphicsSceneMouseEvent *e)
743 {
744 if ((e->buttons() & Qt::MiddleButton) != 0u) {
745 clearTextSelection();
746 QList<QGraphicsView *> viewlist = views();
747 if (!viewlist.isEmpty()) {
748 viewlist.constFirst()->setDragMode(QGraphicsView::ScrollHandDrag);
749 m_pan = true;
750 e->accept();
751 QGraphicsScene::mousePressEvent(e);
752 return;
753 }
754 }
755 int xPos = (int(e->scenePos().x()) / m_gridSize) * m_gridSize;
756 int yPos = (int(e->scenePos().y()) / m_gridSize) * m_gridSize;
757 m_moveStarted = false;
758 m_clickPoint = e->scenePos();
759 m_resizeMode = m_possibleAction;
760 const QList<QGraphicsItem *> list = items(e->scenePos());
761 QGraphicsItem *item = nullptr;
762 if (m_tool == TITLE_SELECT) {
763 QList<QGraphicsView *> viewlist = views();
764 if ((e->modifiers() & Qt::ControlModifier) != 0u) {
765 clearTextSelection();
766 if (!viewlist.isEmpty()) {
767 viewlist.constFirst()->setDragMode(QGraphicsView::ScrollHandDrag);
768 e->ignore();
769 // QGraphicsScene::mousePressEvent(e);
770 return;
771 }
772 } else {
773 if (!viewlist.isEmpty()) {
774 viewlist.constFirst()->setRubberBandSelectionMode(Qt::IntersectsItemShape);
775 }
776 }
777 bool alreadySelected = false;
778 for (QGraphicsItem *g : list) {
779 // qDebug() << " - - CHECKING ITEM Z:" << g->zValue() << ", TYPE: " << g->type();
780 // check is there is a selected item in list
781 if (!(g->flags() & QGraphicsItem::ItemIsSelectable)) {
782 continue;
783 }
784 if (g->zValue() > -1000 /* && g->isSelected()*/) {
785 alreadySelected = g->isSelected();
786 if (!alreadySelected) {
787 g->setSelected(true);
788 }
789 item = g;
790 break;
791 }
792 }
793 if (item == nullptr || (e->modifiers() != Qt::ShiftModifier && !alreadySelected)) {
794 clearTextSelection();
795 } else if ((e->modifiers() & Qt::ShiftModifier) != 0u) {
796 clearTextSelection(false);
797 }
798 if ((item != nullptr) && ((item->flags() & QGraphicsItem::ItemIsMovable) != 0)) {
799 m_sceneClickPoint = e->scenePos();
800 m_selectedItem = item;
801 // qCDebug(KDENLIVE_LOG) << "///////// ITEM TYPE: " << item->type();
802 if (item->type() == QGraphicsTextItem::Type) {
803 auto *t = static_cast<MyTextItem *>(item);
804 if (t->textInteractionFlags() == Qt::TextEditorInteraction) {
805 QGraphicsScene::mousePressEvent(e);
806 return;
807 }
808 t->setTextInteractionFlags(Qt::NoTextInteraction);
809 t->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
810 setCursor(Qt::ClosedHandCursor);
811 } else if (item->type() == QGraphicsRectItem::Type || item->type() == QGraphicsEllipseItem::Type || item->type() == QGraphicsSvgItem::Type || item->type() == QGraphicsPixmapItem::Type) {
812 QRectF r1;
813 if (m_selectedItem->type() == QGraphicsRectItem::Type) {
814 r1 = static_cast<QGraphicsRectItem *>(m_selectedItem)->rect().normalized();
815 } else {
816 r1 = m_selectedItem->boundingRect().normalized();
817 }
818
819 r1.translate(m_selectedItem->scenePos());
820 switch (m_resizeMode) {
821 case BottomRight:
822 case Right:
823 case Down:
824 m_clickPoint = r1.topLeft();
825 e->accept();
826 break;
827 case TopLeft:
828 case Left:
829 case Up:
830 m_clickPoint = r1.bottomRight();
831 e->accept();
832 break;
833 case TopRight:
834 m_clickPoint = r1.bottomLeft();
835 e->accept();
836 break;
837 case BottomLeft:
838 m_clickPoint = r1.topRight();
839 e->accept();
840 break;
841 default:
842 break;
843 }
844 }
845 }
846 QGraphicsScene::mousePressEvent(e);
847 } else if (m_tool == TITLE_RECTANGLE || m_tool == TITLE_ELLIPSE) {
848 clearTextSelection();
849 m_sceneClickPoint = QPointF(xPos, yPos);
850 m_selectedItem = nullptr;
851 e->ignore();
852 } else if (m_tool == TITLE_TEXT) {
853 if (e->button() == Qt::LeftButton) {
854 clearTextSelection();
855 MyTextItem *textItem = new MyTextItem(i18n("Text"), nullptr);
856 yPos = ((int(e->scenePos().y()) - (m_fontSize / 2)) / m_gridSize) * m_gridSize;
857 textItem->setPos(xPos, yPos);
858 addItem(textItem);
859 textItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
860 textItem->setTextInteractionFlags(Qt::TextEditorInteraction);
861 textItem->setFocus(Qt::MouseFocusReason);
862 emit newText(textItem);
863 m_selectedItem = textItem;
864 m_selectedItem->setSelected(true);
865 m_createdText = true;
866 } else {
867 QGraphicsScene::mousePressEvent(e);
868 }
869 }
870 // qCDebug(KDENLIVE_LOG) << "////// MOUSE CLICK, RESIZE MODE: " << m_resizeMode;
871 }
872
clearTextSelection(bool reset)873 void GraphicsSceneRectMove::clearTextSelection(bool reset)
874 {
875 if ((m_selectedItem != nullptr) && m_selectedItem->type() == QGraphicsTextItem::Type) {
876 // disable text editing
877 auto *t = static_cast<MyTextItem *>(m_selectedItem);
878 t->textCursor().setPosition(0);
879 QTextBlock cur = t->textCursor().block();
880 t->setTextCursor(QTextCursor(cur));
881 t->setTextInteractionFlags(Qt::NoTextInteraction);
882 t->unsetCursor();
883 }
884 if (reset) {
885 m_selectedItem = nullptr;
886 clearSelection();
887 }
888 }
889
mouseMoveEvent(QGraphicsSceneMouseEvent * e)890 void GraphicsSceneRectMove::mouseMoveEvent(QGraphicsSceneMouseEvent *e)
891 {
892 QList<QGraphicsView *> viewlist = views();
893 if (viewlist.isEmpty()) {
894 e->ignore();
895 return;
896 }
897 QGraphicsView *view = viewlist.constFirst();
898 if (m_pan) {
899 QPoint diff = e->lastScreenPos() - e->screenPos();
900 view->horizontalScrollBar()->setValue(view->horizontalScrollBar()->value() + diff.x());
901 view->verticalScrollBar()->setValue(view->verticalScrollBar()->value() + diff.y());
902 e->accept();
903 QGraphicsScene::mouseMoveEvent(e);
904 return;
905 }
906 if (e->buttons() != Qt::NoButton && !m_moveStarted) {
907 if ((view->mapFromScene(e->scenePos()) - view->mapFromScene(m_clickPoint)).manhattanLength() < QApplication::startDragDistance()) {
908 e->ignore();
909 return;
910 }
911 m_moveStarted = true;
912 }
913 if ((m_selectedItem != nullptr) && ((e->buttons() & Qt::LeftButton) != 0u)) {
914 if (m_selectedItem->type() == QGraphicsRectItem::Type || m_selectedItem->type() == QGraphicsEllipseItem::Type || m_selectedItem->type() == QGraphicsSvgItem::Type ||
915 m_selectedItem->type() == QGraphicsPixmapItem::Type) {
916 QRectF newrect;
917 if (m_selectedItem->type() == QGraphicsRectItem::Type) {
918 newrect = static_cast<QGraphicsRectItem *>(m_selectedItem)->rect();
919 } else {
920 newrect = m_selectedItem->boundingRect();
921 }
922 int xPos = (int(e->scenePos().x()) / m_gridSize) * m_gridSize;
923 int yPos = (int(e->scenePos().y()) / m_gridSize) * m_gridSize;
924 QPointF newpoint(xPos, yPos);
925 switch (m_resizeMode) {
926 case BottomRight:
927 case BottomLeft:
928 case TopRight:
929 case TopLeft:
930 newrect = QRectF(m_clickPoint, newpoint).normalized();
931 break;
932 case Up:
933 newrect = QRectF(m_clickPoint, QPointF(m_clickPoint.x() - newrect.width(), newpoint.y())).normalized();
934 break;
935 case Down:
936 newrect = QRectF(m_clickPoint, QPointF(newrect.width() + m_clickPoint.x(), newpoint.y())).normalized();
937 break;
938 case Right:
939 newrect = QRectF(m_clickPoint, QPointF(newpoint.x(), m_clickPoint.y() + newrect.height())).normalized();
940 break;
941 case Left:
942 newrect = QRectF(m_clickPoint, QPointF(newpoint.x(), m_clickPoint.y() - newrect.height())).normalized();
943 break;
944 default:
945 break;
946 }
947
948 if (m_selectedItem->type() == QGraphicsRectItem::Type && m_resizeMode != NoResize) {
949 auto *gi = static_cast<MyRectItem *>(m_selectedItem);
950 // Resize using aspect ratio
951 if (!m_selectedItem->data(0).isNull()) {
952 // we want to keep aspect ratio
953 double hRatio = newrect.width() / m_selectedItem->data(0).toInt();
954 double vRatio = newrect.height() / m_selectedItem->data(1).toInt();
955 if (hRatio < vRatio) {
956 newrect.setHeight(m_selectedItem->data(1).toInt() * hRatio);
957 } else {
958 newrect.setWidth(m_selectedItem->data(0).toInt() * vRatio);
959 }
960 }
961 gi->setPos(newrect.topLeft());
962 gi->setRect(QRectF(QPointF(), newrect.bottomRight() - newrect.topLeft()));
963 return;
964 }
965 if (m_selectedItem->type() == QGraphicsEllipseItem::Type && m_resizeMode != NoResize) {
966 auto *gi = static_cast<MyEllipseItem *>(m_selectedItem);
967 // Resize using aspect ratio
968 if (!m_selectedItem->data(0).isNull()) {
969 // we want to keep aspect ratio
970 double hRatio = newrect.width() / m_selectedItem->data(0).toInt();
971 double vRatio = newrect.height() / m_selectedItem->data(1).toInt();
972 if (hRatio < vRatio) {
973 newrect.setHeight(m_selectedItem->data(1).toInt() * hRatio);
974 } else {
975 newrect.setWidth(m_selectedItem->data(0).toInt() * vRatio);
976 }
977 }
978 gi->setPos(newrect.topLeft());
979 gi->setRect(QRectF(QPointF(), newrect.bottomRight() - newrect.topLeft()));
980 return;
981 }
982 QGraphicsScene::mouseMoveEvent(e);
983 } else if (m_selectedItem->type() == QGraphicsTextItem::Type) {
984 auto *t = static_cast<MyTextItem *>(m_selectedItem);
985 if ((t->textInteractionFlags() & static_cast<int>((Qt::TextEditorInteraction) != 0)) != 0) {
986 QGraphicsScene::mouseMoveEvent(e);
987 return;
988 }
989 QGraphicsScene::mouseMoveEvent(e);
990 m_sceneClickPoint = e->scenePos();
991 }
992 emit itemMoved();
993 } else if (m_tool == TITLE_SELECT) {
994 QPointF p = e->scenePos();
995 p += QPoint(-2, -2);
996 m_resizeMode = NoResize;
997 bool itemFound = false;
998 QList<QGraphicsItem *> list = items(QRectF(p, QSizeF(4, 4)).toRect());
999 for (const QGraphicsItem *g : qAsConst(list)) {
1000 if (!(g->flags() & QGraphicsItem::ItemIsSelectable)) {
1001 continue;
1002 }
1003 if ((g->type() == QGraphicsSvgItem::Type || g->type() == QGraphicsPixmapItem::Type) && g->zValue() > -1000) {
1004 // image or svg item
1005 setCursor(Qt::OpenHandCursor);
1006 itemFound = true;
1007 break;
1008 } else if ((g->type() == QGraphicsRectItem::Type || g->type() == QGraphicsEllipseItem::Type) && g->zValue() > -1000) {
1009 if (view == nullptr) {
1010 continue;
1011 }
1012 QRectF r1;
1013 if(g->type() == QGraphicsRectItem::Type) {
1014 r1 = static_cast<const QGraphicsRectItem *>(g)->rect().normalized();
1015 } else {
1016 r1 = static_cast<const QGraphicsEllipseItem *>(g)->rect().normalized();
1017 }
1018 itemFound = true;
1019
1020 // Item mapped coordinates
1021 QPolygon r = g->deviceTransform(view->viewportTransform()).map(r1).toPolygon();
1022 QPainterPath top(r.point(0));
1023 top.lineTo(r.point(1));
1024 QPainterPath bottom(r.point(2));
1025 bottom.lineTo(r.point(3));
1026 QPainterPath left(r.point(0));
1027 left.lineTo(r.point(3));
1028 QPainterPath right(r.point(1));
1029 right.lineTo(r.point(2));
1030
1031 // The area interested by the mouse pointer
1032 QPoint viewPos = view->mapFromScene(e->scenePos());
1033 QPainterPath mouseArea;
1034 QFontMetrics metrics(font());
1035 int box = metrics.lineSpacing() / 2;
1036 mouseArea.addRect(viewPos.x() - box, viewPos.y() - box, 2 * box, 2 * box);
1037
1038 // Check for collisions between the mouse and the borders
1039 if (mouseArea.contains(r.point(0))) {
1040 m_possibleAction = TopLeft;
1041 setCursor(Qt::SizeFDiagCursor);
1042 } else if (mouseArea.contains(r.point(2))) {
1043 m_possibleAction = BottomRight;
1044 setCursor(Qt::SizeFDiagCursor);
1045 } else if (mouseArea.contains(r.point(1))) {
1046 m_possibleAction = TopRight;
1047 setCursor(Qt::SizeBDiagCursor);
1048 } else if (mouseArea.contains(r.point(3))) {
1049 m_possibleAction = BottomLeft;
1050 setCursor(Qt::SizeBDiagCursor);
1051 } else if (top.intersects(mouseArea)) {
1052 m_possibleAction = Up;
1053 setCursor(Qt::SizeVerCursor);
1054 } else if (bottom.intersects(mouseArea)) {
1055 m_possibleAction = Down;
1056 setCursor(Qt::SizeVerCursor);
1057 } else if (right.intersects(mouseArea)) {
1058 m_possibleAction = Right;
1059 setCursor(Qt::SizeHorCursor);
1060 } else if (left.intersects(mouseArea)) {
1061 m_possibleAction = Left;
1062 setCursor(Qt::SizeHorCursor);
1063 } else {
1064 setCursor(Qt::OpenHandCursor);
1065 m_possibleAction = NoResize;
1066 }
1067 }
1068 break;
1069 }
1070 if (!itemFound) {
1071 m_possibleAction = NoResize;
1072 setCursor(Qt::ArrowCursor);
1073 }
1074 QGraphicsScene::mouseMoveEvent(e);
1075 } else if (m_tool == TITLE_RECTANGLE && ((e->buttons() & Qt::LeftButton) != 0u)) {
1076 if (m_selectedItem == nullptr) {
1077 // create new rect item
1078 QRectF r(0, 0, e->scenePos().x() - m_sceneClickPoint.x(), e->scenePos().y() - m_sceneClickPoint.y());
1079 r = r.normalized();
1080 auto *rect = new MyRectItem();
1081 rect->setRect(QRectF(0, 0, r.width(), r.height()));
1082 addItem(rect);
1083 m_selectedItem = rect;
1084 m_selectedItem->setPos(m_sceneClickPoint);
1085 m_selectedItem->setSelected(true);
1086 emit newRect(rect);
1087 m_selectedItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
1088 m_resizeMode = BottomRight;
1089 QGraphicsScene::mouseMoveEvent(e);
1090 }
1091 } else if (m_tool == TITLE_ELLIPSE && ((e->buttons() & Qt::LeftButton) != 0u)) {
1092 if (m_selectedItem == nullptr) {
1093 // create new rect item
1094 QRectF r(0, 0, e->scenePos().x() - m_sceneClickPoint.x(), e->scenePos().y() - m_sceneClickPoint.y());
1095 r = r.normalized();
1096 auto *ellipse = new MyEllipseItem();
1097 ellipse->setRect(QRectF(0, 0, r.width(), r.height()));
1098 addItem(ellipse);
1099 m_selectedItem = ellipse;
1100 m_selectedItem->setPos(m_sceneClickPoint);
1101 m_selectedItem->setSelected(true);
1102 emit newEllipse(ellipse);
1103 m_selectedItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
1104 m_resizeMode = BottomRight;
1105 QGraphicsScene::mouseMoveEvent(e);
1106 }
1107 }
1108 }
1109
wheelEvent(QGraphicsSceneWheelEvent * wheelEvent)1110 void GraphicsSceneRectMove::wheelEvent(QGraphicsSceneWheelEvent *wheelEvent)
1111 {
1112 if (wheelEvent->modifiers() == Qt::ControlModifier) {
1113 QList<QGraphicsView *> viewlist = views();
1114 ////qCDebug(KDENLIVE_LOG) << wheelEvent->delta() << ' ' << zoom;
1115 if (!viewlist.isEmpty()) {
1116 if (wheelEvent->delta() > 0) {
1117 emit sceneZoom(true);
1118 } else {
1119 emit sceneZoom(false);
1120 }
1121 }
1122 } else {
1123 wheelEvent->setAccepted(false);
1124 }
1125 }
1126
setScale(double s)1127 void GraphicsSceneRectMove::setScale(double s)
1128 {
1129 if (m_zoom < 1.0 / 7.0 && s < 1.0) {
1130 return;
1131 }
1132 if (m_zoom > 10.0 / 7.9 && s > 1.0) {
1133 return;
1134 }
1135 QList<QGraphicsView *> viewlist = views();
1136 if (!viewlist.isEmpty()) {
1137 viewlist[0]->scale(s, s);
1138 m_zoom = m_zoom * s;
1139 }
1140 ////qCDebug(KDENLIVE_LOG)<<"////////// ZOOM: "<<zoom;
1141 }
1142
setZoom(double s)1143 void GraphicsSceneRectMove::setZoom(double s)
1144 {
1145 QList<QGraphicsView *> viewlist = views();
1146 if (!viewlist.isEmpty()) {
1147 viewlist[0]->resetTransform();
1148 viewlist[0]->scale(s, s);
1149 m_zoom = s;
1150 }
1151
1152 ////qCDebug(KDENLIVE_LOG)<<"////////// ZOOM: "<<zoom;
1153 }
1154
setCursor(const QCursor & c)1155 void GraphicsSceneRectMove::setCursor(const QCursor &c)
1156 {
1157 const QList<QGraphicsView *> l = views();
1158 for (QGraphicsView *v : l) {
1159 v->setCursor(c);
1160 }
1161 }
1162
slotUpdateFontSize(int s)1163 void GraphicsSceneRectMove::slotUpdateFontSize(int s)
1164 {
1165 m_fontSize = s;
1166 }
1167
drawForeground(QPainter * painter,const QRectF & rect)1168 void GraphicsSceneRectMove::drawForeground(QPainter *painter, const QRectF &rect)
1169 {
1170 // draw the grid if needed
1171 if (m_gridSize <= 1) {
1172 return;
1173 }
1174
1175 QPen pen(QColor(255, 0, 0, 100));
1176 painter->setPen(pen);
1177
1178 qreal left = int(rect.left()) - (int(rect.left()) % m_gridSize);
1179 qreal top = int(rect.top()) - (int(rect.top()) % m_gridSize);
1180 QVector<QPointF> points;
1181 for (qreal x = left; x < rect.right(); x += m_gridSize) {
1182 for (qreal y = top; y < rect.bottom(); y += m_gridSize) {
1183 points.append(QPointF(x, y));
1184 }
1185 }
1186 painter->drawPoints(points.data(), points.size());
1187 }
1188
gridSize() const1189 int GraphicsSceneRectMove::gridSize() const
1190 {
1191 return m_gridSize;
1192 }
1193
slotUseGrid(bool enableGrid)1194 void GraphicsSceneRectMove::slotUseGrid(bool enableGrid)
1195 {
1196 m_gridSize = enableGrid ? 20 : 1;
1197 }
1198
addNewItem(QGraphicsItem * item)1199 void GraphicsSceneRectMove::addNewItem(QGraphicsItem *item)
1200 {
1201 clearSelection();
1202 addItem(item);
1203 item->setSelected(true);
1204 m_selectedItem = item;
1205 }
1206