From b75292c3416041edac6b1aed37774db9b5ac7ee7 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Wed, 9 Feb 2022 15:31:34 +0200 Subject: [PATCH] Improve Puzzle's piece rotation handlers. --- src/app/puzzle/layout/vpsheet.cpp | 1 - .../puzzle/scene/vpgraphicspiececontrols.cpp | 555 ++++++++++-------- .../puzzle/scene/vpgraphicspiececontrols.h | 75 ++- src/app/puzzle/scene/vpmaingraphicsview.cpp | 21 - src/app/puzzle/scene/vpmaingraphicsview.h | 1 - .../vbackgroundimagecontrols.cpp | 92 +-- .../vbackgroundimagecontrols.h | 6 +- src/libs/vwidgets/global.cpp | 18 + src/libs/vwidgets/global.h | 2 + src/libs/vwidgets/vmaingraphicsscene.cpp | 21 +- 10 files changed, 429 insertions(+), 363 deletions(-) diff --git a/src/app/puzzle/layout/vpsheet.cpp b/src/app/puzzle/layout/vpsheet.cpp index 2fc8119ab..2e2d1a5b1 100644 --- a/src/app/puzzle/layout/vpsheet.cpp +++ b/src/app/puzzle/layout/vpsheet.cpp @@ -54,7 +54,6 @@ VPSheetSceneData::VPSheetSceneData(const VPLayoutPtr &layout, const QUuid &sheet m_scene->addItem(m_graphicsTileGrid); m_rotationControls = new VPGraphicsPieceControls(layout); - m_rotationControls->setVisible(false); m_scene->addItem(m_rotationControls); m_rotationOrigin = new VPGraphicsTransformationOrigin(layout); diff --git a/src/app/puzzle/scene/vpgraphicspiececontrols.cpp b/src/app/puzzle/scene/vpgraphicspiececontrols.cpp index 5404a606a..0f787f6cf 100644 --- a/src/app/puzzle/scene/vpgraphicspiececontrols.cpp +++ b/src/app/puzzle/scene/vpgraphicspiececontrols.cpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include "../vmisc/compatibility.h" #include "../vwidgets/global.h" @@ -40,20 +42,13 @@ #include "../layout/vppiece.h" #include "../undocommands/vpundopiecerotate.h" #include "../undocommands/vpundooriginmove.h" +#include "qgraphicsscene.h" +#include "qgraphicsview.h" +#include "qnamespace.h" #include "vpgraphicspiece.h" 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; const qreal centerRadius1 = 5; @@ -62,15 +57,6 @@ const qreal centerRadius2 = 10; const QColor defaultColor = Qt::black; 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 { SCASSERT(layout != nullptr) @@ -310,10 +296,12 @@ VPGraphicsPieceControls::VPGraphicsPieceControls(const VPLayoutPtr &layout, QGra m_layout(layout) { SCASSERT(m_layout != nullptr) - QPixmap cursor_pixmap = QIcon("://puzzleicon/svg/cursor_rotate.svg").pixmap(QSize(32,32)); - setCursor(QCursor(cursor_pixmap, 16, 16)); - setZValue(1); + setCursor(QCursor(Qt::OpenHandCursor)); + setZValue(100); + setFlag(QGraphicsItem::ItemIgnoresTransformations); setAcceptHoverEvents(true); + + InitPixmaps(); } //--------------------------------------------------------------------------------------------------------------------- @@ -326,7 +314,7 @@ void VPGraphicsPieceControls::on_UpdateControls() m_selectedPieces = SelectedPieces(); m_pieceRect = PiecesBoundingRect(m_selectedPieces); - setVisible(not m_pieceRect.isNull()); + m_controlsVisible = not m_pieceRect.isNull(); if (not m_pieceRect.isNull()) { @@ -361,8 +349,20 @@ void VPGraphicsPieceControls::on_HideHandles(bool hide) //--------------------------------------------------------------------------------------------------------------------- auto VPGraphicsPieceControls::boundingRect() const -> QRectF { - constexpr qreal halfPenWidth = penWidth/2.; - return Handles().boundingRect().adjusted(-halfPenWidth, -halfPenWidth, halfPenWidth, halfPenWidth); + QRectF boundingRect; + + 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(option); - const qreal scale = SceneScale(scene()); - - QPen pen(defaultColor, penWidth/scale, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); - - painter->setPen(pen); - if (m_controlsVisible) { - TopLeftControl(painter); - TopRightControl(painter); - BottomLeftControl(painter); - BottomRightControl(painter); + painter->drawPixmap(TopLeftHandlerPosition(), + HandlerPixmap(m_handleCorner == VPHandleCorner::TopLeft, + VPHandleCornerType::TopLeft)); + + 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) { - if(event->button() == Qt::LeftButton) + if(event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick) { m_rotationStartPoint = event->scenePos(); m_rotationSum = 0; m_controlsVisible = false; - m_handleCorner = SelectedHandleCorner(event->scenePos()); + m_handleCorner = SelectedHandleCorner(event->pos()); m_ignorePieceTransformation = true; 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 { @@ -413,8 +433,7 @@ void VPGraphicsPieceControls::mousePressEvent(QGraphicsSceneMouseEvent *event) //--------------------------------------------------------------------------------------------------------------------- void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { - if((event->modifiers() & Qt::ShiftModifier) != 0U - && static_cast(m_handleCorner) != HandleCorner::Invalid) + if((event->modifiers() & Qt::ShiftModifier) && m_handleCorner != VPHandleCorner::Invalid) { if (not m_originSaved) { @@ -431,22 +450,22 @@ void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event) VPTransformationOrigon origin; origin.custom = true; - if (static_cast(m_handleCorner) == HandleCorner::TopLeft) - { - origin.origin = m_pieceRect.topLeft(); - } - else if (static_cast(m_handleCorner) == HandleCorner::TopRight) - { - origin.origin = m_pieceRect.topRight(); - } - else if (static_cast(m_handleCorner) == HandleCorner::BottomRight) + if (m_handleCorner == VPHandleCorner::TopLeft) { origin.origin = m_pieceRect.bottomRight(); } - else if (static_cast(m_handleCorner) == HandleCorner::BottomLeft) + else if (m_handleCorner == VPHandleCorner::TopRight) { 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); emit TransformationOriginChanged(); @@ -565,6 +584,19 @@ void VPGraphicsPieceControls::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) m_controlsVisible = true; 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) { VPLayoutPtr layout = m_layout.toStrongRef(); @@ -591,49 +623,152 @@ void VPGraphicsPieceControls::mouseReleaseEvent(QGraphicsSceneMouseEvent *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) { 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 { @@ -647,161 +782,34 @@ auto VPGraphicsPieceControls::Handles() const -> QPainterPath 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 { 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; - QRectF rect = m_pieceRect; - 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.); - } + rect.adjust(- (handler.width() + gap), - (handler.height() + gap), handler.width() + gap, handler.height() + gap); 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 { @@ -836,27 +844,74 @@ auto VPGraphicsPieceControls::PiecesBoundingRect(const QList &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(HandleCorner::BottomRight); + QList views = scene->views(); + if (not views.isEmpty()) + { + return views.at(0); + } } - if (TopRightControl().boundingRect().contains(pos)) - { - return static_cast(HandleCorner::BottomLeft); - } - - if (BottomLeftControl().boundingRect().contains(pos)) - { - return static_cast(HandleCorner::TopRight); - } - - if (BottomRightControl().boundingRect().contains(pos)) - { - return static_cast(HandleCorner::TopLeft); - } - - return static_cast(HandleCorner::Invalid); + return nullptr; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsPieceControls::UpdateCursor(VPHandleCorner corner) +{ + m_handleCorner = corner; + + if (m_handleCorner != VPHandleCorner::Invalid) + { + setCursor(QCursor(Qt::OpenHandCursor)); + } + else + { + QGraphicsView *view = ItemView(); + if (view != nullptr) + { + setCursor(view->viewport()->cursor()); + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPGraphicsPieceControls::SelectedHandleCorner(const QPointF &pos) const -> VPHandleCorner +{ + QMap 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 VPHandleCorner::Invalid; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPGraphicsPieceControls::HandlerPixmap(bool hover, VPHandleCornerType type) const -> QPixmap +{ + return hover ? m_handleHoverPixmaps.value(type) : m_handlePixmaps.value(type); } diff --git a/src/app/puzzle/scene/vpgraphicspiececontrols.h b/src/app/puzzle/scene/vpgraphicspiececontrols.h index 985681cf6..1959575a1 100644 --- a/src/app/puzzle/scene/vpgraphicspiececontrols.h +++ b/src/app/puzzle/scene/vpgraphicspiececontrols.h @@ -34,16 +34,38 @@ #include "scenedef.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 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 { - Q_OBJECT + Q_OBJECT // NOLINT public: 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(PGraphicsItem::TransformationOrigin)}; public slots: @@ -64,7 +86,7 @@ protected: void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; private: - Q_DISABLE_COPY(VPGraphicsTransformationOrigin) + Q_DISABLE_COPY_MOVE(VPGraphicsTransformationOrigin) // NOLINT bool m_originVisible{true}; VPLayoutWeakPtr m_layout{}; @@ -78,11 +100,11 @@ private: class VPGraphicsPieceControls : public QGraphicsObject { - Q_OBJECT + Q_OBJECT // NOLINT public: 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(PGraphicsItem::Handles)}; void SetIgnorePieceTransformation(bool newIgnorePieceTransformation); @@ -100,39 +122,58 @@ protected: auto shape() const -> QPainterPath override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; - void mousePressEvent(QGraphicsSceneMouseEvent * event) override; - void mouseMoveEvent(QGraphicsSceneMouseEvent * event) override; + void mousePressEvent(QGraphicsSceneMouseEvent *event) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; + void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override; + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; private: - Q_DISABLE_COPY(VPGraphicsPieceControls) + Q_DISABLE_COPY_MOVE(VPGraphicsPieceControls) // NOLINT + QRectF m_pieceRect{}; QPointF m_rotationStartPoint{}; qreal m_rotationSum{0}; - bool m_controlsVisible{true}; + bool m_controlsVisible{false}; VPLayoutWeakPtr m_layout{}; - int m_handleCorner{0}; + VPHandleCorner m_handleCorner{VPHandleCorner::Invalid}; VPTransformationOrigon m_savedOrigin{}; bool m_originSaved{false}; bool allowChangeMerge{false}; QList m_selectedPieces{}; bool m_ignorePieceTransformation{false}; - auto TopLeftControl(QPainter *painter = nullptr) const -> QPainterPath; - auto TopRightControl(QPainter *painter = nullptr) const -> QPainterPath; - auto BottomLeftControl(QPainter *painter = nullptr) const -> QPainterPath; - auto BottomRightControl(QPainter *painter = nullptr) const -> QPainterPath; + QMap m_handlePixmaps{}; + QMap m_handleHoverPixmaps{}; + QMap m_handlePaths{}; + + 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 Controller(const QTransform &t, QPainter *painter = nullptr) const -> QPainterPath; 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; static auto PiecesBoundingRect(const QList &selectedPieces) -> QRectF; + + auto ItemView() -> QGraphicsView *; + + void UpdateCursor(VPHandleCorner corner); }; #endif // VPGRAPHICSPIECECONTROLS_H diff --git a/src/app/puzzle/scene/vpmaingraphicsview.cpp b/src/app/puzzle/scene/vpmaingraphicsview.cpp index 93cce9622..31c28824c 100644 --- a/src/app/puzzle/scene/vpmaingraphicsview.cpp +++ b/src/app/puzzle/scene/vpmaingraphicsview.cpp @@ -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) { @@ -657,8 +638,6 @@ void VPMainGraphicsView::SwitchScene(const VPSheetPtr &sheet) { VMainGraphicsScene *scene = sheet->SceneData()->Scene(); setScene(scene); - connect(scene, &VMainGraphicsScene::ItemByMousePress, this, &VPMainGraphicsView::on_ItemClicked, - Qt::UniqueConnection); connect(scene, &VMainGraphicsScene::mouseMove, this, &VPMainGraphicsView::on_SceneMouseMove, Qt::UniqueConnection); } diff --git a/src/app/puzzle/scene/vpmaingraphicsview.h b/src/app/puzzle/scene/vpmaingraphicsview.h index 792cd5b39..3fe8d9f3b 100644 --- a/src/app/puzzle/scene/vpmaingraphicsview.h +++ b/src/app/puzzle/scene/vpmaingraphicsview.h @@ -88,7 +88,6 @@ protected: private slots: void RestoreOrigin() const; - void on_ItemClicked(QGraphicsItem* item); void on_SceneMouseMove(const QPointF &scenePos); private: diff --git a/src/libs/vtools/tools/backgroundimage/vbackgroundimagecontrols.cpp b/src/libs/vtools/tools/backgroundimage/vbackgroundimagecontrols.cpp index b1cc59e9c..96ab447ae 100644 --- a/src/libs/vtools/tools/backgroundimage/vbackgroundimagecontrols.cpp +++ b/src/libs/vtools/tools/backgroundimage/vbackgroundimagecontrols.cpp @@ -45,25 +45,8 @@ #include "../vmisc/vmath.h" #include "../vwidgets/vmaingraphicsview.h" -extern auto qt_regionToPath(const QRegion ®ion) -> QPainterPath; - 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 { @@ -466,68 +449,21 @@ void VBackgroundImageControls::mouseReleaseEvent(QGraphicsSceneMouseEvent *event //--------------------------------------------------------------------------------------------------------------------- void VBackgroundImageControls::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { - m_handleCornerHover = 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()); - } + UpdateCursor(SelectedHandleCorner(event->pos())); QGraphicsObject::hoverEnterEvent(event); } //--------------------------------------------------------------------------------------------------------------------- void VBackgroundImageControls::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { - m_handleCornerHover = 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()); - } + UpdateCursor(SelectedHandleCorner(event->pos())); QGraphicsObject::hoverMoveEvent(event); } //--------------------------------------------------------------------------------------------------------------------- void VBackgroundImageControls::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { - m_handleCornerHover = 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()); - } + UpdateCursor(BIHandleCorner::Invalid); QGraphicsObject::hoverLeaveEvent(event); } @@ -1894,3 +1830,25 @@ void VBackgroundImageControls::RotateImage(QGraphicsSceneMouseEvent *event) 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()); + } +} diff --git a/src/libs/vtools/tools/backgroundimage/vbackgroundimagecontrols.h b/src/libs/vtools/tools/backgroundimage/vbackgroundimagecontrols.h index 7dda267af..89cac03bc 100644 --- a/src/libs/vtools/tools/backgroundimage/vbackgroundimagecontrols.h +++ b/src/libs/vtools/tools/backgroundimage/vbackgroundimagecontrols.h @@ -70,7 +70,7 @@ enum class BIHandleCornerType class VBackgroundImageControls : public QGraphicsObject { - Q_OBJECT + Q_OBJECT // NOLINT public: explicit VBackgroundImageControls(VAbstractPattern *doc, QGraphicsItem * parent = nullptr); ~VBackgroundImageControls() override = default; @@ -104,7 +104,7 @@ private slots: void ScreenChanged(); private: - Q_DISABLE_COPY_MOVE(VBackgroundImageControls) + Q_DISABLE_COPY_MOVE(VBackgroundImageControls) // NOLINT QUuid m_id{}; VAbstractPattern *m_doc; @@ -180,6 +180,8 @@ private: void ScaleImage(QGraphicsSceneMouseEvent * event); void RotateImage(QGraphicsSceneMouseEvent * event); + + void UpdateCursor(BIHandleCorner corner); }; #endif // VBACKGROUNDIMAGECONTROLS_H diff --git a/src/libs/vwidgets/global.cpp b/src/libs/vwidgets/global.cpp index 100fe95cd..15a5122c6 100644 --- a/src/libs/vwidgets/global.cpp +++ b/src/libs/vwidgets/global.cpp @@ -31,6 +31,7 @@ #include "../vmisc/vabstractapplication.h" #include "../vmisc/compatibility.h" +#include #include #include #include @@ -38,6 +39,8 @@ const qreal minVisibleFontSize = 5; +extern auto qt_regionToPath(const QRegion ®ion) -> QPainterPath; + inline qreal DefPointRadiusPixel() { return (VAbstractApplication::VApp()->Settings()->GetLineWidth() + 0.8) / 25.4 * PrintDPI; @@ -140,6 +143,21 @@ QPainterPath ItemShapeFromPath(const QPainterPath &path, const QPen &pen) 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, const QStyleOptionGraphicsItem *option) diff --git a/src/libs/vwidgets/global.h b/src/libs/vwidgets/global.h index 38ef48e32..2f0c0aba0 100644 --- a/src/libs/vwidgets/global.h +++ b/src/libs/vwidgets/global.h @@ -57,6 +57,8 @@ qreal ScaleWidth(qreal width, qreal scale); QPainterPath ItemShapeFromPath(const QPainterPath &path, const QPen &pen); +auto PixmapToPainterPath(const QPixmap &pixmap) -> QPainterPath; + void GraphicsItemHighlightSelected(const QRectF &boundingRect, qreal itemPenWidth, QPainter *painter, const QStyleOptionGraphicsItem *option); diff --git a/src/libs/vwidgets/vmaingraphicsscene.cpp b/src/libs/vwidgets/vmaingraphicsscene.cpp index 95ba2de12..a05a59370 100644 --- a/src/libs/vwidgets/vmaingraphicsscene.cpp +++ b/src/libs/vwidgets/vmaingraphicsscene.cpp @@ -40,11 +40,11 @@ #include #include #include +#include #include "global.h" #include "../vmisc/vabstractapplication.h" - //--------------------------------------------------------------------------------------------------------------------- /** * @brief VMainGraphicsScene default constructor. @@ -95,11 +95,17 @@ void VMainGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick) { emit MouseLeftPressed(); + + QTransform deviceTransform; + auto *view = qobject_cast(event->widget()); + if (view != nullptr) + { + deviceTransform = view->transform(); + } + emit ItemByMousePress(itemAt(event->scenePos(), deviceTransform)); } 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) { emit MouseLeftReleased(); - emit ItemByMouseRelease(itemAt(event->scenePos(), {})); + + QTransform deviceTransform; + auto *view = qobject_cast(event->widget()); + if (view != nullptr) + { + deviceTransform = view->transform(); + } + emit ItemByMouseRelease(itemAt(event->scenePos(), deviceTransform)); } QGraphicsScene::mouseReleaseEvent(event); }