From a9d6fae27d3f1d46ca2dc020d34eaef539322522 Mon Sep 17 00:00:00 2001 From: Ronan Le Tiec Date: Sat, 9 May 2020 14:45:36 +0200 Subject: [PATCH] optimization angle / rotation --- src/app/puzzle/puzzlemainwindow.cpp | 13 +++ src/app/puzzle/puzzlemainwindow.h | 5 + src/app/puzzle/share/resources/puzzleicon.qrc | 1 + .../puzzleicon/64x64/cursorRotate.png | Bin 0 -> 1635 bytes .../puzzleicon/64x64/cursorRotate@2x.png | Bin 0 -> 2938 bytes .../puzzleicon/svg/cursor_rotate.svg | 67 +++++++++++++ src/app/puzzle/vpuzzlegraphicspiece.cpp | 94 ++++++++++++++++-- src/app/puzzle/vpuzzlegraphicspiece.h | 6 ++ src/app/puzzle/vpuzzlepiece.cpp | 37 +++---- 9 files changed, 197 insertions(+), 26 deletions(-) create mode 100644 src/app/puzzle/share/resources/puzzleicon/64x64/cursorRotate.png create mode 100644 src/app/puzzle/share/resources/puzzleicon/64x64/cursorRotate@2x.png create mode 100644 src/app/puzzle/share/resources/puzzleicon/svg/cursor_rotate.svg diff --git a/src/app/puzzle/puzzlemainwindow.cpp b/src/app/puzzle/puzzlemainwindow.cpp index 83375cba9..b76bcb9b0 100644 --- a/src/app/puzzle/puzzlemainwindow.cpp +++ b/src/app/puzzle/puzzlemainwindow.cpp @@ -200,6 +200,7 @@ VPuzzlePiece* PuzzleMainWindow::CreatePiece(const VLayoutPiece &rawPiece) // connect(piece, &VPuzzlePiece::SelectionChanged, this, &PuzzleMainWindow::on_PieceSelectionChanged); connect(piece, &VPuzzlePiece::PositionChanged, this, &PuzzleMainWindow::on_PiecePositionChanged); + connect(piece, &VPuzzlePiece::RotationChanged, this, &PuzzleMainWindow::on_PieceRotationChanged); return piece; @@ -892,3 +893,15 @@ void PuzzleMainWindow::on_PiecePositionChanged() SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceBoxPositionY, UnitConvertor(pos.y(), Unit::Px, m_layout->GetUnit())); } } + +//--------------------------------------------------------------------------------------------------------------------- +void PuzzleMainWindow::on_PieceRotationChanged() +{ + if(m_selectedPieces.count() == 1) + { + VPuzzlePiece *piece = m_selectedPieces.first(); + qreal angle = piece->GetRotation(); + + SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceAngle, angle); + } +} diff --git a/src/app/puzzle/puzzlemainwindow.h b/src/app/puzzle/puzzlemainwindow.h index 8d5015a4e..4ffa3f29c 100644 --- a/src/app/puzzle/puzzlemainwindow.h +++ b/src/app/puzzle/puzzlemainwindow.h @@ -373,6 +373,11 @@ private slots: */ void on_PiecePositionChanged(); + /** + * @brief on_PieceRotationChanged When the current piece rotation has changed + */ + void on_PieceRotationChanged(); + }; #endif // PUZZLEMAINWINDOW_H diff --git a/src/app/puzzle/share/resources/puzzleicon.qrc b/src/app/puzzle/share/resources/puzzleicon.qrc index fb33ba546..809e972be 100644 --- a/src/app/puzzle/share/resources/puzzleicon.qrc +++ b/src/app/puzzle/share/resources/puzzleicon.qrc @@ -9,5 +9,6 @@ puzzleicon/64x64/iconPortrait.png puzzleicon/64x64/iconGrainlineVertical.png puzzleicon/64x64/iconGrainlineHorizontal.png + puzzleicon/64x64/cursorRotate.png diff --git a/src/app/puzzle/share/resources/puzzleicon/64x64/cursorRotate.png b/src/app/puzzle/share/resources/puzzleicon/64x64/cursorRotate.png new file mode 100644 index 0000000000000000000000000000000000000000..a9ade2aee24b7949c0e842cd8722883b286671cd GIT binary patch literal 1635 zcmV-p2AuhcP)i|UK~#90)!S)|B~=x`@!#|`bTgWkWf&Y3!sZM{*+dYXPK*nX zu!SWi1Tg9+!+e0SM-u&@F(w2P{Xh_jf*KQzCaj5)Kv)wN*&-njNEjzGA_fL%rn}$k z>7IrU=RK!s>Q-01s(SDFPi{I>Q+4h+r|vy<@44r#(tkGK3>=4zI27x!fcHCpr|}A& zz;k%M^Y8y#PQcCh59Tli9~MD_jZ z>Z~B6xJ7zOEaEM(=cvp@(%zmEpRYl2xp>vS+`uU6Omo|+{$_l$bLr^!m{-hp#Yv*|BQSfjXL8H<^N0-2W${onJoI2d8t6^OyQ`a4md1veYeQ<4?8a>uCFQT zfQiKQIkC$ccDBlnVdJCt1wOOvKX!^J+2zv-!3+32z9m+J-7IhSM5iSjG~cV{4Kq$G zVS7Eim>15PTGDokmDU2@5t-sa^CK|=vX=0OQLs{et!$gYrA=E_kQ-$uaQ+v-$M7%p z9b+wuz?1rN^qbT&{;8!mO-iqu%eJ-}b8t1VUACToU4G-QRG$iM{IN-EO0u8qbIKO3 zTYmEz{9CoDFpKpK8dR2xMPSZ~Q730T@HM?pg=vwP9479T{X$!EQunt>XIJwA->Z2- z2f#Y%m-%4cgA-zhSH=M?e6;~1s&Iqsn6?uauJrI3ijRV}NIwk|`^!(_6v_$yNiio3 zTi_#JNS5w%V&PYa{l!^(p7Ardx<Mwf{ zdWUQ$wDI-IDszmCMM)1FA}YsH=ND7>L@$C5^ii+Q;jW4bkBRb^-MF`+ti$Zt_ot@n z_p5Ypp$|vZmUNz=2$Nz1);(#i;($}d3rZQ^#^2RY6!tfJN?ot-QN{#r?I^W$h1QD$ z_7R6Nc`MgNQI%Fp&BA(N{5ILC=9M^GWQelj$vq|HtP)3CZ(6you%+gjh40|>lFzIY zHA8u8in|NQIS^OiHN^@l+c>kNuC?=Bdvc6<%HEmr?5LF1Yp`$gCgw9Pw!%9#GXi#rCGNaPZQq1V(#0C3sp~U1Axh$}?8xk; zG=4!C+ZHRlt$0=h)hEPTA9@bJ&xH|r72H|v_XE(kF%H4)%KcpK_5tYGI7f?3PLa>! zZwI7fUpNU5$p5L!Zw97aAK8SbWv>)(9iU!)=bPdbX{jTIso1(NtQNV2H$;56Ww7cD hj=gc29!uD(@&VNnLwq?<1%vwmR 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 literal 0 HcmV?d00001 diff --git a/src/app/puzzle/share/resources/puzzleicon/svg/cursor_rotate.svg b/src/app/puzzle/share/resources/puzzleicon/svg/cursor_rotate.svg new file mode 100644 index 000000000..f5b2423cb --- /dev/null +++ b/src/app/puzzle/share/resources/puzzleicon/svg/cursor_rotate.svg @@ -0,0 +1,67 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/app/puzzle/vpuzzlegraphicspiece.cpp b/src/app/puzzle/vpuzzlegraphicspiece.cpp index fb18783f6..3d53423fe 100644 --- a/src/app/puzzle/vpuzzlegraphicspiece.cpp +++ b/src/app/puzzle/vpuzzlegraphicspiece.cpp @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include "vpuzzlepiece.h" #include "vpuzzlelayer.h" @@ -50,7 +52,8 @@ VPuzzleGraphicsPiece::VPuzzleGraphicsPiece(VPuzzlePiece *piece, QGraphicsItem *p m_piece(piece), m_cuttingLine(QPainterPath()), m_seamLine(QPainterPath()), - m_grainline(QPainterPath()) + m_grainline(QPainterPath()), + m_rotationStartPoint(QPointF()) { Init(); } @@ -66,6 +69,7 @@ void VPuzzleGraphicsPiece::Init() { // set some infos setFlags(ItemIsSelectable | ItemIsMovable | ItemSendsGeometryChanges); + setAcceptHoverEvents(true); setCursor(QCursor(Qt::OpenHandCursor)); // initialises the seam line @@ -188,8 +192,50 @@ void VPuzzleGraphicsPiece::mousePressEvent(QGraphicsSceneMouseEvent *event) setSelected(true); } } + + if((event->button() == Qt::LeftButton) && (event->modifiers() & Qt::AltModifier)) + { + m_rotationStartPoint = event->scenePos(); + + QPixmap cursor_pixmap = QPixmap(":/cursor_rotate"); + cursor_pixmap = cursor_pixmap.scaledToWidth(32); + QCursor cursor_rotate = QCursor(cursor_pixmap, 16, 16); + + setCursor(cursor_rotate); + } } +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::mouseMoveEvent(QGraphicsSceneMouseEvent * event) +{ + if((event->buttons() == Qt::LeftButton) && (event->modifiers() & Qt::AltModifier)) + { + + QPointF rotationNewPoint = event->scenePos(); + QPointF rotationCenter = sceneBoundingRect().center(); + + // get the angle from the center to the initial click point + qreal init_x = m_rotationStartPoint.x() - rotationCenter.x(); + qreal init_y = m_rotationStartPoint.y() - rotationCenter.y(); + qreal initial_angle = qAtan2(init_y, init_x); + + qreal x = rotationNewPoint.x() - rotationCenter.x(); + qreal y = rotationNewPoint.y() - rotationCenter.y(); + qreal mv_angle = qAtan2(y,x); + + qreal angle = (initial_angle-mv_angle)*180/M_PI; + + setTransformOriginPoint(boundingRect().center()); + setRotation(-(angle+m_piece->GetRotation())); + event->accept(); + } + else + { + QGraphicsItem::mouseMoveEvent(event); + } +} + + //--------------------------------------------------------------------------------------------------------------------- void VPuzzleGraphicsPiece::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { @@ -204,6 +250,36 @@ void VPuzzleGraphicsPiece::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) setCursor(Qt::OpenHandCursor); setSelected(selectionState); + + if(m_piece->GetPosition() != pos()) + { + m_piece->SetPosition(pos()); + } + } + + if((event->button() == Qt::LeftButton) && (event->modifiers() & Qt::AltModifier)) + { + m_piece->SetRotation(-rotation()); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::hoverMoveEvent(QGraphicsSceneHoverEvent *event) +{ + + if(event->modifiers() & Qt::AltModifier) + { + // TODO FIXME: find a more efficient way + + QPixmap cursor_pixmap = QPixmap(":/cursor_rotate"); + cursor_pixmap = cursor_pixmap.scaledToWidth(32); + QCursor cursor_rotate = QCursor(cursor_pixmap, 16, 16); + + setCursor(cursor_rotate); + } + else + { + setCursor(QCursor(Qt::OpenHandCursor)); } } @@ -246,7 +322,7 @@ void VPuzzleGraphicsPiece::on_ActionPieceMovedToLayer() { QAction *act = qobject_cast(sender()); QVariant v = act->data(); - VPuzzleLayer *layer = (VPuzzleLayer *) v.value(); + VPuzzleLayer *layer = v.value(); if(layer != nullptr) { layer->GetLayout()->MovePieceToLayer(m_piece, layer); @@ -277,12 +353,14 @@ void VPuzzleGraphicsPiece::on_PieceRotationChanged() QVariant VPuzzleGraphicsPiece::itemChange(GraphicsItemChange change, const QVariant &value) { if (scene()) { - if(change == ItemPositionHasChanged) - { - blockSignals(true); - m_piece->SetPosition(pos()); - blockSignals(false); - } + + // we do this in the mouseRelease button to avoid updated this property all the time. +// if(change == ItemPositionHasChanged) +// { +// blockSignals(true); +// m_piece->SetPosition(pos()); +// blockSignals(false); +// } if(change == ItemSelectedHasChanged) { diff --git a/src/app/puzzle/vpuzzlegraphicspiece.h b/src/app/puzzle/vpuzzlegraphicspiece.h index 496f55e76..fee04892f 100644 --- a/src/app/puzzle/vpuzzlegraphicspiece.h +++ b/src/app/puzzle/vpuzzlegraphicspiece.h @@ -69,8 +69,11 @@ protected: void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget) override; void mousePressEvent(QGraphicsSceneMouseEvent * event) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent * event) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override; + QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; @@ -89,6 +92,9 @@ private: QPainterPath m_cuttingLine; QPainterPath m_seamLine; QPainterPath m_grainline; + + QPointF m_rotationStartPoint; + }; #endif // VPUZZLEGRAPHICSPIECE_H diff --git a/src/app/puzzle/vpuzzlepiece.cpp b/src/app/puzzle/vpuzzlepiece.cpp index 92a42191f..45e652516 100644 --- a/src/app/puzzle/vpuzzlepiece.cpp +++ b/src/app/puzzle/vpuzzlepiece.cpp @@ -144,27 +144,28 @@ QPointF VPuzzlePiece::GetPosition() //--------------------------------------------------------------------------------------------------------------------- void VPuzzlePiece::SetRotation(qreal angle) { - m_pieceAngle = angle; + // qreal currentAngle = GetRotation(); + // qreal newAngle = angle - currentAngle; - // make sure the angle is [0 <= angle < 360] - while(m_pieceAngle >= 360) + // m_transform.rotate(newAngle); + + if(m_pieceAngle != angle) { - m_pieceAngle -= 360; + m_pieceAngle = angle; + + // make sure the angle is [0 <= angle < 360] + while(m_pieceAngle >= 360) + { + m_pieceAngle -= 360; + } + + while(m_pieceAngle < 0) + { + m_pieceAngle += 360; + } + + emit RotationChanged(); } - - while(m_pieceAngle < 0) - { - m_pieceAngle += 360; - } - - -// qreal currentAngle = GetRotation(); -// qreal newAngle = angle - currentAngle; - -// m_transform.rotate(newAngle); - - - emit RotationChanged(); } //---------------------------------------------------------------------------------------------------------------------