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_rotationControls = new VPGraphicsPieceControls(layout);
m_rotationControls->setVisible(false);
m_scene->addItem(m_rotationControls);
m_rotationOrigin = new VPGraphicsTransformationOrigin(layout);

View file

@ -33,6 +33,8 @@
#include <QIcon>
#include <QPainter>
#include <QtDebug>
#include <QGuiApplication>
#include <QScreen>
#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<HandleCorner>(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<HandleCorner>(m_handleCorner) == HandleCorner::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)
if (m_handleCorner == VPHandleCorner::TopLeft)
{
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();
}
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<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 static_cast<int>(HandleCorner::BottomLeft);
}
if (BottomLeftControl().boundingRect().contains(pos))
{
return static_cast<int>(HandleCorner::TopRight);
}
if (BottomRightControl().boundingRect().contains(pos))
{
return static_cast<int>(HandleCorner::TopLeft);
}
return static_cast<int>(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<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 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 "../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<int>(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<int>(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<VPPiecePtr> 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<VPHandleCornerType, QPixmap> m_handlePixmaps{};
QMap<VPHandleCornerType, QPixmap> m_handleHoverPixmaps{};
QMap<VPHandleCornerType, QPainterPath> 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<VPPiecePtr>;
static auto PiecesBoundingRect(const QList<VPPiecePtr> &selectedPieces) -> QRectF;
auto ItemView() -> QGraphicsView *;
void UpdateCursor(VPHandleCorner corner);
};
#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)
{
@ -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);
}

View file

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

View file

@ -45,25 +45,8 @@
#include "../vmisc/vmath.h"
#include "../vwidgets/vmaingraphicsview.h"
extern auto qt_regionToPath(const QRegion &region) -> 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());
}
}

View file

@ -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

View file

@ -31,6 +31,7 @@
#include "../vmisc/vabstractapplication.h"
#include "../vmisc/compatibility.h"
#include <QBitmap>
#include <QGraphicsItem>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
@ -38,6 +39,8 @@
const qreal minVisibleFontSize = 5;
extern auto qt_regionToPath(const QRegion &region) -> 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)

View file

@ -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);

View file

@ -40,11 +40,11 @@
#include <QStringData>
#include <QStringDataPtr>
#include <Qt>
#include <QGraphicsView>
#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<QGraphicsView *>(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<QGraphicsView *>(event->widget());
if (view != nullptr)
{
deviceTransform = view->transform();
}
emit ItemByMouseRelease(itemAt(event->scenePos(), deviceTransform));
}
QGraphicsScene::mouseReleaseEvent(event);
}