Improve Puzzle's piece rotation handlers.

This commit is contained in:
Roman Telezhynskyi 2022-02-09 15:31:34 +02:00
parent 23e6d524b1
commit b75292c341
10 changed files with 429 additions and 363 deletions

View File

@ -54,7 +54,6 @@ VPSheetSceneData::VPSheetSceneData(const VPLayoutPtr &layout, const QUuid &sheet
m_scene->addItem(m_graphicsTileGrid); m_scene->addItem(m_graphicsTileGrid);
m_rotationControls = new VPGraphicsPieceControls(layout); m_rotationControls = new VPGraphicsPieceControls(layout);
m_rotationControls->setVisible(false);
m_scene->addItem(m_rotationControls); m_scene->addItem(m_rotationControls);
m_rotationOrigin = new VPGraphicsTransformationOrigin(layout); m_rotationOrigin = new VPGraphicsTransformationOrigin(layout);

View File

@ -33,6 +33,8 @@
#include <QIcon> #include <QIcon>
#include <QPainter> #include <QPainter>
#include <QtDebug> #include <QtDebug>
#include <QGuiApplication>
#include <QScreen>
#include "../vmisc/compatibility.h" #include "../vmisc/compatibility.h"
#include "../vwidgets/global.h" #include "../vwidgets/global.h"
@ -40,20 +42,13 @@
#include "../layout/vppiece.h" #include "../layout/vppiece.h"
#include "../undocommands/vpundopiecerotate.h" #include "../undocommands/vpundopiecerotate.h"
#include "../undocommands/vpundooriginmove.h" #include "../undocommands/vpundooriginmove.h"
#include "qgraphicsscene.h"
#include "qgraphicsview.h"
#include "qnamespace.h"
#include "vpgraphicspiece.h" #include "vpgraphicspiece.h"
namespace namespace
{ {
const qreal arcStartAngle = 105;
const qreal arcAngle = 25;
const qreal arcRadius = 15;
const qreal arrowTail = 2;
const qreal arrowSide = 2;
const qreal arrowLength = 4;
const qreal arrow1Angle = 13;
const qreal arrow2Angle = 38;
constexpr qreal penWidth = 2; constexpr qreal penWidth = 2;
const qreal centerRadius1 = 5; const qreal centerRadius1 = 5;
@ -62,15 +57,6 @@ const qreal centerRadius2 = 10;
const QColor defaultColor = Qt::black; const QColor defaultColor = Qt::black;
const QColor hoverColor = Qt::green; const QColor hoverColor = Qt::green;
enum class HandleCorner : int
{
Invalid = 0,
TopLeft = 1,
TopRight = 2,
BottomRight = 3,
BottomLeft = 4
};
auto TransformationOrigin(const VPLayoutPtr &layout, const QRectF &boundingRect) -> VPTransformationOrigon auto TransformationOrigin(const VPLayoutPtr &layout, const QRectF &boundingRect) -> VPTransformationOrigon
{ {
SCASSERT(layout != nullptr) SCASSERT(layout != nullptr)
@ -310,10 +296,12 @@ VPGraphicsPieceControls::VPGraphicsPieceControls(const VPLayoutPtr &layout, QGra
m_layout(layout) m_layout(layout)
{ {
SCASSERT(m_layout != nullptr) SCASSERT(m_layout != nullptr)
QPixmap cursor_pixmap = QIcon("://puzzleicon/svg/cursor_rotate.svg").pixmap(QSize(32,32)); setCursor(QCursor(Qt::OpenHandCursor));
setCursor(QCursor(cursor_pixmap, 16, 16)); setZValue(100);
setZValue(1); setFlag(QGraphicsItem::ItemIgnoresTransformations);
setAcceptHoverEvents(true); setAcceptHoverEvents(true);
InitPixmaps();
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -326,7 +314,7 @@ void VPGraphicsPieceControls::on_UpdateControls()
m_selectedPieces = SelectedPieces(); m_selectedPieces = SelectedPieces();
m_pieceRect = PiecesBoundingRect(m_selectedPieces); m_pieceRect = PiecesBoundingRect(m_selectedPieces);
setVisible(not m_pieceRect.isNull()); m_controlsVisible = not m_pieceRect.isNull();
if (not m_pieceRect.isNull()) if (not m_pieceRect.isNull())
{ {
@ -361,8 +349,20 @@ void VPGraphicsPieceControls::on_HideHandles(bool hide)
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::boundingRect() const -> QRectF auto VPGraphicsPieceControls::boundingRect() const -> QRectF
{ {
constexpr qreal halfPenWidth = penWidth/2.; QRectF boundingRect;
return Handles().boundingRect().adjusted(-halfPenWidth, -halfPenWidth, halfPenWidth, halfPenWidth);
auto HandlerBoundingRect = [this, &boundingRect](VPHandleCorner corner, VPHandleCornerType type, QPointF pos)
{
QPixmap handler = HandlerPixmap(m_handleCorner == corner, type);
boundingRect = boundingRect.united(QRectF(pos, handler.size() / handler.devicePixelRatio()));
};
HandlerBoundingRect(VPHandleCorner::TopLeft, VPHandleCornerType::TopLeft, TopLeftHandlerPosition());
HandlerBoundingRect(VPHandleCorner::TopRight, VPHandleCornerType::TopRight, TopRightHandlerPosition());
HandlerBoundingRect(VPHandleCorner::BottomRight, VPHandleCornerType::BottomRight, BottomRightHandlerPosition());
HandlerBoundingRect(VPHandleCorner::BottomLeft, VPHandleCornerType::BottomLeft, BottomLeftHandlerPosition());
return boundingRect;
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -377,32 +377,52 @@ void VPGraphicsPieceControls::paint(QPainter *painter, const QStyleOptionGraphic
Q_UNUSED(widget); Q_UNUSED(widget);
Q_UNUSED(option); Q_UNUSED(option);
const qreal scale = SceneScale(scene());
QPen pen(defaultColor, penWidth/scale, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
painter->setPen(pen);
if (m_controlsVisible) if (m_controlsVisible)
{ {
TopLeftControl(painter); painter->drawPixmap(TopLeftHandlerPosition(),
TopRightControl(painter); HandlerPixmap(m_handleCorner == VPHandleCorner::TopLeft,
BottomLeftControl(painter); VPHandleCornerType::TopLeft));
BottomRightControl(painter);
painter->drawPixmap(TopRightHandlerPosition(),
HandlerPixmap(m_handleCorner == VPHandleCorner::TopRight,
VPHandleCornerType::TopRight));
painter->drawPixmap(BottomRightHandlerPosition(),
HandlerPixmap(m_handleCorner == VPHandleCorner::BottomRight,
VPHandleCornerType::BottomRight));
painter->drawPixmap(BottomLeftHandlerPosition(),
HandlerPixmap(m_handleCorner == VPHandleCorner::BottomLeft,
VPHandleCornerType::BottomLeft));
} }
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VPGraphicsPieceControls::mousePressEvent(QGraphicsSceneMouseEvent *event) void VPGraphicsPieceControls::mousePressEvent(QGraphicsSceneMouseEvent *event)
{ {
if(event->button() == Qt::LeftButton) if(event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
{ {
m_rotationStartPoint = event->scenePos(); m_rotationStartPoint = event->scenePos();
m_rotationSum = 0; m_rotationSum = 0;
m_controlsVisible = false; m_controlsVisible = false;
m_handleCorner = SelectedHandleCorner(event->scenePos()); m_handleCorner = SelectedHandleCorner(event->pos());
m_ignorePieceTransformation = true; m_ignorePieceTransformation = true;
prepareGeometryChange(); prepareGeometryChange();
if (m_handleCorner != VPHandleCorner::Invalid)
{
setCursor(QCursor(Qt::ClosedHandCursor));
event->accept();
}
else
{
QGraphicsView *view = ItemView();
if (view != nullptr)
{
setCursor(view->viewport()->cursor());
}
event->ignore();
}
} }
else else
{ {
@ -413,8 +433,7 @@ void VPGraphicsPieceControls::mousePressEvent(QGraphicsSceneMouseEvent *event)
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event) void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{ {
if((event->modifiers() & Qt::ShiftModifier) != 0U if((event->modifiers() & Qt::ShiftModifier) && m_handleCorner != VPHandleCorner::Invalid)
&& static_cast<HandleCorner>(m_handleCorner) != HandleCorner::Invalid)
{ {
if (not m_originSaved) if (not m_originSaved)
{ {
@ -431,22 +450,22 @@ void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
VPTransformationOrigon origin; VPTransformationOrigon origin;
origin.custom = true; origin.custom = true;
if (static_cast<HandleCorner>(m_handleCorner) == HandleCorner::TopLeft) if (m_handleCorner == VPHandleCorner::TopLeft)
{
origin.origin = m_pieceRect.topLeft();
}
else if (static_cast<HandleCorner>(m_handleCorner) == HandleCorner::TopRight)
{
origin.origin = m_pieceRect.topRight();
}
else if (static_cast<HandleCorner>(m_handleCorner) == HandleCorner::BottomRight)
{ {
origin.origin = m_pieceRect.bottomRight(); origin.origin = m_pieceRect.bottomRight();
} }
else if (static_cast<HandleCorner>(m_handleCorner) == HandleCorner::BottomLeft) else if (m_handleCorner == VPHandleCorner::TopRight)
{ {
origin.origin = m_pieceRect.bottomLeft(); origin.origin = m_pieceRect.bottomLeft();
} }
else if (m_handleCorner == VPHandleCorner::BottomRight)
{
origin.origin = m_pieceRect.topLeft();
}
else if (m_handleCorner == VPHandleCorner::BottomLeft)
{
origin.origin = m_pieceRect.topRight();
}
sheet->SetTransformationOrigin(origin); sheet->SetTransformationOrigin(origin);
emit TransformationOriginChanged(); emit TransformationOriginChanged();
@ -565,6 +584,19 @@ void VPGraphicsPieceControls::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
m_controlsVisible = true; m_controlsVisible = true;
m_ignorePieceTransformation = false; m_ignorePieceTransformation = false;
if (SelectedHandleCorner(event->pos()) != VPHandleCorner::Invalid)
{
setCursor(QCursor(Qt::OpenHandCursor));
}
else
{
QGraphicsView *view = ItemView();
if (view != nullptr)
{
setCursor(view->viewport()->cursor());
}
}
if (m_originSaved) if (m_originSaved)
{ {
VPLayoutPtr layout = m_layout.toStrongRef(); VPLayoutPtr layout = m_layout.toStrongRef();
@ -591,49 +623,152 @@ void VPGraphicsPieceControls::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
QGraphicsObject::mouseReleaseEvent(event); QGraphicsObject::mouseReleaseEvent(event);
} }
//---------------------------------------------------------------------------------------------------------------------
void VPGraphicsPieceControls::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
UpdateCursor(SelectedHandleCorner(event->pos()));
QGraphicsObject::hoverEnterEvent(event);
}
//---------------------------------------------------------------------------------------------------------------------
void VPGraphicsPieceControls::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
UpdateCursor(SelectedHandleCorner(event->pos()));
QGraphicsObject::hoverMoveEvent(event);
}
//---------------------------------------------------------------------------------------------------------------------
void VPGraphicsPieceControls::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
UpdateCursor(VPHandleCorner::Invalid);
QGraphicsObject::hoverLeaveEvent(event);
}
//---------------------------------------------------------------------------------------------------------------------
void VPGraphicsPieceControls::InitPixmaps()
{
m_handlePixmaps.clear();
m_handleHoverPixmaps.clear();
m_handlePaths.clear();
auto InitPixmap = [this](VPHandleCornerType type, const QString &fileName)
{
const QFileInfo fileInfo(fileName);
const QString imageName = fileInfo.baseName();
const QString fileNameHover = QStringLiteral("%1/%2-hover.%3")
.arg(fileInfo.absolutePath(), imageName, fileInfo.suffix());
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
if (QGuiApplication::primaryScreen()->devicePixelRatio() >= 2 )
{
const QString fileName2x = QStringLiteral("%1/%2@2x.%3")
.arg(fileInfo.absolutePath(), imageName, fileInfo.suffix());
const QString fileName2xHover = QStringLiteral("%1/%2-hover@2x.%3")
.arg(fileInfo.absolutePath(), imageName, fileInfo.suffix());
m_handlePixmaps.insert(type, QPixmap(fileName2x));
m_handleHoverPixmaps.insert(type, QPixmap(fileName2xHover));
}
else
{
m_handlePixmaps.insert(type, QPixmap(fileName));
m_handleHoverPixmaps.insert(type, QPixmap(fileNameHover));
}
#else
m_handlePixmaps.insert(type, QPixmap(fileName));
m_handleHoverPixmaps.insert(type, QPixmap(fileNameHover));
#endif
QPainterPath p = PixmapToPainterPath(m_handlePixmaps.value(type));
p.setFillRule(Qt::WindingFill);
p.closeSubpath();
m_handlePaths.insert(type, p);
};
InitPixmap(VPHandleCornerType::TopLeft, QStringLiteral("://icon/32x32/rotate-top-left.png"));
InitPixmap(VPHandleCornerType::TopRight, QStringLiteral("://icon/32x32/rotate-top-right.png"));
InitPixmap(VPHandleCornerType::BottomRight, QStringLiteral("://icon/32x32/rotate-bottom-right.png"));
InitPixmap(VPHandleCornerType::BottomLeft, QStringLiteral("://icon/32x32/rotate-bottom-left.png"));
}
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::TopLeftHandlerPosition() const -> QPointF
{
return ControllersRect().topLeft();
}
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::TopRightHandlerPosition() const -> QPointF
{
QRectF rect = ControllersRect();
QPixmap handler = m_handlePixmaps.value(VPHandleCornerType::TopRight);
QSize size = handler.size() / handler.devicePixelRatio();
return {rect.topLeft().x() + (rect.width() - size.width()), rect.topLeft().y()};
}
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::BottomRightHandlerPosition() const -> QPointF
{
QRectF rect = ControllersRect();
QPixmap handler = m_handlePixmaps.value(VPHandleCornerType::BottomRight);
QSize size = handler.size() / handler.devicePixelRatio();
return {rect.topLeft().x() + (rect.width() - size.width()),
rect.topLeft().y() + (rect.height() - size.height())};
}
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::BottomLeftHandlerPosition() const -> QPointF
{
QRectF rect = ControllersRect();
QPixmap handler = m_handlePixmaps.value(VPHandleCornerType::BottomLeft);
QSize size = handler.size() / handler.devicePixelRatio();
return {rect.topLeft().x(), rect.topLeft().y() + (rect.height() - size.height())};
}
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::ControllerPath(VPHandleCornerType type, QPointF pos) const -> QPainterPath
{
QTransform t;
t.translate(pos.x(), pos.y());
QPainterPath controller = m_handlePaths.value(type);
controller = t.map(controller);
return controller;
}
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::TopLeftControl() const -> QPainterPath
{
return ControllerPath(VPHandleCornerType::TopLeft, TopLeftHandlerPosition());
}
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::TopRightControl() const -> QPainterPath
{
return ControllerPath(VPHandleCornerType::TopRight, TopRightHandlerPosition());
}
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::BottomRightControl() const -> QPainterPath
{
return ControllerPath(VPHandleCornerType::BottomRight, BottomRightHandlerPosition());
}
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::BottomLeftControl() const -> QPainterPath
{
return ControllerPath(VPHandleCornerType::BottomLeft, BottomLeftHandlerPosition());
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VPGraphicsPieceControls::SetIgnorePieceTransformation(bool newIgnorePieceTransformation) void VPGraphicsPieceControls::SetIgnorePieceTransformation(bool newIgnorePieceTransformation)
{ {
m_ignorePieceTransformation = newIgnorePieceTransformation; m_ignorePieceTransformation = newIgnorePieceTransformation;
} }
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::TopLeftControl(QPainter *painter) const -> QPainterPath
{
return Controller(QTransform(), painter);
}
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::TopRightControl(QPainter *painter) const -> QPainterPath
{
QTransform t;
t.scale(-1, 1);
t.translate(-(m_pieceRect.topLeft().x() * 2. + m_pieceRect.width()), 0);
return Controller(t, painter);
}
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::BottomLeftControl(QPainter *painter) const -> QPainterPath
{
QTransform t;
t.scale(1, -1);
t.translate(0, -(m_pieceRect.topLeft().y() * 2. + m_pieceRect.height()));
return Controller(t, painter);
}
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::BottomRightControl(QPainter *painter) const -> QPainterPath
{
QTransform t;
t.scale(-1, -1);
t.translate(-(m_pieceRect.topLeft().x() * 2. + m_pieceRect.width()),
-(m_pieceRect.topLeft().y() * 2. + m_pieceRect.height()));
return Controller(t, painter);
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::Handles() const -> QPainterPath auto VPGraphicsPieceControls::Handles() const -> QPainterPath
{ {
@ -647,161 +782,34 @@ auto VPGraphicsPieceControls::Handles() const -> QPainterPath
return path; return path;
} }
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::Controller(const QTransform &t, QPainter *painter) const -> QPainterPath
{
if (painter != nullptr)
{
QPen pen = painter->pen();
pen.setColor(defaultColor);
painter->setPen(pen);
}
QBrush colorBrush(defaultColor);
QPainterPath controller = ArrowPath();
controller = t.map(controller);
if (painter != nullptr)
{
painter->save();
painter->setBrush(colorBrush);
painter->drawPath(controller);
painter->restore();
}
return controller;
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::ControllersRect() const -> QRectF auto VPGraphicsPieceControls::ControllersRect() const -> QRectF
{ {
const qreal scale = SceneScale(scene()); const qreal scale = SceneScale(scene());
QPixmap handler = m_handlePixmaps.value(VPHandleCornerType::TopLeft);
QRectF pieceRect = m_pieceRect;
pieceRect = QRectF(pieceRect.topLeft()*scale, QSizeF(pieceRect.width()*scale, pieceRect.height()*scale));
QRectF rect = pieceRect;
if (pieceRect.width() < handler.width())
{
qreal diff = handler.width() - pieceRect.width();
rect.adjust(0, 0, diff, 0);
}
if (pieceRect.height() < handler.height())
{
qreal diff = handler.height() - pieceRect.height();
rect.adjust(0, 0, 0, diff);
}
const qreal gap = 2; const qreal gap = 2;
QRectF rect = m_pieceRect; rect.adjust(- (handler.width() + gap), - (handler.height() + gap), handler.width() + gap, handler.height() + gap);
const qreal minWidth = arcRadius/scale+gap;
const qreal minHeight = arcRadius/scale+gap;
if (m_pieceRect.width() < minWidth)
{
qreal diff = minWidth - m_pieceRect.width();
rect.adjust(-diff/2., 0, diff/2., 0);
}
if (m_pieceRect.height() < minHeight)
{
qreal diff = minHeight - m_pieceRect.height();
rect.adjust(0, -diff/2., 0, diff/2.);
}
return rect; return rect;
} }
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::ArrowPath() const -> QPainterPath
{
const qreal scale = SceneScale(scene())/2;
QPainterPath arrow;
QRectF pieceRect = ControllersRect();
QLineF start(pieceRect.topLeft().x(), pieceRect.topLeft().y(),
pieceRect.topLeft().x(), pieceRect.topLeft().y() - (arcRadius+1)/scale);
start.setAngle(arcStartAngle);
arrow.moveTo(start.p2());
QLineF baseLine(start.p2(), QPointF(start.p2().x()+arrowTail/scale, start.p2().y()));
baseLine.setAngle(arrow1Angle);
arrow.lineTo(baseLine.p2());
QLineF leftSide = QLineF(baseLine.p2(), baseLine.p1());
leftSide.setLength(arrowSide/scale);
leftSide.setAngle(leftSide.angle()-90);
arrow.lineTo(leftSide.p2());
start = QLineF(pieceRect.topLeft().x(), pieceRect.topLeft().y(),
pieceRect.topLeft().x(), pieceRect.topLeft().y() - arcRadius/scale);
start.setAngle(arcStartAngle);
baseLine = QLineF(start.p2(), QPointF(start.p2().x()+(arrowTail+arrowLength)/scale, start.p2().y()));
baseLine.setAngle(arrow1Angle);
arrow.lineTo(baseLine.p2());
start = QLineF(pieceRect.topLeft().x(), pieceRect.topLeft().y(),
pieceRect.topLeft().x(), pieceRect.topLeft().y() - (arcRadius-1)/scale);
start.setAngle(arcStartAngle);
baseLine = QLineF(start.p2(), QPointF(start.p2().x()+arrowTail/scale, start.p2().y()));
baseLine.setAngle(arrow1Angle);
QLineF rightSide = QLineF(baseLine.p2(), baseLine.p1());
rightSide.setLength(arrowSide/scale);
rightSide.setAngle(rightSide.angle()+90);
arrow.lineTo(rightSide.p2());
arrow.lineTo(baseLine.p2());
arrow.lineTo(start.p2());
// arc 1
QRectF arc1Rect(pieceRect.topLeft().x()-(arcRadius-1)/scale, pieceRect.topLeft().y()-(arcRadius-1)/scale,
(arcRadius-1)/scale*2, (arcRadius-1)/scale*2);
arrow.arcTo(arc1Rect, arcStartAngle, arcAngle);
// arrow 2
start = QLineF(pieceRect.topLeft().x(), pieceRect.topLeft().y(),
pieceRect.topLeft().x(), pieceRect.topLeft().y() - (arcRadius-1)/scale);
start.setAngle(arcStartAngle+arcAngle);
baseLine = QLineF(start.p2(), QPointF(start.p2().x()+arrowTail/scale, start.p2().y()));
baseLine.setAngle(arrow2Angle+180);
arrow.lineTo(baseLine.p2());
leftSide = QLineF(baseLine.p2(), baseLine.p1());
leftSide.setLength(arrowSide/scale);
leftSide.setAngle(leftSide.angle()-90);
arrow.lineTo(leftSide.p2());
start = QLineF(pieceRect.topLeft().x(), pieceRect.topLeft().y(),
pieceRect.topLeft().x(), pieceRect.topLeft().y() - arcRadius/scale);
start.setAngle(arcStartAngle+arcAngle);
baseLine = QLineF(start.p2(), QPointF(start.p2().x()+(arrowTail+arrowLength)/scale, start.p2().y()));
baseLine.setAngle(arrow2Angle+180);
arrow.lineTo(baseLine.p2());
start = QLineF(pieceRect.topLeft().x(), pieceRect.topLeft().y(),
pieceRect.topLeft().x(), pieceRect.topLeft().y() - (arcRadius+1)/scale);
start.setAngle(arcStartAngle+arcAngle);
baseLine = QLineF(start.p2(), QPointF(start.p2().x()+arrowTail/scale, start.p2().y()));
baseLine.setAngle(arrow2Angle+180);
rightSide = QLineF(baseLine.p2(), baseLine.p1());
rightSide.setLength(arrowSide/scale);
rightSide.setAngle(rightSide.angle()+90);
arrow.lineTo(rightSide.p2());
arrow.lineTo(baseLine.p2());
arrow.lineTo(start.p2());
// arc 2
QRectF arc2Rect(pieceRect.topLeft().x()-(arcRadius+1)/scale, pieceRect.topLeft().y()-(arcRadius+1)/scale,
(arcRadius+1)/scale*2, (arcRadius+1)/scale*2);
QPainterPath arc;
start = QLineF(pieceRect.topLeft().x(), pieceRect.topLeft().y(),
pieceRect.topLeft().x(), pieceRect.topLeft().y() - (arcRadius+1)/scale);
start.setAngle(arcStartAngle);
arc.moveTo(start.p2());
arc.arcTo(arc2Rect, arcStartAngle, arcAngle);
arrow.addPath(arc.toReversed());
return arrow;
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::SelectedPieces() const -> QList<VPPiecePtr> auto VPGraphicsPieceControls::SelectedPieces() const -> QList<VPPiecePtr>
{ {
@ -836,27 +844,74 @@ auto VPGraphicsPieceControls::PiecesBoundingRect(const QList<VPPiecePtr> &select
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::SelectedHandleCorner(const QPointF &pos) const -> int auto VPGraphicsPieceControls::ItemView() -> QGraphicsView *
{ {
if (TopLeftControl().boundingRect().contains(pos)) QGraphicsScene *scene = this->scene();
if (scene != nullptr)
{ {
return static_cast<int>(HandleCorner::BottomRight); QList<QGraphicsView *> views = scene->views();
if (not views.isEmpty())
{
return views.at(0);
}
} }
if (TopRightControl().boundingRect().contains(pos)) return nullptr;
{
return static_cast<int>(HandleCorner::BottomLeft);
} }
if (BottomLeftControl().boundingRect().contains(pos)) //---------------------------------------------------------------------------------------------------------------------
void VPGraphicsPieceControls::UpdateCursor(VPHandleCorner corner)
{ {
return static_cast<int>(HandleCorner::TopRight); m_handleCorner = corner;
if (m_handleCorner != VPHandleCorner::Invalid)
{
setCursor(QCursor(Qt::OpenHandCursor));
}
else
{
QGraphicsView *view = ItemView();
if (view != nullptr)
{
setCursor(view->viewport()->cursor());
}
}
} }
if (BottomRightControl().boundingRect().contains(pos)) //---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::SelectedHandleCorner(const QPointF &pos) const -> VPHandleCorner
{ {
return static_cast<int>(HandleCorner::TopLeft); QMap<VPHandleCorner, QPainterPath> corners
{
{VPHandleCorner::TopLeft, TopLeftControl()},
{VPHandleCorner::TopRight, TopRightControl()},
{VPHandleCorner::BottomRight, BottomRightControl()},
{VPHandleCorner::BottomLeft, BottomLeftControl()},
};
QPainterPath circle;
circle.addEllipse(pos.x()-4, pos.y()-4, 8, 8);
auto CheckCorner = [circle](const QPainterPath &handler)
{
return handler.intersects(circle) || handler.contains(circle);
};
auto i = corners.constBegin();
while (i != corners.constEnd())
{
if (CheckCorner(i.value()))
{
return i.key();
}
++i;
} }
return static_cast<int>(HandleCorner::Invalid); return VPHandleCorner::Invalid;
}
//---------------------------------------------------------------------------------------------------------------------
auto VPGraphicsPieceControls::HandlerPixmap(bool hover, VPHandleCornerType type) const -> QPixmap
{
return hover ? m_handleHoverPixmaps.value(type) : m_handlePixmaps.value(type);
} }

View File

@ -34,16 +34,38 @@
#include "scenedef.h" #include "scenedef.h"
#include "../layout/vpsheet.h" #include "../layout/vpsheet.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
#include "../vmisc/defglobal.h"
#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
class VPLayout; class VPLayout;
class VPGraphicsPiece; class VPGraphicsPiece;
class QGraphicsView;
enum class VPHandleCorner : int
{
Invalid = 0,
TopLeft = 1,
TopRight = 2,
BottomRight = 3,
BottomLeft = 4
};
enum class VPHandleCornerType
{
TopLeft,
TopRight,
BottomRight,
BottomLeft
};
class VPGraphicsTransformationOrigin : public QGraphicsObject class VPGraphicsTransformationOrigin : public QGraphicsObject
{ {
Q_OBJECT Q_OBJECT // NOLINT
public: public:
explicit VPGraphicsTransformationOrigin(const VPLayoutPtr &layout, QGraphicsItem * parent = nullptr); explicit VPGraphicsTransformationOrigin(const VPLayoutPtr &layout, QGraphicsItem * parent = nullptr);
virtual int type() const override {return Type;} auto type() const -> int override {return Type;}
enum { Type = UserType + static_cast<int>(PGraphicsItem::TransformationOrigin)}; enum { Type = UserType + static_cast<int>(PGraphicsItem::TransformationOrigin)};
public slots: public slots:
@ -64,7 +86,7 @@ protected:
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
private: private:
Q_DISABLE_COPY(VPGraphicsTransformationOrigin) Q_DISABLE_COPY_MOVE(VPGraphicsTransformationOrigin) // NOLINT
bool m_originVisible{true}; bool m_originVisible{true};
VPLayoutWeakPtr m_layout{}; VPLayoutWeakPtr m_layout{};
@ -78,11 +100,11 @@ private:
class VPGraphicsPieceControls : public QGraphicsObject class VPGraphicsPieceControls : public QGraphicsObject
{ {
Q_OBJECT Q_OBJECT // NOLINT
public: public:
explicit VPGraphicsPieceControls(const VPLayoutPtr &layout, QGraphicsItem * parent = nullptr); explicit VPGraphicsPieceControls(const VPLayoutPtr &layout, QGraphicsItem * parent = nullptr);
virtual int type() const override {return Type;} auto type() const -> int override {return Type;}
enum { Type = UserType + static_cast<int>(PGraphicsItem::Handles)}; enum { Type = UserType + static_cast<int>(PGraphicsItem::Handles)};
void SetIgnorePieceTransformation(bool newIgnorePieceTransformation); void SetIgnorePieceTransformation(bool newIgnorePieceTransformation);
@ -103,36 +125,55 @@ protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override;
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
private: private:
Q_DISABLE_COPY(VPGraphicsPieceControls) Q_DISABLE_COPY_MOVE(VPGraphicsPieceControls) // NOLINT
QRectF m_pieceRect{}; QRectF m_pieceRect{};
QPointF m_rotationStartPoint{}; QPointF m_rotationStartPoint{};
qreal m_rotationSum{0}; qreal m_rotationSum{0};
bool m_controlsVisible{true}; bool m_controlsVisible{false};
VPLayoutWeakPtr m_layout{}; VPLayoutWeakPtr m_layout{};
int m_handleCorner{0}; VPHandleCorner m_handleCorner{VPHandleCorner::Invalid};
VPTransformationOrigon m_savedOrigin{}; VPTransformationOrigon m_savedOrigin{};
bool m_originSaved{false}; bool m_originSaved{false};
bool allowChangeMerge{false}; bool allowChangeMerge{false};
QList<VPPiecePtr> m_selectedPieces{}; QList<VPPiecePtr> m_selectedPieces{};
bool m_ignorePieceTransformation{false}; bool m_ignorePieceTransformation{false};
auto TopLeftControl(QPainter *painter = nullptr) const -> QPainterPath; QMap<VPHandleCornerType, QPixmap> m_handlePixmaps{};
auto TopRightControl(QPainter *painter = nullptr) const -> QPainterPath; QMap<VPHandleCornerType, QPixmap> m_handleHoverPixmaps{};
auto BottomLeftControl(QPainter *painter = nullptr) const -> QPainterPath; QMap<VPHandleCornerType, QPainterPath> m_handlePaths{};
auto BottomRightControl(QPainter *painter = nullptr) const -> QPainterPath;
void InitPixmaps();
auto TopLeftHandlerPosition() const -> QPointF;
auto TopRightHandlerPosition() const -> QPointF;
auto BottomRightHandlerPosition() const -> QPointF;
auto BottomLeftHandlerPosition() const -> QPointF;
auto ControllerPath(VPHandleCornerType type, QPointF pos) const -> QPainterPath;
auto TopLeftControl() const -> QPainterPath;
auto TopRightControl() const -> QPainterPath;
auto BottomRightControl() const -> QPainterPath;
auto BottomLeftControl() const -> QPainterPath;
auto Handles() const -> QPainterPath; auto Handles() const -> QPainterPath;
auto Controller(const QTransform &t, QPainter *painter = nullptr) const -> QPainterPath;
auto ControllersRect() const -> QRectF; auto ControllersRect() const -> QRectF;
auto ArrowPath() const -> QPainterPath; auto SelectedHandleCorner(const QPointF &pos) const -> VPHandleCorner;
auto SelectedHandleCorner(const QPointF &pos) const -> int; auto HandlerPixmap(bool hover, VPHandleCornerType type) const -> QPixmap;
auto SelectedPieces() const -> QList<VPPiecePtr>; auto SelectedPieces() const -> QList<VPPiecePtr>;
static auto PiecesBoundingRect(const QList<VPPiecePtr> &selectedPieces) -> QRectF; static auto PiecesBoundingRect(const QList<VPPiecePtr> &selectedPieces) -> QRectF;
auto ItemView() -> QGraphicsView *;
void UpdateCursor(VPHandleCorner corner);
}; };
#endif // VPGRAPHICSPIECECONTROLS_H #endif // VPGRAPHICSPIECECONTROLS_H

View File

@ -474,25 +474,6 @@ void VPMainGraphicsView::RestoreOrigin() const
} }
} }
//---------------------------------------------------------------------------------------------------------------------
void VPMainGraphicsView::on_ItemClicked(QGraphicsItem *item)
{
if (item == nullptr || (item->type() != VPGraphicsPiece::Type &&
item->type() != VPGraphicsPieceControls::Type &&
item->type() != VPGraphicsTransformationOrigin::Type))
{
VPLayoutPtr layout = m_layout.toStrongRef();
if (not layout.isNull())
{
VPSheetPtr sheet = layout->GetFocusedSheet();
if (not sheet.isNull())
{
sheet->ClearSelection();
}
}
}
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VPMainGraphicsView::on_SceneMouseMove(const QPointF &scenePos) void VPMainGraphicsView::on_SceneMouseMove(const QPointF &scenePos)
{ {
@ -657,8 +638,6 @@ void VPMainGraphicsView::SwitchScene(const VPSheetPtr &sheet)
{ {
VMainGraphicsScene *scene = sheet->SceneData()->Scene(); VMainGraphicsScene *scene = sheet->SceneData()->Scene();
setScene(scene); setScene(scene);
connect(scene, &VMainGraphicsScene::ItemByMousePress, this, &VPMainGraphicsView::on_ItemClicked,
Qt::UniqueConnection);
connect(scene, &VMainGraphicsScene::mouseMove, this, &VPMainGraphicsView::on_SceneMouseMove, connect(scene, &VMainGraphicsScene::mouseMove, this, &VPMainGraphicsView::on_SceneMouseMove,
Qt::UniqueConnection); Qt::UniqueConnection);
} }

View File

@ -88,7 +88,6 @@ protected:
private slots: private slots:
void RestoreOrigin() const; void RestoreOrigin() const;
void on_ItemClicked(QGraphicsItem* item);
void on_SceneMouseMove(const QPointF &scenePos); void on_SceneMouseMove(const QPointF &scenePos);
private: private:

View File

@ -45,25 +45,8 @@
#include "../vmisc/vmath.h" #include "../vmisc/vmath.h"
#include "../vwidgets/vmaingraphicsview.h" #include "../vwidgets/vmaingraphicsview.h"
extern auto qt_regionToPath(const QRegion &region) -> QPainterPath;
namespace namespace
{ {
//---------------------------------------------------------------------------------------------------------------------
auto PixmapToPainterPath(const QPixmap &pixmap) -> QPainterPath
{
if (not pixmap.isNull())
{
QBitmap mask = pixmap.mask();
if (not mask.isNull())
{
return qt_regionToPath(QRegion(mask));
}
}
return {};
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto RectTopPoint(const QRectF &rect) -> QPointF auto RectTopPoint(const QRectF &rect) -> QPointF
{ {
@ -466,68 +449,21 @@ void VBackgroundImageControls::mouseReleaseEvent(QGraphicsSceneMouseEvent *event
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageControls::hoverEnterEvent(QGraphicsSceneHoverEvent *event) void VBackgroundImageControls::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{ {
m_handleCornerHover = SelectedHandleCorner(event->pos()); UpdateCursor(SelectedHandleCorner(event->pos()));
if (m_handleCornerHover != BIHandleCorner::Invalid)
{
if (not m_image.Hold())
{
SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1);
}
else
{
setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor());
}
}
else
{
setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor());
}
QGraphicsObject::hoverEnterEvent(event); QGraphicsObject::hoverEnterEvent(event);
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageControls::hoverMoveEvent(QGraphicsSceneHoverEvent *event) void VBackgroundImageControls::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{ {
m_handleCornerHover = SelectedHandleCorner(event->pos()); UpdateCursor(SelectedHandleCorner(event->pos()));
if (m_handleCornerHover != BIHandleCorner::Invalid)
{
if (not m_image.Hold())
{
SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1);
}
else
{
setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor());
}
}
else
{
setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor());
}
QGraphicsObject::hoverMoveEvent(event); QGraphicsObject::hoverMoveEvent(event);
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageControls::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) void VBackgroundImageControls::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{ {
m_handleCornerHover = BIHandleCorner::Invalid; UpdateCursor(BIHandleCorner::Invalid);
if (SelectedHandleCorner(event->pos()) != BIHandleCorner::Invalid)
{
if (not m_image.Hold())
{
SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1);
}
else
{
setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor());
}
}
else
{
setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor());
}
QGraphicsObject::hoverLeaveEvent(event); QGraphicsObject::hoverLeaveEvent(event);
} }
@ -1894,3 +1830,25 @@ void VBackgroundImageControls::RotateImage(QGraphicsSceneMouseEvent *event)
m_allowChangeMerge = true; m_allowChangeMerge = true;
} }
} }
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageControls::UpdateCursor(BIHandleCorner corner)
{
m_handleCornerHover = corner;
if (m_handleCornerHover != BIHandleCorner::Invalid)
{
if (not m_image.Hold())
{
SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1);
}
else
{
setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor());
}
}
else
{
setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor());
}
}

View File

@ -70,7 +70,7 @@ enum class BIHandleCornerType
class VBackgroundImageControls : public QGraphicsObject class VBackgroundImageControls : public QGraphicsObject
{ {
Q_OBJECT Q_OBJECT // NOLINT
public: public:
explicit VBackgroundImageControls(VAbstractPattern *doc, QGraphicsItem * parent = nullptr); explicit VBackgroundImageControls(VAbstractPattern *doc, QGraphicsItem * parent = nullptr);
~VBackgroundImageControls() override = default; ~VBackgroundImageControls() override = default;
@ -104,7 +104,7 @@ private slots:
void ScreenChanged(); void ScreenChanged();
private: private:
Q_DISABLE_COPY_MOVE(VBackgroundImageControls) Q_DISABLE_COPY_MOVE(VBackgroundImageControls) // NOLINT
QUuid m_id{}; QUuid m_id{};
VAbstractPattern *m_doc; VAbstractPattern *m_doc;
@ -180,6 +180,8 @@ private:
void ScaleImage(QGraphicsSceneMouseEvent * event); void ScaleImage(QGraphicsSceneMouseEvent * event);
void RotateImage(QGraphicsSceneMouseEvent * event); void RotateImage(QGraphicsSceneMouseEvent * event);
void UpdateCursor(BIHandleCorner corner);
}; };
#endif // VBACKGROUNDIMAGECONTROLS_H #endif // VBACKGROUNDIMAGECONTROLS_H

View File

@ -31,6 +31,7 @@
#include "../vmisc/vabstractapplication.h" #include "../vmisc/vabstractapplication.h"
#include "../vmisc/compatibility.h" #include "../vmisc/compatibility.h"
#include <QBitmap>
#include <QGraphicsItem> #include <QGraphicsItem>
#include <QGraphicsScene> #include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent> #include <QGraphicsSceneMouseEvent>
@ -38,6 +39,8 @@
const qreal minVisibleFontSize = 5; const qreal minVisibleFontSize = 5;
extern auto qt_regionToPath(const QRegion &region) -> QPainterPath;
inline qreal DefPointRadiusPixel() inline qreal DefPointRadiusPixel()
{ {
return (VAbstractApplication::VApp()->Settings()->GetLineWidth() + 0.8) / 25.4 * PrintDPI; return (VAbstractApplication::VApp()->Settings()->GetLineWidth() + 0.8) / 25.4 * PrintDPI;
@ -140,6 +143,21 @@ QPainterPath ItemShapeFromPath(const QPainterPath &path, const QPen &pen)
return p; return p;
} }
//---------------------------------------------------------------------------------------------------------------------
auto PixmapToPainterPath(const QPixmap &pixmap) -> QPainterPath
{
if (not pixmap.isNull())
{
QBitmap mask = pixmap.mask();
if (not mask.isNull())
{
return qt_regionToPath(QRegion(mask));
}
}
return {};
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void GraphicsItemHighlightSelected(const QRectF &boundingRect, qreal itemPenWidth, QPainter *painter, void GraphicsItemHighlightSelected(const QRectF &boundingRect, qreal itemPenWidth, QPainter *painter,
const QStyleOptionGraphicsItem *option) const QStyleOptionGraphicsItem *option)

View File

@ -57,6 +57,8 @@ qreal ScaleWidth(qreal width, qreal scale);
QPainterPath ItemShapeFromPath(const QPainterPath &path, const QPen &pen); QPainterPath ItemShapeFromPath(const QPainterPath &path, const QPen &pen);
auto PixmapToPainterPath(const QPixmap &pixmap) -> QPainterPath;
void GraphicsItemHighlightSelected(const QRectF &boundingRect, qreal itemPenWidth, QPainter *painter, void GraphicsItemHighlightSelected(const QRectF &boundingRect, qreal itemPenWidth, QPainter *painter,
const QStyleOptionGraphicsItem *option); const QStyleOptionGraphicsItem *option);

View File

@ -40,11 +40,11 @@
#include <QStringData> #include <QStringData>
#include <QStringDataPtr> #include <QStringDataPtr>
#include <Qt> #include <Qt>
#include <QGraphicsView>
#include "global.h" #include "global.h"
#include "../vmisc/vabstractapplication.h" #include "../vmisc/vabstractapplication.h"
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
/** /**
* @brief VMainGraphicsScene default constructor. * @brief VMainGraphicsScene default constructor.
@ -95,11 +95,17 @@ void VMainGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick) if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
{ {
emit MouseLeftPressed(); emit MouseLeftPressed();
QTransform deviceTransform;
auto *view = qobject_cast<QGraphicsView *>(event->widget());
if (view != nullptr)
{
deviceTransform = view->transform();
}
emit ItemByMousePress(itemAt(event->scenePos(), deviceTransform));
} }
QGraphicsScene::mousePressEvent(event); QGraphicsScene::mousePressEvent(event);
emit ItemByMousePress(itemAt(event->scenePos(), {}));
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -108,7 +114,14 @@ void VMainGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick) if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
{ {
emit MouseLeftReleased(); emit MouseLeftReleased();
emit ItemByMouseRelease(itemAt(event->scenePos(), {}));
QTransform deviceTransform;
auto *view = qobject_cast<QGraphicsView *>(event->widget());
if (view != nullptr)
{
deviceTransform = view->transform();
}
emit ItemByMouseRelease(itemAt(event->scenePos(), deviceTransform));
} }
QGraphicsScene::mouseReleaseEvent(event); QGraphicsScene::mouseReleaseEvent(event);
} }