From c4473b0d273631f41853459f876a893ae7c7251e Mon Sep 17 00:00:00 2001 From: Ronan Le Tiec Date: Sun, 14 Mar 2021 14:27:45 +0100 Subject: [PATCH] Add rotation shortcuts and grid placement --- src/app/puzzle/share/resources/puzzleicon.qrc | 8 + .../64x64/iconRotate90Anticlockwise.png | Bin 0 -> 1847 bytes .../64x64/iconRotate90Clockwise.png | Bin 0 -> 1831 bytes .../64x64/iconRotateGrainlineHorizontal.png | Bin 0 -> 1224 bytes .../iconRotateGrainlineHorizontal@2x.png | Bin 0 -> 2389 bytes .../64x64/iconRotateGrainlineVertical.png | Bin 0 -> 1249 bytes .../64x64/iconRotateGrainlineVertical@2x.png | Bin 0 -> 2641 bytes .../svg/icon_rotate_90_anticlockwise.svg | 79 ++++++++++ .../svg/icon_rotate_90_clockwise.svg | 79 ++++++++++ .../svg/icon_rotate_grainline_horizontal.svg | 77 ++++++++++ .../svg/icon_rotate_grainline_vertical.svg | 77 ++++++++++ src/app/puzzle/vpgraphicssheet.cpp | 38 ++++- src/app/puzzle/vpgraphicssheet.h | 6 +- src/app/puzzle/vpmaingraphicsview.cpp | 5 + src/app/puzzle/vpmaingraphicsview.h | 5 + src/app/puzzle/vpmainwindow.cpp | 59 +++++++- src/app/puzzle/vpmainwindow.h | 49 +++++- src/app/puzzle/vpmainwindow.ui | 140 +++++++++++++++++- src/app/puzzle/vppiece.cpp | 25 ++++ src/app/puzzle/vppiece.h | 18 ++- src/app/puzzle/vpsheet.cpp | 61 ++++++++ src/app/puzzle/vpsheet.h | 79 ++++++++++ 22 files changed, 790 insertions(+), 15 deletions(-) create mode 100644 src/app/puzzle/share/resources/puzzleicon/64x64/iconRotate90Anticlockwise.png create mode 100644 src/app/puzzle/share/resources/puzzleicon/64x64/iconRotate90Clockwise.png create mode 100644 src/app/puzzle/share/resources/puzzleicon/64x64/iconRotateGrainlineHorizontal.png create mode 100644 src/app/puzzle/share/resources/puzzleicon/64x64/iconRotateGrainlineHorizontal@2x.png create mode 100644 src/app/puzzle/share/resources/puzzleicon/64x64/iconRotateGrainlineVertical.png create mode 100644 src/app/puzzle/share/resources/puzzleicon/64x64/iconRotateGrainlineVertical@2x.png create mode 100644 src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_90_anticlockwise.svg create mode 100644 src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_90_clockwise.svg create mode 100644 src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_grainline_horizontal.svg create mode 100644 src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_grainline_vertical.svg diff --git a/src/app/puzzle/share/resources/puzzleicon.qrc b/src/app/puzzle/share/resources/puzzleicon.qrc index cf7527f52..33d297039 100644 --- a/src/app/puzzle/share/resources/puzzleicon.qrc +++ b/src/app/puzzle/share/resources/puzzleicon.qrc @@ -16,5 +16,13 @@ puzzleicon/16x16/roll.png puzzleicon/16x16/template.png puzzleicon/svg/cursor_rotate.svg + puzzleicon/svg/icon_rotate_90_anticlockwise.svg + puzzleicon/svg/icon_rotate_90_clockwise.svg + puzzleicon/64x64/iconRotate90Anticlockwise.png + puzzleicon/64x64/iconRotate90Clockwise.png + puzzleicon/64x64/iconRotateGrainlineHorizontal.png + puzzleicon/64x64/iconRotateGrainlineVertical.png + puzzleicon/svg/icon_rotate_grainline_horizontal.svg + puzzleicon/svg/icon_rotate_grainline_vertical.svg diff --git a/src/app/puzzle/share/resources/puzzleicon/64x64/iconRotate90Anticlockwise.png b/src/app/puzzle/share/resources/puzzleicon/64x64/iconRotate90Anticlockwise.png new file mode 100644 index 0000000000000000000000000000000000000000..278265d82e5e288269d3f4deb6415cf9da9910c1 GIT binary patch literal 1847 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 LNkvXXu0mjfk?lX2 literal 0 HcmV?d00001 diff --git a/src/app/puzzle/share/resources/puzzleicon/64x64/iconRotateGrainlineVertical@2x.png b/src/app/puzzle/share/resources/puzzleicon/64x64/iconRotateGrainlineVertical@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e4af4320d5ccc7ca42c98b99fedb9c753a597377 GIT binary patch literal 2641 zcmV-X3a<5uP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H13EoLW zK~#90?VWp!T}2(oKX=<@AEjMdXyu_&3?&xD3YJ2k2n(nQ{Lv<+F+PF@wLXY~5g*Wq zmMByuCSt*0d{G4i)Bqw1KB}cH8fgu!6)03GU0U0MO=$~#?Ja-&_U4{FJ#+5NoX4Dd zXFkcK-Mwe$e19{)d7R(O+*70T=mDkzCq>dkU;vl^j32qC!7kunwH}Dd0 z$Z>iGxD}WS^c85g*Bk|02K)v%fcr{UrB_BY&I67pq$E7!bl^6mU|m{*3D?ws$-ptlW8_Jf&J$)dNs9r!od3vxg3Ti`=T>n)mTz!#8sKpu|pOJGt7x+_B$a5dRm z{YK!6lvC*{P6cj3qK8>**#ulzvUVqo2Oc0>VXXt+M{&_U8zutR0{Ew&PAe;rseVkGQn&MrXnk0rbhmN&gk-6 zaXhdZ^YZy4ZBRaaz~h)3x5$N9ha8DSFHOtoW*1_0sUfRfCI$@yA9o=Z*|4z)iA=hn z8@Lm5C%D{&SRFoxnIQ*}T|O?T0lyg0@k2)%K!RFJFe|sc$Q-Lu%)l(RKMZ`piBe%P zvU1pP#DxyEbOArb%n8;}p=e<*GD|fv;ImGY3JW=WU*T@x6Am?v0q(`D3>Q05n!q

Nx#2V2(R!^a4v0bg5FE3alWWhOEcyioV^AOhCf2FDi63(tnZj1+JKY zbnm+5xgK#GCv+jPdR?(A7=0qAOa_4$G&CLp)&M8EkqOAEsma3G^=@R!uBAFI8CXHLqDWBjJvVw1ni=2hmZvvmyx%xD|98LyR+P= z+v0DoGZ42Ri?|F7AT8OZ@*C+VrK@f-2K_Dab>w`cDSaTD5=~C89D{6U))BT6H#>N` zfd@4;w(7lZC|P@y6VcyGvD7f{LF5UJ+mYGvC7OSz+coV0PB9df2Q}% zi@uSNQ5`vA)o97{GzC1Ei@9dZp>>omuk;U!IWyRb0rYI#iyUbK(W%;Za6vTl^HVbX zE3%7asm9Ig$eI2!IU6}MP)6l9(j&NuYJN#m-!;IQNN79h^WDVsca#3Ou^qjM)x8B6 zoyH83D}OhzGa+q7y)pCU*tJ`bU{^G4K%$E4aT6oxM{k??4$|jB4uOoDK#bVX9epU#-+vYZVq3Y7z>X3te)64@ua zCpR*SKJ!14QP_FN;mAhUxdrKpHphN9gmkf0qY5p)5BV0f<0nT+PDuuk}1uvr6%XMLQx;L6u;dWt=4U zxxu$JGQN%WdozY=y`$Y60HonPM(cWdmrdpur)0Pnci-%h6_o>2@sU-B9_0I#RCVmqsh- z*td115gfpCd~|>?35?*S(SasDIzZ?FB6w-Ef-nj61TQOEg^v!P!ppMo(&#{w-~dg$ z92$ZHH1V=5d^Fn2maf7_2Tvl=m8@5=m09bbPOLIAcTS=cxiN?NpOHBVF(EL zM{oeo@zDWPU40k=0{-En1B4zRf^QDsWhJNKn**fbrE~b^0A5yd8ooII1Sc4UZw`=F z`CdAPZw?TM;iChD$G`}_IY1Z!V)*6&ff&9yfS0X24c{C9f)k9wHwOrFfEd0x0C-x_ zDtvQ*8uG26s?WT`HwOsB@X-OhZ0Ra|bAT`jjNzLDfTtC$!Z!y9JwOcK93YM003P6F zC8sggwSbHq0gQ|M+=sk&UBxuiPTvnq)VSwP~pJ_R8N% zXT4I^D<%Oev9J7Hz-6VY4&=&oU_IuQzaRLr1HFL)7z8$>U-@<5J5H1a3gi7q3}43q z?xg)g9l$)tS^|zZ1Nf9{5w3X+hs*%PN2`{^00000NkvXXu0mjfLWapY literal 0 HcmV?d00001 diff --git a/src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_90_anticlockwise.svg b/src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_90_anticlockwise.svg new file mode 100644 index 000000000..47851199d --- /dev/null +++ b/src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_90_anticlockwise.svg @@ -0,0 +1,79 @@ + + + + + + image/svg+xml + + + + + + + + + + 90 + + diff --git a/src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_90_clockwise.svg b/src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_90_clockwise.svg new file mode 100644 index 000000000..d2effc39a --- /dev/null +++ b/src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_90_clockwise.svg @@ -0,0 +1,79 @@ + + + + + + image/svg+xml + + + + + + + + + + 90 + + diff --git a/src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_grainline_horizontal.svg b/src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_grainline_horizontal.svg new file mode 100644 index 000000000..4509e66c8 --- /dev/null +++ b/src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_grainline_horizontal.svg @@ -0,0 +1,77 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_grainline_vertical.svg b/src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_grainline_vertical.svg new file mode 100644 index 000000000..34e32c7a7 --- /dev/null +++ b/src/app/puzzle/share/resources/puzzleicon/svg/icon_rotate_grainline_vertical.svg @@ -0,0 +1,77 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/app/puzzle/vpgraphicssheet.cpp b/src/app/puzzle/vpgraphicssheet.cpp index 5c9638faf..4734e7e47 100644 --- a/src/app/puzzle/vpgraphicssheet.cpp +++ b/src/app/puzzle/vpgraphicssheet.cpp @@ -57,6 +57,8 @@ void VPGraphicsSheet::paint(QPainter *painter, const QStyleOptionGraphicsItem *o painter->setPen(pen); painter->setBrush(noBrush); + QRectF sheetRect = GetSheetRect(); + if(m_showMargin) { painter->drawRect(GetMarginsRect()); @@ -67,10 +69,41 @@ void VPGraphicsSheet::paint(QPainter *painter, const QStyleOptionGraphicsItem *o pen.setColor(Qt::black); painter->setPen(pen); - painter->drawRect(GetSheetRect()); + painter->drawRect(sheetRect); } - m_boundingRect = GetSheetRect(); + if(m_sheet->GetShowGrid()) + { + pen.setColor(QColor(204,204,204)); + painter->setPen(pen); + + qreal colWidth = m_sheet->GetGridColWidth(); + if(colWidth > 0) + { + qreal colX = colWidth; + while (colX < sheetRect.right()) + { + QLineF line = QLineF(colX, 0, colX, sheetRect.bottom()); + painter->drawLine(line); + colX += colWidth; + } + } + + qreal rowHeight = m_sheet->GetGridRowHeight(); + if(rowHeight > 0) + { + qreal rowY = rowHeight; + + while (rowY < sheetRect.bottom()) + { + QLineF line = QLineF(0, rowY, sheetRect.right(), rowY); + painter->drawLine(line); + rowY += rowHeight; + } + } + } + + m_boundingRect = sheetRect; } //--------------------------------------------------------------------------------------------------------------------- @@ -116,7 +149,6 @@ void VPGraphicsSheet::SetShowBorder(bool value) m_showBorder = value; } - //--------------------------------------------------------------------------------------------------------------------- QRectF VPGraphicsSheet::boundingRect() const { diff --git a/src/app/puzzle/vpgraphicssheet.h b/src/app/puzzle/vpgraphicssheet.h index 0cbef3a41..29e31bf34 100644 --- a/src/app/puzzle/vpgraphicssheet.h +++ b/src/app/puzzle/vpgraphicssheet.h @@ -48,19 +48,17 @@ public: QRectF GetMarginsRect() const; /** - * @brief ShowMargin Sets Wether we see the margin + * @brief SetShowMargin Sets Wether we see the margin * @param value true to show the margin */ void SetShowMargin(bool value); /** - * @brief ShowBorder Sets whether we see the border of the sheet + * @brief SetShowBorder Sets whether we see the border of the sheet * @param value true to show the border */ void SetShowBorder(bool value); - - private: Q_DISABLE_COPY(VPGraphicsSheet) diff --git a/src/app/puzzle/vpmaingraphicsview.cpp b/src/app/puzzle/vpmaingraphicsview.cpp index 17a246d96..94cdcdb81 100644 --- a/src/app/puzzle/vpmaingraphicsview.cpp +++ b/src/app/puzzle/vpmaingraphicsview.cpp @@ -95,6 +95,9 @@ void VPMainGraphicsView::PrepareForExport() m_graphicsSheet->SetShowBorder(false); m_graphicsSheet->SetShowMargin(false); + m_showGridTmp = m_layout->GetFocusedSheet()->GetShowGrid(); + m_layout->GetFocusedSheet()->SetShowGrid(false); + m_showTilesTmp = m_layout->GetShowTiles(); m_layout->SetShowTiles(false); @@ -107,6 +110,8 @@ void VPMainGraphicsView::CleanAfterExport() m_graphicsSheet->SetShowBorder(true); m_graphicsSheet->SetShowMargin(true); + m_layout->GetFocusedSheet()->SetShowGrid(m_showGridTmp); + m_layout->SetShowTiles(m_showTilesTmp); RefreshLayout(); diff --git a/src/app/puzzle/vpmaingraphicsview.h b/src/app/puzzle/vpmaingraphicsview.h index b1c84bc90..f1cef49b0 100644 --- a/src/app/puzzle/vpmaingraphicsview.h +++ b/src/app/puzzle/vpmaingraphicsview.h @@ -112,6 +112,11 @@ private: */ bool m_showTilesTmp{false}; + /** + * variable to hold temporarly hte value of the show grid + */ + bool m_showGridTmp{false}; + }; #endif // VPMAINGRAPHICSVIEW_H diff --git a/src/app/puzzle/vpmainwindow.cpp b/src/app/puzzle/vpmainwindow.cpp index 6a6efa726..19e6e7592 100644 --- a/src/app/puzzle/vpmainwindow.cpp +++ b/src/app/puzzle/vpmainwindow.cpp @@ -82,7 +82,7 @@ VPMainWindow::VPMainWindow(const VPCommandLinePtr &cmd, QWidget *parent) : m_layout->SetTilesSizeConverted(21,29.7); m_layout->SetTilesOrientation(PageOrientation::Portrait); m_layout->SetTilesMarginsConverted(1,1,1,1); - m_layout->SetShowTiles(true); +// m_layout->SetShowTiles(true); // -------------------------------------------------------- @@ -1150,6 +1150,27 @@ void VPMainWindow::on_SheetMarginChanged() m_graphicsView->RefreshLayout(); } +//--------------------------------------------------------------------------------------------------------------------- +void VPMainWindow::on_checkBoxSheetShowGrid_toggled(bool checked) +{ + m_layout->GetFocusedSheet()->SetShowGrid(checked); + m_graphicsView->RefreshLayout(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPMainWindow::on_doubleSpinBoxSheetGridColWidth_valueChanged(double value) +{ + m_layout->GetFocusedSheet()->SetGridColWidthConverted(value); + m_graphicsView->RefreshLayout(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPMainWindow::on_doubleSpinBoxSheetGridRowHeight_valueChanged(double value) +{ + m_layout->GetFocusedSheet()->SetGridRowHeightConverted(value); + m_graphicsView->RefreshLayout(); +} + //--------------------------------------------------------------------------------------------------------------------- void VPMainWindow::on_comboBoxTilesTemplate_currentIndexChanged(int index) { @@ -1376,6 +1397,42 @@ void VPMainWindow::on_checkBoxCurrentPieceMirrorPiece_toggled(bool checked) } } +//--------------------------------------------------------------------------------------------------------------------- +void VPMainWindow::on_pushButtonCurrentPieceRotate90Anticlockwise_clicked() +{ + if(m_selectedPieces.count() == 1) + { + m_selectedPieces.first()->RotateBy(90); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPMainWindow::on_pushButtonCurrentPieceRotate90Clockwise_clicked() +{ + if(m_selectedPieces.count() == 1) + { + m_selectedPieces.first()->RotateBy(-90); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPMainWindow::on_pushButtonCurrentPieceRotateGrainlineVertical_clicked() +{ + if(m_selectedPieces.count() == 1) + { + m_selectedPieces.first()->RotateToGrainline(90, true); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPMainWindow::on_pushButtonCurrentPieceRotateGrainlineHorizontal_clicked() +{ + if(m_selectedPieces.count() == 1) + { + m_selectedPieces.first()->RotateToGrainline(0, true); + } +} + //--------------------------------------------------------------------------------------------------------------------- void VPMainWindow::on_doubleSpinBoxCurrentPieceAngle_valueChanged(double value) { diff --git a/src/app/puzzle/vpmainwindow.h b/src/app/puzzle/vpmainwindow.h index aaf5bd0c0..f6c9bb01a 100644 --- a/src/app/puzzle/vpmainwindow.h +++ b/src/app/puzzle/vpmainwindow.h @@ -326,6 +326,29 @@ private slots: */ void on_SheetMarginChanged(); + /** + * @brief on_checkBoxSheetShowGrid_toggled When the checkbox "show grid" is + * clicked + * @param checked + */ + void on_checkBoxSheetShowGrid_toggled(bool checked); + + /** + * @brief on_doubleSpinBoxSheetGridColWidth_valueChanged When the "grid placement + * column width" value is changed in the layout property tab. + * The slot is automatically connected through name convention. + * @param value the new value of the grid placement column width + */ + void on_doubleSpinBoxSheetGridColWidth_valueChanged(double value); + + /** + * @brief on_doubleSpinBoxSheetGridRowHeight_valueChanged When the "grid placement + * row height" value is changed in the layout property tab. + * The slot is automatically connected through name convention. + * @param value the new value of the grid placement row height + */ + void on_doubleSpinBoxSheetGridRowHeight_valueChanged(double value); + /** * @brief LayoutFollowGrainlineChanged When one of the radio boxes for the * "Follow grainline" has been clicked in the sheet property tab. @@ -370,7 +393,7 @@ private slots: /** * @brief on_checkBoxTilesShowTiles_toggled When the checkbox "show tiles" is * clicked - * @param checked´ + * @param checked */ void on_checkBoxTilesShowTiles_toggled(bool checked); @@ -428,6 +451,30 @@ private slots: */ void on_checkBoxCurrentPieceMirrorPiece_toggled(bool checked); + /** + * @brief on_pushButtonCurrentPieceRotate90Antilockwise_clicked When the 90 + * anticlockwise angle button is clicked + */ + void on_pushButtonCurrentPieceRotate90Anticlockwise_clicked(); + + /** + * @brief on_pushButtonCurrentPieceRotate90Clockwise_clicked When the 90 + * clockwise angle button is clicked + */ + void on_pushButtonCurrentPieceRotate90Clockwise_clicked(); + + /** + * @brief on_pushButtonCurrentPieceRotateGrainlineVertical_clicked + * When the grainline vertical angle button is clicked + */ + void on_pushButtonCurrentPieceRotateGrainlineVertical_clicked(); + + /** + * @brief on_pushButtonCurrentPieceRotateGrainlineHorizontal_clicked + * When the grainline horizontal angle button is clicked + */ + void on_pushButtonCurrentPieceRotateGrainlineHorizontal_clicked(); + /** * @brief on_doubleSpinBoxCurrentPieceAngle_valueChanged When the * "Current Piece Angle" value in the current piece property is changed diff --git a/src/app/puzzle/vpmainwindow.ui b/src/app/puzzle/vpmainwindow.ui index 7d73aa8d2..fd9e9a7d7 100644 --- a/src/app/puzzle/vpmainwindow.ui +++ b/src/app/puzzle/vpmainwindow.ui @@ -17,6 +17,9 @@ :/puzzleicon/64x64/logo.png:/puzzleicon/64x64/logo.png + + Qt::LeftToRight + true @@ -176,7 +179,7 @@ QTabWidget::Rounded - 1 + 0 @@ -234,7 +237,7 @@ 0 0 342 - 1318 + 1370 @@ -359,14 +362,14 @@ Rotation - + Angle: - + 360.000000000000000 @@ -376,6 +379,90 @@ + + + + + + Rotate the piece by 90° clockwise + + + + + + + :/puzzleicon/64x64/iconRotate90Clockwise.png:/puzzleicon/64x64/iconRotate90Clockwise.png + + + + 32 + 32 + + + + + + + + Rotate the piece by 90° anti-clockwise + + + + + + + :/puzzleicon/64x64/iconRotate90Anticlockwise.png:/puzzleicon/64x64/iconRotate90Anticlockwise.png + + + + 32 + 32 + + + + + + + + Rotate the piece so that the grainline is vertical + + + + + + + :/puzzleicon/64x64/iconRotateGrainlineVertical.png:/puzzleicon/64x64/iconRotateGrainlineVertical.png + + + + 32 + 32 + + + + + + + + Rotate the piece so that the grainline is horizontal + + + + + + + :/puzzleicon/64x64/iconRotateGrainlineHorizontal.png:/puzzleicon/64x64/iconRotateGrainlineHorizontal.png + + + + 32 + 32 + + + + + + @@ -565,7 +652,7 @@ 0 0 342 - 731 + 870 @@ -803,6 +890,49 @@ + + + + Placement Grid + + + + + + + + Qt::LeftToRight + + + Show Grid + + + + + + + Column width + + + + + + + + + + Row height + + + + + + + + + + + diff --git a/src/app/puzzle/vppiece.cpp b/src/app/puzzle/vppiece.cpp index 4ae030063..cb46ed570 100644 --- a/src/app/puzzle/vppiece.cpp +++ b/src/app/puzzle/vppiece.cpp @@ -136,6 +136,31 @@ void VPPiece::SetRotation(qreal angle) } } +//--------------------------------------------------------------------------------------------------------------------- +void VPPiece::RotateBy(qreal angle) +{ + SetRotation(m_pieceAngle + angle); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPPiece::RotateToGrainline(qreal angleOfGrainline, bool add180IfAlreadyInPosition) +{ + qreal newAngle = -GrainlineAngle() + angleOfGrainline; + if(newAngle < 0) + { + newAngle += 360; + } + + if(not VFuzzyComparePossibleNulls(m_pieceAngle, newAngle)) + { + SetRotation(newAngle); + } + else if(add180IfAlreadyInPosition) + { + newAngle += 180; + SetRotation(newAngle); + } +} //--------------------------------------------------------------------------------------------------------------------- qreal VPPiece::GetRotation() diff --git a/src/app/puzzle/vppiece.h b/src/app/puzzle/vppiece.h index 4e88434ae..f14148f18 100644 --- a/src/app/puzzle/vppiece.h +++ b/src/app/puzzle/vppiece.h @@ -95,6 +95,23 @@ public: */ qreal GetRotation(); + /** + * @brief rotateBy adds the given angle to the current rotation (anti-clockwise) + * @param angle the angle to add + */ + void RotateBy(qreal angle); + + /** + * @brief RotateToGrainline rotates the piece, so that the grainline has + * the given angle + * + * @param angleOfGrainline + * @param add180IfAlreadyInPosition, automatically adds 180, if the piece is + * already in the grainline position + */ + void RotateToGrainline(qreal angleOfGrainline, bool add180IfAlreadyInPosition = false); + + /** * @brief SetIsSelected Sets wether the piece is selected * @param value true if the piece is selected @@ -153,7 +170,6 @@ private: QVector m_grainline{QVector()}; bool m_isGrainlineEnabled{false}; - qreal m_grainlineAngle{0}; // for now separate the position of the piece to the matrix coming from vlayoutpiece // because it's difficult to have the origin of the piece by (0,0) diff --git a/src/app/puzzle/vpsheet.cpp b/src/app/puzzle/vpsheet.cpp index 96796a0c1..15ca24b27 100644 --- a/src/app/puzzle/vpsheet.cpp +++ b/src/app/puzzle/vpsheet.cpp @@ -467,3 +467,64 @@ void VPSheet::ClearSelection() { m_pieceList->ClearSelection(); } + + +//--------------------------------------------------------------------------------------------------------------------- +bool VPSheet::GetShowGrid() +{ + return m_showGrid; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPSheet::SetShowGrid(bool value) +{ + m_showGrid = value; +} + +//--------------------------------------------------------------------------------------------------------------------- +qreal VPSheet::GetGridColWidth() const +{ + return m_gridColWidth; +} + +//--------------------------------------------------------------------------------------------------------------------- +qreal VPSheet::GetGridColWidthConverted() const +{ + return UnitConvertor(m_gridColWidth, Unit::Px, m_layout->GetUnit()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPSheet::SetGridColWidth(qreal value) +{ + m_gridColWidth = value; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPSheet::SetGridColWidthConverted(qreal value) +{ + m_gridColWidth = UnitConvertor(value, m_layout->GetUnit(), Unit::Px); +} + +//--------------------------------------------------------------------------------------------------------------------- +qreal VPSheet::GetGridRowHeight() const +{ + return m_gridRowHeight; +} + +//--------------------------------------------------------------------------------------------------------------------- +qreal VPSheet::GetGridRowHeightConverted() const +{ + return UnitConvertor(m_gridRowHeight, Unit::Px, m_layout->GetUnit()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPSheet::SetGridRowHeight(qreal value) +{ + m_gridRowHeight = value; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPSheet::SetGridRowHeightConverted(qreal value) +{ + m_gridRowHeight = UnitConvertor(value, m_layout->GetUnit(), Unit::Px); +} diff --git a/src/app/puzzle/vpsheet.h b/src/app/puzzle/vpsheet.h index 39fa05268..f1423dcab 100644 --- a/src/app/puzzle/vpsheet.h +++ b/src/app/puzzle/vpsheet.h @@ -268,6 +268,70 @@ public: */ void ClearSelection(); + /** + * @brief GetShowGrid Returns true if the placement grid has to be shown on the current sheet + * @return + */ + bool GetShowGrid(); + + /** + * @brief SetShowGrid Returns true if the placement grid has to be shown on the current sheet + * @param value whether to show the grid or not + */ + void SetShowGrid(bool value); + + /** + * @brief GetGridColWidth returns the placement grid column width in Unit::Px + * @return the placement grid column width in Unit::Px + */ + qreal GetGridColWidth() const; + + /** + * @brief GetGridColWidth returns the placement grid column width in the layout's unit + * @return the placement grid column width in the layout's unit + */ + qreal GetGridColWidthConverted() const; + + /** + * @brief SetGridColWidth sets the placement grid column width to the given value, the unit has to be Unit::Px + * @param value the placement grid column width in Unit::Px + */ + void SetGridColWidth(qreal value); + + /** + * @brief SetGridColWidthConverted sets the placement grid column width to the given value, the unit has to be in the layout's unit + * @param value the placement grid column width in the layout's unit + */ + void SetGridColWidthConverted(qreal value); + + /** + * @brief GetGridRowHeight returns the placement grid row height in Unit::Px + * @return the placement grid row height in Unit::Px + */ + qreal GetGridRowHeight() const; + + /** + * @brief GetGridRowHeightConverted returns the placement grid row height in the layout's unit + * @return the placement grid row height in the layout's unit + */ + qreal GetGridRowHeightConverted() const; + + /** + * @brief SetGridRowHeight sets the placement grid row height to the given value, the unit has to be Unit::Px + * @param value the placement grid row height in Unit::Px + */ + void SetGridRowHeight(qreal value); + + /** + * @brief SetGridRowHeightConverted sets the placement grid row height to the given value, the unit has to be in the layout's unit + * @param value the placement grid row height in the layout's unit + */ + void SetGridRowHeightConverted(qreal value); + + + + + void SetStickyEdges(bool state); bool GetStickyEdges() const; @@ -305,6 +369,21 @@ private: */ qreal m_piecesGap{0}; + // placement grid + /** + * @brief GetShowGrid Returns true if the placement grid has to be shown on the current sheet + */ + bool m_showGrid{false}; + /** + * @brief m_gridColWidth the column width of the placement grid in Unit::Px + */ + qreal m_gridColWidth{0}; + + /** + * @brief m_gridRowHeight the row height of the placement grid in Unit::Px + */ + qreal m_gridRowHeight{0}; + bool m_stickyEdges{false}; };