1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2010-09-09
7 * Description : tag region frame
8 *
9 * Copyright (C) 2007 by Aurelien Gateau <agateau at kde dot org>
10 * Copyright (C) 2010-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
11 *
12 * This program is free software; you can redistribute it
13 * and/or modify it under the terms of the GNU General
14 * Public License as published by the Free Software Foundation;
15 * either version 2, or (at your option)
16 * any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * ============================================================ */
24
25 #include "regionframeitem.h"
26
27 // C++ includes
28
29 #include <cmath>
30
31 // Qt includes
32
33 #include <QApplication>
34 #include <QFlags>
35 #include <QGraphicsProxyWidget>
36 #include <QGraphicsScene>
37 #include <QGraphicsSceneMouseEvent>
38 #include <QHBoxLayout>
39 #include <QPainter>
40 #include <QPropertyAnimation>
41 #include <QRect>
42 #include <QTimer>
43 #include <QToolButton>
44
45 // Local includes
46
47 #include "graphicsdimgitem.h"
48 #include "itemvisibilitycontroller.h"
49
50 namespace
51 {
52 static const int HANDLE_SIZE = 15;
53 }
54
55 namespace Digikam
56 {
57
58 enum CropHandleFlag
59 {
60 CH_None,
61 CH_Top = 1,
62 CH_Left = 2,
63 CH_Right = 4,
64 CH_Bottom = 8,
65 CH_TopLeft = CH_Top | CH_Left,
66 CH_BottomLeft = CH_Bottom | CH_Left,
67 CH_TopRight = CH_Top | CH_Right,
68 CH_BottomRight = CH_Bottom | CH_Right,
69 CH_Content = 16
70 };
71
72 enum HudSide
73 {
74 HS_None = 0, ///< Special value used to avoid initial animation
75 HS_Top = 1,
76 HS_Bottom = 2,
77 HS_Inside = 4,
78 HS_TopInside = HS_Top | HS_Inside,
79 HS_BottomInside = HS_Bottom | HS_Inside
80 };
81
82 typedef QPair<QPointF, HudSide> OptimalPosition;
83
84 Q_DECLARE_FLAGS(CropHandle, CropHandleFlag)
85
86 } // namespace Digikam
87
88 Q_DECLARE_OPERATORS_FOR_FLAGS(Digikam::CropHandle)
89
90 // --------------------------------------------------------------------------------
91
92 namespace Digikam
93 {
94
95 class Q_DECL_HIDDEN RegionFrameItem::Private
96 {
97 public:
98
99 explicit Private(RegionFrameItem* const q);
100
101 QRectF handleRect(CropHandle handle) const;
102 CropHandle handleAt(const QPointF& pos) const;
103 void updateCursor(CropHandle handle, bool buttonDown);
104 QRectF keepRectInsideImage(const QRectF& rect, bool moving = true) const;
105 OptimalPosition computeOptimalHudWidgetPosition() const;
106 void updateHudWidgetPosition();
107
108 public:
109
110 RegionFrameItem* const q;
111
112 HudSide hudSide;
113 QRectF viewportRect;
114 QList<CropHandle> cropHandleList;
115 CropHandle movingHandle;
116 QPointF lastMouseMovePos;
117 double fixedRatio;
118 QGraphicsWidget* hudWidget;
119
120 RegionFrameItem::Flags flags;
121
122 AnimatedVisibility* resizeHandleVisibility;
123 qreal hoverAnimationOpacity;
124 QTimer* hudTimer;
125 QPointF hudEndPos;
126
127 const int HUD_TIMER_MAX_PIXELS_PER_UPDATE;
128 const int HUD_TIMER_ANIMATION_INTERVAL;
129 };
130
Private(RegionFrameItem * const qq)131 RegionFrameItem::Private::Private(RegionFrameItem* const qq)
132 : q (qq),
133 hudSide (HS_None),
134 movingHandle (CH_None),
135 fixedRatio (0),
136 hudWidget (nullptr),
137 flags (NoFlags),
138 resizeHandleVisibility (nullptr),
139 hoverAnimationOpacity (1.0),
140 hudTimer (nullptr),
141 HUD_TIMER_MAX_PIXELS_PER_UPDATE (20),
142 HUD_TIMER_ANIMATION_INTERVAL (20)
143 {
144
145 cropHandleList << CH_Left << CH_Right << CH_Top << CH_Bottom
146 << CH_TopLeft << CH_TopRight
147 << CH_BottomLeft << CH_BottomRight;
148 }
149
handleRect(CropHandle handle) const150 QRectF RegionFrameItem::Private::handleRect(CropHandle handle) const
151 {
152 QSizeF size = q->boundingRect().size();
153 double left, top;
154
155 if (handle & CH_Top)
156 {
157 top = 0;
158 }
159 else if (handle & CH_Bottom)
160 {
161 top = size.height() - HANDLE_SIZE;
162 }
163 else
164 {
165 top = (size.height() - HANDLE_SIZE) / 2;
166 }
167
168 if (handle & CH_Left)
169 {
170 left = 0;
171 }
172 else if (handle & CH_Right)
173 {
174 left = size.width() - HANDLE_SIZE;
175 }
176 else
177 {
178 left = (size.width() - HANDLE_SIZE) / 2;
179 }
180
181 return QRectF(left, top, HANDLE_SIZE, HANDLE_SIZE);
182 }
183
handleAt(const QPointF & pos) const184 CropHandle RegionFrameItem::Private::handleAt(const QPointF& pos) const
185 {
186 if (flags & ShowResizeHandles)
187 {
188 foreach (const CropHandle& handle, cropHandleList)
189 {
190 QRectF rect = handleRect(handle);
191
192 if (rect.contains(pos))
193 {
194 return handle;
195 }
196 }
197 }
198
199 if (flags & MoveByDrag)
200 {
201 if (q->boundingRect().contains(pos))
202 {
203 return CH_Content;
204 }
205 }
206
207
208 return CH_None;
209 }
210
updateCursor(CropHandle handle,bool buttonDown)211 void RegionFrameItem::Private::updateCursor(CropHandle handle, bool buttonDown)
212 {
213 Qt::CursorShape shape;
214
215 switch (handle)
216 {
217 case CH_TopLeft:
218 case CH_BottomRight:
219 shape = Qt::SizeFDiagCursor;
220 break;
221
222 case CH_TopRight:
223 case CH_BottomLeft:
224 shape = Qt::SizeBDiagCursor;
225 break;
226
227 case CH_Left:
228 case CH_Right:
229 shape = Qt::SizeHorCursor;
230 break;
231
232 case CH_Top:
233 case CH_Bottom:
234 shape = Qt::SizeVerCursor;
235 break;
236
237 case CH_Content:
238 shape = buttonDown ? Qt::ClosedHandCursor : Qt::OpenHandCursor;
239 break;
240
241 default:
242 shape = Qt::ArrowCursor;
243 break;
244 }
245
246 q->setCursor(shape);
247 }
248
keepRectInsideImage(const QRectF & rect,bool moving) const249 QRectF RegionFrameItem::Private::keepRectInsideImage(const QRectF& rect, bool moving) const
250 {
251 QRectF r(rect);
252 const QSizeF imageSize = q->parentDImgItem()->boundingRect().size();
253
254 if ((r.width() > imageSize.width()) || (r.height() > imageSize.height()))
255 {
256 // This can happen when the crop ratio changes
257
258 QSizeF rectSize = r.size();
259 rectSize.scale(imageSize, Qt::KeepAspectRatio);
260 r.setSize(rectSize);
261 }
262
263 if (r.right() > imageSize.width())
264 {
265 moving ? r.moveRight(imageSize.width()) : r.setRight(imageSize.width());
266 }
267 else if (r.left() < 0)
268 {
269 moving ? r.moveLeft(0) : r.setLeft(0);
270 }
271
272 if (r.bottom() > imageSize.height())
273 {
274 moving ? r.moveBottom(imageSize.height()) : r.setBottom(imageSize.height());
275 }
276 else if (r.top() < 0)
277 {
278 moving ? r.moveTop(0) : r.setTop(0);
279 }
280
281 return r;
282 }
283
computeOptimalHudWidgetPosition() const284 OptimalPosition RegionFrameItem::Private::computeOptimalHudWidgetPosition() const
285 {
286 const QRectF visibleSceneRect = viewportRect.isValid() ? viewportRect : q->scene()->sceneRect();
287 const QRectF rect = q->sceneBoundingRect();
288
289 const int margin = HANDLE_SIZE;
290 const int hudHeight = hudWidget->boundingRect().height();
291 const QRectF hudMaxRect = visibleSceneRect.adjusted(0, 0, 0, -hudHeight);
292
293 OptimalPosition ret;
294
295 // Compute preferred and fallback positions. Preferred is outside rect
296 // on the same side, fallback is outside on the other side.
297
298 OptimalPosition preferred = OptimalPosition(QPointF(rect.left(), rect.bottom() + margin), HS_Bottom);
299 OptimalPosition fallback = OptimalPosition(QPointF(rect.left(), rect.top() - margin - hudHeight), HS_Top);
300
301 if (hudSide & HS_Top)
302 {
303 std::swap(preferred, fallback);
304 }
305
306 // Check if a position outside rect fits
307
308 if (hudMaxRect.contains(preferred.first))
309 {
310 ret = preferred;
311 }
312 else if (hudMaxRect.contains(fallback.first))
313 {
314 ret= fallback;
315 }
316 else
317 {
318 // Does not fit outside, use a position inside rect
319
320 QPoint pos;
321
322 if (hudSide & HS_Top)
323 {
324 pos = QPoint(rect.left() + margin, rect.top() + margin);
325 }
326 else
327 {
328 pos = QPoint(rect.left() + margin, rect.bottom() - margin - hudHeight);
329 }
330
331 ret = OptimalPosition(pos, HudSide(hudSide | HS_Inside));
332 }
333
334 // Ensure it's always fully visible
335
336 ret.first.rx() = qMin(ret.first.rx(), hudMaxRect.width() - hudWidget->boundingRect().width());
337
338 // map from scene to item coordinates
339
340 ret.first = q->mapFromScene(ret.first);
341
342 return ret;
343 }
344
updateHudWidgetPosition()345 void RegionFrameItem::Private::updateHudWidgetPosition()
346 {
347 if (!hudWidget || !q->scene())
348 {
349 return;
350 }
351
352 OptimalPosition result = computeOptimalHudWidgetPosition();
353
354 if ((result.first == hudWidget->pos()) && (result.second == hudSide))
355 {
356 return;
357 }
358
359 if (hudSide == HS_None)
360 {
361 hudSide = result.second;
362 }
363
364 if ((hudSide == result.second) && !hudTimer->isActive())
365 {
366 // Not changing side and not in an animation, move directly the hud
367 // to the final position to avoid lagging effect
368
369 hudWidget->setPos(result.first);
370 }
371 else
372 {
373 hudEndPos = result.first;
374 hudSide = result.second;
375
376 if (!hudTimer->isActive())
377 {
378 hudTimer->start();
379 }
380 }
381 }
382
383 // ---------------------------------------------------------------------------------------
384
RegionFrameItem(QGraphicsItem * const item)385 RegionFrameItem::RegionFrameItem(QGraphicsItem* const item)
386 : DImgChildItem(item),
387 d (new Private(this))
388 {
389 d->resizeHandleVisibility = new AnimatedVisibility(this);
390 d->resizeHandleVisibility->controller()->setShallBeShown(false);
391
392 connect(d->resizeHandleVisibility, SIGNAL(visibleChanged()),
393 this, SLOT(slotUpdate()));
394
395 connect(d->resizeHandleVisibility, SIGNAL(opacityChanged()),
396 this, SLOT(slotUpdate()));
397
398 d->hudTimer = new QTimer(this);
399 d->hudTimer->setInterval(d->HUD_TIMER_ANIMATION_INTERVAL);
400
401 connect(d->hudTimer, SIGNAL(timeout()),
402 this, SLOT(moveHudWidget()));
403
404 connect(this, SIGNAL(positionChanged()),
405 this, SLOT(slotPosChanged()));
406
407 connect(this, SIGNAL(sizeChanged()),
408 this, SLOT(slotSizeChanged()));
409
410 setFlags(GeometryEditable);
411
412 d->updateHudWidgetPosition();
413 }
414
~RegionFrameItem()415 RegionFrameItem::~RegionFrameItem()
416 {
417 if (d->hudWidget)
418 {
419 // See bug #359196: hide or close the QGraphicsWidget before delete it. Possible Qt bug?
420
421 d->hudWidget->hide();
422 delete d->hudWidget;
423 }
424
425 delete d;
426 }
427
setHudWidget(QWidget * const widget,Qt::WindowFlags wFlags)428 void RegionFrameItem::setHudWidget(QWidget* const widget, Qt::WindowFlags wFlags)
429 {
430 QGraphicsProxyWidget* const proxy = new QGraphicsProxyWidget(nullptr, wFlags);
431
432 /*
433 * This is utterly undocumented magic. If you add a normal widget directly,
434 * with transparent parts (round corners), you will have ugly color in the corners.
435 * If you set WA_TranslucentBackground on the widget directly, a lot of the
436 * painting and stylesheets is broken. Like this, with an extra container, it seems to work.
437 */
438
439 QWidget* const container = new QWidget;
440 container->setAttribute(Qt::WA_TranslucentBackground);
441 QHBoxLayout* const layout = new QHBoxLayout;
442 layout->setSizeConstraint(QLayout::SetFixedSize);
443 layout->setContentsMargins(QMargins());
444 layout->setSpacing(0);
445 layout->addWidget(widget);
446 container->setLayout(layout);
447 proxy->setWidget(container);
448
449 // Reset fixed sizes wrongly copied by setWidget onto the QGraphicsWidget
450
451 proxy->setMinimumSize(QSizeF());
452 proxy->setMaximumSize(QSizeF());
453
454 setHudWidget(proxy);
455 }
456
setHudWidget(QGraphicsWidget * const hudWidget)457 void RegionFrameItem::setHudWidget(QGraphicsWidget* const hudWidget)
458 {
459 if (d->hudWidget == hudWidget)
460 {
461 return;
462 }
463
464 if (d->hudWidget)
465 {
466 d->hudWidget->hide();
467 delete d->hudWidget;
468 }
469
470 d->hudWidget = hudWidget;
471
472 if (d->hudWidget)
473 {
474 d->hudWidget->setParentItem(this);
475 d->hudWidget->installEventFilter(this);
476 d->updateHudWidgetPosition();
477 }
478 }
479
hudWidget() const480 QGraphicsWidget* RegionFrameItem::hudWidget() const
481 {
482 return d->hudWidget;
483 }
484
setFlags(Flags flags)485 void RegionFrameItem::setFlags(Flags flags)
486 {
487 if (d->flags == flags)
488 {
489 return;
490 }
491
492 d->flags = flags;
493 update();
494 setAcceptHoverEvents(d->flags & GeometryEditable);
495 d->resizeHandleVisibility->controller()->setShallBeShown(d->flags & ShowResizeHandles);
496
497 // ensure cursor is reset
498
499 CropHandle handle = d->handleAt(QCursor::pos());
500 d->updateCursor(handle, false/* buttonDown*/);
501 }
502
changeFlags(Flags flags,bool addOrRemove)503 void RegionFrameItem::changeFlags(Flags flags, bool addOrRemove)
504 {
505 if (addOrRemove)
506 {
507 setFlags(d->flags | flags);
508 }
509 else
510 {
511 setFlags(d->flags & ~flags);
512 }
513 }
514
setHudWidgetVisible(bool visible)515 void RegionFrameItem::setHudWidgetVisible(bool visible)
516 {
517 if (d->hudWidget)
518 {
519 d->hudWidget->setVisible(visible);
520 }
521 }
522
flags() const523 RegionFrameItem::Flags RegionFrameItem::flags() const
524 {
525 return d->flags;
526 }
527
setFixedRatio(double ratio)528 void RegionFrameItem::setFixedRatio(double ratio)
529 {
530 d->fixedRatio = ratio;
531 }
532
slotSizeChanged()533 void RegionFrameItem::slotSizeChanged()
534 {
535 d->updateHudWidgetPosition();
536 }
537
slotPosChanged()538 void RegionFrameItem::slotPosChanged()
539 {
540 d->updateHudWidgetPosition();
541 }
542
hudSizeChanged()543 void RegionFrameItem::hudSizeChanged()
544 {
545 d->updateHudWidgetPosition();
546 }
547
setViewportRect(const QRectF & rect)548 void RegionFrameItem::setViewportRect(const QRectF& rect)
549 {
550 d->viewportRect = rect;
551 d->updateHudWidgetPosition();
552 }
553
boundingRect() const554 QRectF RegionFrameItem::boundingRect() const
555 {
556 return DImgChildItem::boundingRect(); //.adjusted(-1, -1, 1, 1);
557 }
558
paint(QPainter * painter,const QStyleOptionGraphicsItem *,QWidget *)559 void RegionFrameItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*)
560 {
561 /*
562 QRect rect = d->viewportCropRect();
563 QRect imageRect = imageView()->rect();
564 static const QColor outerColor = QColor::fromHsvF(0, 0, 0, 0.5);
565 QRegion outerRegion = QRegion(imageRect) - QRegion(rect);
566
567 foreach (const QRect& outerRect, outerRegion.rects())
568 {
569 painter->fillRect(outerRect, outerColor);
570 }
571 */
572
573 const QColor borderColor = QColor::fromHsvF(0, 0, 1.0, 0.66 + 0.34 * d->hoverAnimationOpacity);
574 const QColor fillColor = QColor::fromHsvF(0, 0, 0.75, 0.66);
575
576 // will paint to the left and bottom of logical coordinates
577
578 QRectF drawRect = boundingRect();
579
580 painter->setPen(borderColor);
581 painter->drawRect(drawRect);
582
583 if (d->resizeHandleVisibility->isVisible())
584 {
585 // Only draw handles when user is not resizing
586
587 if (d->movingHandle == CH_None)
588 {
589 painter->setOpacity(d->resizeHandleVisibility->opacity());
590 painter->setBrush(fillColor);
591
592 foreach (const CropHandle& handle, d->cropHandleList)
593 {
594 QRectF rect = d->handleRect(handle);
595 painter->drawRect(rect);
596 }
597 }
598 }
599 }
600
slotUpdate()601 void RegionFrameItem::slotUpdate()
602 {
603 update();
604 }
605
hoverEnterEvent(QGraphicsSceneHoverEvent * e)606 void RegionFrameItem::hoverEnterEvent(QGraphicsSceneHoverEvent* e)
607 {
608 if (boundingRect().contains(e->pos()))
609 {
610 d->resizeHandleVisibility->controller()->show();
611 }
612 }
613
hoverLeaveEvent(QGraphicsSceneHoverEvent * e)614 void RegionFrameItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* e)
615 {
616 if (!boundingRect().contains(e->pos()))
617 {
618 d->resizeHandleVisibility->controller()->hide();
619 }
620 }
621
hoverMoveEvent(QGraphicsSceneHoverEvent * e)622 void RegionFrameItem::hoverMoveEvent(QGraphicsSceneHoverEvent* e)
623 {
624 if (boundingRect().contains(e->pos()))
625 {
626 if (d->flags & GeometryEditable)
627 {
628 CropHandle handle = d->handleAt(e->pos());
629 d->updateCursor(handle, false/* buttonDown*/);
630 }
631
632 d->resizeHandleVisibility->controller()->show();
633 }
634 }
635
mousePressEvent(QGraphicsSceneMouseEvent * event)636 void RegionFrameItem::mousePressEvent(QGraphicsSceneMouseEvent* event)
637 {
638 // FIXME: Fade out?
639 /*
640 d->hudWidget->hide();
641 */
642 if (!(d->flags & GeometryEditable))
643 {
644 DImgChildItem::mousePressEvent(event);
645 return;
646 }
647
648 d->movingHandle = d->handleAt(event->pos());
649 d->updateCursor(d->movingHandle, event->buttons() != Qt::NoButton);
650
651 if (d->movingHandle == CH_Content)
652 {
653 d->lastMouseMovePos = mapToParent(event->pos());
654 }
655
656 // Update to hide handles
657
658 update();
659 }
660
mouseMoveEvent(QGraphicsSceneMouseEvent * event)661 void RegionFrameItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
662 {
663 const QSizeF maxSize = parentDImgItem()->boundingRect().size();
664 const QPointF point = mapToParent(event->pos());
665 qreal posX = qBound<qreal>(0., point.x(), maxSize.width());
666 qreal posY = qBound<qreal>(0., point.y(), maxSize.height());
667 QRectF r = rect();
668
669 // Adjust edge
670
671 if (d->movingHandle & CH_Top)
672 {
673 r.setTop(posY);
674 }
675 else if (d->movingHandle & CH_Bottom)
676 {
677 r.setBottom(posY);
678 }
679
680 if (d->movingHandle & CH_Left)
681 {
682 r.setLeft(posX);
683 }
684 else if (d->movingHandle & CH_Right)
685 {
686 r.setRight(posX);
687 }
688
689 // Normalize rect and handles (this is useful when user drag the right side
690 // of the crop rect to the left of the left side)
691
692 if (r.height() < 0)
693 {
694 d->movingHandle = d->movingHandle ^ (CH_Top | CH_Bottom);
695 }
696
697 if (r.width() < 0)
698 {
699 d->movingHandle = d->movingHandle ^ (CH_Left | CH_Right);
700 }
701
702 r = r.normalized();
703
704 // Enforce ratio
705
706 if (d->fixedRatio > 0.)
707 {
708 if ((d->movingHandle == CH_Top) || (d->movingHandle == CH_Bottom))
709 {
710 // Top or bottom
711
712 int width = int(r.height() / d->fixedRatio);
713 r.setWidth(width);
714 }
715 else if ((d->movingHandle == CH_Left) || (d->movingHandle == CH_Right))
716 {
717 // Left or right
718
719 int height = int(r.width() * d->fixedRatio);
720 r.setHeight(height);
721 }
722 else if (d->movingHandle & CH_Top)
723 {
724 // Top left or top right
725
726 int height = int(r.width() * d->fixedRatio);
727 r.setTop(r.bottom() - height);
728 }
729 else if (d->movingHandle & CH_Bottom)
730 {
731 // Bottom left or bottom right
732
733 int height = int(r.width() * d->fixedRatio);
734 r.setHeight(height);
735 }
736 }
737
738 if (d->movingHandle == CH_Content)
739 {
740 QPointF delta = point - d->lastMouseMovePos;
741 r.adjust(delta.x(), delta.y(), delta.x(), delta.y());
742 d->lastMouseMovePos = mapToParent(event->pos());
743 }
744
745 setRect(d->keepRectInsideImage(r));
746
747 d->updateHudWidgetPosition();
748 }
749
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)750 void RegionFrameItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
751 {
752 // FIXME: Fade in?
753 /*
754 d->hudWidget->show();
755 */
756 d->movingHandle = CH_None;
757 d->updateCursor(d->handleAt(event->pos()), false);
758
759 // Update to show handles
760
761 update();
762 }
763
eventFilter(QObject * watched,QEvent * event)764 bool RegionFrameItem::eventFilter(QObject* watched, QEvent* event)
765 {
766 if ((watched == d->hudWidget) && (event->type() == QEvent::GraphicsSceneResize))
767 {
768 d->updateHudWidgetPosition();
769 }
770
771 return DImgChildItem::eventFilter(watched, event);
772 }
773
moveHudWidget()774 void RegionFrameItem::moveHudWidget()
775 {
776 const QPointF delta = d->hudEndPos - d->hudWidget->pos();
777 const double distance = sqrt(pow(delta.x(), 2) + pow(delta.y(), 2));
778 QPointF pos;
779
780 if (distance > double(d->HUD_TIMER_MAX_PIXELS_PER_UPDATE))
781 {
782 pos = d->hudWidget->pos() + delta * double(d->HUD_TIMER_MAX_PIXELS_PER_UPDATE) / distance;
783 }
784 else
785 {
786 pos = d->hudEndPos;
787 d->hudTimer->stop();
788 }
789
790 d->hudWidget->setPos(pos);
791 }
792
setRectInSceneCoordinatesAdjusted(const QRectF & rect)793 void RegionFrameItem::setRectInSceneCoordinatesAdjusted(const QRectF& rect)
794 {
795 setRectInSceneCoordinates(d->keepRectInsideImage(rect, false));
796 }
797
798 } // namespace Digikam
799