basegfx/source/matrix/b2dhommatrixtools.cxx | 43 include/basegfx/matrix/b2dhommatrixtools.hxx | 8 include/svx/svdobj.hxx | 4 include/svx/svdovirt.hxx | 3 include/svx/svxids.hrc | 2 officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu | 8 svx/sdi/svx.sdi | 17 svx/source/sidebar/possize/PosSizePropertyPanel.cxx | 1 svx/source/svdraw/svddrgmt.cxx | 487 +++------- svx/source/svdraw/svdmrkv.cxx | 79 + svx/source/svdraw/svdobj.cxx | 6 svx/source/svdraw/svdovirt.cxx | 6 sw/inc/fesh.hxx | 3 sw/sdi/_grfsh.sdi | 14 sw/sdi/grfsh.sdi | 9 sw/source/core/doc/notxtfrm.cxx | 39 sw/source/core/draw/dflyobj.cxx | 160 +++ sw/source/core/draw/dview.cxx | 24 sw/source/core/frmedt/feshview.cxx | 23 sw/source/core/inc/dflyobj.hxx | 13 sw/source/core/inc/frmtool.hxx | 7 sw/source/ui/frmdlg/frmpage.cxx | 31 sw/source/uibase/frmdlg/frmmgr.cxx | 24 sw/source/uibase/inc/frmmgr.hxx | 3 sw/source/uibase/inc/frmpage.hxx | 6 sw/source/uibase/shells/frmsh.cxx | 17 sw/source/uibase/shells/grfsh.cxx | 189 ++- sw/uiconfig/sglobal/menubar/menubar.xml | 1 sw/uiconfig/sglobal/popupmenu/graphic.xml | 1 sw/uiconfig/sglobal/toolbar/graphicobjectbar.xml | 1 sw/uiconfig/sweb/menubar/menubar.xml | 1 sw/uiconfig/sweb/popupmenu/graphic.xml | 1 sw/uiconfig/swform/menubar/menubar.xml | 1 sw/uiconfig/swform/popupmenu/graphic.xml | 1 sw/uiconfig/swform/toolbar/graphicobjectbar.xml | 1 sw/uiconfig/swreport/menubar/menubar.xml | 1 sw/uiconfig/swreport/popupmenu/graphic.xml | 1 sw/uiconfig/swreport/toolbar/graphicobjectbar.xml | 1 sw/uiconfig/swriter/menubar/menubar.xml | 1 sw/uiconfig/swriter/popupmenu/graphic.xml | 1 sw/uiconfig/swriter/toolbar/graphicobjectbar.xml | 2 sw/uiconfig/swriter/ui/notebookbar.ui | 26 sw/uiconfig/swriter/ui/notebookbar_groupedbar_compact.ui | 7 sw/uiconfig/swriter/ui/notebookbar_groupedbar_full.ui | 7 sw/uiconfig/swriter/ui/picturepage.ui | 149 +++ sw/uiconfig/swxform/menubar/menubar.xml | 1 sw/uiconfig/swxform/popupmenu/graphic.xml | 1 sw/uiconfig/swxform/toolbar/graphicobjectbar.xml | 3 xmloff/source/text/XMLTextFrameContext.cxx | 5 49 files changed, 1021 insertions(+), 419 deletions(-)
New commits: commit 387554ef787ced5d3e5c94bb824aa5dc383f133a Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Thu Oct 5 22:00:35 2017 +0200 RotGrfFlyFrame: Clang error fix Change-Id: Ifae68d4d5a17446f01c97ce2e94cd0419217259e diff --git a/sw/source/core/draw/dview.cxx b/sw/source/core/draw/dview.cxx index 7db8e4946abd..0935ddbd637c 100644 --- a/sw/source/core/draw/dview.cxx +++ b/sw/source/core/draw/dview.cxx @@ -829,11 +829,7 @@ void SwDrawView::CheckPossibilities() pFrame = pFly->GetAnchorFrame(); if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() ) { - // SwNoTextNode& rNoTNd = const_cast<SwNoTextNode&>(*static_cast<const SwNoTextNode*>((static_cast<const SwContentFrame*>(pFly->Lower()))->GetNode())); - // SwGrfNode* pGrfNd = rNoTNd.GetGrfNode(); - // SwOLENode* pOLENd = rNoTNd.GetOLENode(); - - const SwContentFrame* pCntFr = const_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(pFly->Lower())); + const SwContentFrame* pCntFr(static_cast<const SwContentFrame*>(pFly->Lower())); const SwOLENode* pOLENd = pCntFr->GetNode()->GetOLENode(); const SwGrfNode* pGrfNd = pCntFr->GetNode()->GetGrfNode(); commit 9743ecb42095b6e742ab7636ccc67b820f8b9fee Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Wed Oct 4 17:44:24 2017 +0200 RotGrfFlyFrame: Added interactive rotation mode The FlyFrames containing a graphic now support an interactive rotation mode. Added a rotation icon to the Toolbar close to right/left 90degree rotation. When activated, works as similar to draw object mode as possible. Shear and move of the rotation center is deactivated since not supported. It uses as much of the existing interaction stuff as possible. Change-Id: Ia1a4e5c064d8576b114c3fcf3a96ccb42c9372bb diff --git a/basegfx/source/matrix/b2dhommatrixtools.cxx b/basegfx/source/matrix/b2dhommatrixtools.cxx index 26936aff2e5c..e26fb922f5b6 100644 --- a/basegfx/source/matrix/b2dhommatrixtools.cxx +++ b/basegfx/source/matrix/b2dhommatrixtools.cxx @@ -364,7 +364,8 @@ namespace basegfx { basegfx::B2DHomMatrix aRetval; - // RotGrfFlyFrame: Take rotation into account. Rotation is in 10th degrees + // RotGrfFlyFrame: Create a transformation that maps the range inside of itself + // so that it fits, takes as much space as possible and keeps the aspect ratio if(0.0 != fRotate) { // Fit rotated graphic to center of available space, keeping page ratio: diff --git a/include/svx/svdobj.hxx b/include/svx/svdobj.hxx index 3d7ded0a7fe9..cd6953312565 100644 --- a/include/svx/svdobj.hxx +++ b/include/svx/svdobj.hxx @@ -410,6 +410,10 @@ public: void SingleObjectPainter(OutputDevice& rOut) const; bool LineGeometryUsageIsNecessary() const; + // RotGrfFlyFrame: If true, this SdrObject supports only limited rotation, that + // means no change of the rotation point (only centered) and no shear allowed + virtual bool HasLimitedRotation() const; + // Returns a copy of the object. Every inherited class must reimplement this (in class Foo // it should be sufficient to do "virtual Foo* Clone() const { return CloneHelper< Foo >(); }". // Note that this function uses operator= internally. diff --git a/include/svx/svdovirt.hxx b/include/svx/svdovirt.hxx index a6223975572d..c6d626e1305f 100644 --- a/include/svx/svdovirt.hxx +++ b/include/svx/svdovirt.hxx @@ -68,6 +68,9 @@ public: virtual OUString TakeObjNameSingul() const override; virtual OUString TakeObjNamePlural() const override; + // RotGrfFlyFrame: If true, this SdrObject supports only limited rotation + virtual bool HasLimitedRotation() const override; + virtual basegfx::B2DPolyPolygon TakeXorPoly() const override; virtual sal_uInt32 GetHdlCount() const override; virtual SdrHdl* GetHdl(sal_uInt32 nHdlNum) const override; diff --git a/include/svx/svxids.hrc b/include/svx/svxids.hrc index 79ebc50726c1..8d0e22a22179 100644 --- a/include/svx/svxids.hrc +++ b/include/svx/svxids.hrc @@ -919,7 +919,7 @@ #define SID_ROTATE_GRAPHIC_LEFT ( SID_SVX_START + 1121 ) #define SID_ROTATE_GRAPHIC_RIGHT ( SID_SVX_START + 1122 ) #define SID_ROTATE_GRAPHIC_180 ( SID_SVX_START + 1123 ) -#define SID_ROTATE_GRAPHIC_RESET ( SID_SVX_START + 1092 ) /* RotGrfFlyFrame: new slot */ +#define SID_ROTATE_GRAPHIC_RESET ( SID_SVX_START + 1092 ) /* RotGrfFlyFrame: */ // new slots for panels #define SID_ATTR_FILL_TRANSPARENCE ( SID_SVX_START + 1124 ) diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx index 3348579bd508..a00528f61af8 100644 --- a/svx/source/svdraw/svddrgmt.cxx +++ b/svx/source/svdraw/svddrgmt.cxx @@ -2097,18 +2097,28 @@ bool SdrDragRotate::BeginSdrDrag() { SdrHdl* pH=GetHdlList().GetHdl(SdrHdlKind::Ref1); - if (pH!=nullptr) + if (nullptr != pH) { Show(); DragStat().Ref1()=pH->GetPos(); nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1()); return true; } - else + + // RotGrfFlyFrame: Support rotation around center *without* Ref1 (normally + // the rotation point) + const tools::Rectangle aLocalMarkRect(getSdrDragView().GetMarkedObjRect()); + + if(!aLocalMarkRect.IsEmpty()) { - OSL_FAIL("SdrDragRotate::BeginSdrDrag(): No reference point handle found."); - return false; + Show(); + DragStat().Ref1() = aLocalMarkRect.Center(); + nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1()); + return true; } + + OSL_FAIL("SdrDragRotate::BeginSdrDrag(): No reference point handle found."); + return false; } basegfx::B2DHomMatrix SdrDragRotate::getCurrentTransformation() diff --git a/svx/source/svdraw/svdmrkv.cxx b/svx/source/svdraw/svdmrkv.cxx index 73a79d4bb983..61286258cc0f 100644 --- a/svx/source/svdraw/svdmrkv.cxx +++ b/svx/source/svdraw/svdmrkv.cxx @@ -658,14 +658,22 @@ void SdrMarkView::SetMarkHandles(SfxViewShell* pOtherShell) const size_t nMarkCount=GetMarkedObjectCount(); bool bStdDrag=meDragMode==SdrDragMode::Move; bool bSingleTextObjMark=false; + bool bLimitedRotation(false); if (nMarkCount==1) { mpMarkedObj=GetMarkedObjectByIndex(0); - bSingleTextObjMark = - mpMarkedObj && - dynamic_cast<const SdrTextObj*>( mpMarkedObj) != nullptr && - static_cast<SdrTextObj*>(mpMarkedObj)->IsTextFrame(); + + if(nullptr != mpMarkedObj) + { + bSingleTextObjMark = + mpMarkedObj && + dynamic_cast<const SdrTextObj*>( mpMarkedObj) != nullptr && + static_cast<SdrTextObj*>(mpMarkedObj)->IsTextFrame(); + + // RotGrfFlyFrame: we may have limited rotation + bLimitedRotation = SdrDragMode::Rotate == meDragMode && mpMarkedObj->HasLimitedRotation(); + } } bool bFrmHdl=ImpIsFrameHandles(); @@ -831,27 +839,59 @@ void SdrMarkView::SetMarkHandles(SfxViewShell* pOtherShell) } else { - bool bWdt0=aRect.Left()==aRect.Right(); - bool bHgt0=aRect.Top()==aRect.Bottom(); + const bool bWdt0(aRect.Left() == aRect.Right()); + const bool bHgt0(aRect.Top() == aRect.Bottom()); + if (bWdt0 && bHgt0) { - maHdlList.AddHdl(new SdrHdl(aRect.TopLeft(),SdrHdlKind::UpperLeft)); + maHdlList.AddHdl(new SdrHdl(aRect.TopLeft(), SdrHdlKind::UpperLeft)); } else if (!bStdDrag && (bWdt0 || bHgt0)) { - maHdlList.AddHdl(new SdrHdl(aRect.TopLeft() ,SdrHdlKind::UpperLeft)); - maHdlList.AddHdl(new SdrHdl(aRect.BottomRight(),SdrHdlKind::LowerRight)); + maHdlList.AddHdl(new SdrHdl(aRect.TopLeft(), SdrHdlKind::UpperLeft)); + maHdlList.AddHdl(new SdrHdl(aRect.BottomRight(), SdrHdlKind::LowerRight)); } else { - if (!bWdt0 && !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.TopLeft() ,SdrHdlKind::UpperLeft)); - if ( !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.TopCenter() ,SdrHdlKind::Upper)); - if (!bWdt0 && !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.TopRight() ,SdrHdlKind::UpperRight)); - if (!bWdt0 ) maHdlList.AddHdl(new SdrHdl(aRect.LeftCenter() ,SdrHdlKind::Left )); - if (!bWdt0 ) maHdlList.AddHdl(new SdrHdl(aRect.RightCenter() ,SdrHdlKind::Right)); - if (!bWdt0 && !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.BottomLeft() ,SdrHdlKind::LowerLeft)); - if ( !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.BottomCenter(),SdrHdlKind::Lower)); - if (!bWdt0 && !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.BottomRight() ,SdrHdlKind::LowerRight)); + if (!bWdt0 && !bHgt0) + { + maHdlList.AddHdl(new SdrHdl(aRect.TopLeft(), SdrHdlKind::UpperLeft)); + } + + if (!bLimitedRotation && !bHgt0) + { + maHdlList.AddHdl(new SdrHdl(aRect.TopCenter(), SdrHdlKind::Upper)); + } + + if (!bWdt0 && !bHgt0) + { + maHdlList.AddHdl(new SdrHdl(aRect.TopRight(), SdrHdlKind::UpperRight)); + } + + if (!bLimitedRotation && !bWdt0) + { + maHdlList.AddHdl(new SdrHdl(aRect.LeftCenter(), SdrHdlKind::Left )); + } + + if (!bLimitedRotation && !bWdt0) + { + maHdlList.AddHdl(new SdrHdl(aRect.RightCenter(), SdrHdlKind::Right)); + } + + if (!bWdt0 && !bHgt0) + { + maHdlList.AddHdl(new SdrHdl(aRect.BottomLeft(), SdrHdlKind::LowerLeft)); + } + + if (!bLimitedRotation && !bHgt0) + { + maHdlList.AddHdl(new SdrHdl(aRect.BottomCenter(), SdrHdlKind::Lower)); + } + + if (!bWdt0 && !bHgt0) + { + maHdlList.AddHdl(new SdrHdl(aRect.BottomRight(), SdrHdlKind::LowerRight)); + } } } } @@ -945,7 +985,10 @@ void SdrMarkView::SetMarkHandles(SfxViewShell* pOtherShell) } // rotation point/axis of reflection - AddDragModeHdl(meDragMode); + if(!bLimitedRotation) + { + AddDragModeHdl(meDragMode); + } // sort handles maHdlList.Sort(); diff --git a/svx/source/svdraw/svdobj.cxx b/svx/source/svdraw/svdobj.cxx index f5f3f269f866..b2dd3a2fc6c8 100644 --- a/svx/source/svdraw/svdobj.cxx +++ b/svx/source/svdraw/svdobj.cxx @@ -931,6 +931,12 @@ bool SdrObject::LineGeometryUsageIsNecessary() const return (eXLS != drawing::LineStyle_NONE); } +bool SdrObject::HasLimitedRotation() const +{ + // RotGrfFlyFrame: Default is false, support full rotation + return false; +} + SdrObject* SdrObject::Clone() const { return CloneHelper< SdrObject >(); diff --git a/svx/source/svdraw/svdovirt.cxx b/svx/source/svdraw/svdovirt.cxx index 7c9f54e35bd8..d7145be8f93a 100644 --- a/svx/source/svdraw/svdovirt.cxx +++ b/svx/source/svdraw/svdovirt.cxx @@ -166,6 +166,12 @@ OUString SdrVirtObj::TakeObjNamePlural() const return sName.makeStringAndClear(); } +bool SdrVirtObj::HasLimitedRotation() const +{ + // RotGrfFlyFrame: If true, this SdrObject supports only limited rotation + return rRefObj.HasLimitedRotation(); +} + basegfx::B2DPolyPolygon SdrVirtObj::TakeXorPoly() const { basegfx::B2DPolyPolygon aPolyPolygon(rRefObj.TakeXorPoly()); diff --git a/sw/inc/fesh.hxx b/sw/inc/fesh.hxx index 0775d14cd852..1141a4ea9812 100644 --- a/sw/inc/fesh.hxx +++ b/sw/inc/fesh.hxx @@ -505,6 +505,9 @@ public: // Start cropping the selected image void StartCropImage(); + // RotGrfFlyFrame: check if RotationMode is possibe + bool IsRotationOfSwGrfNodePossible() const; + size_t IsObjSelected() const; ///< @return object count, but doesn't count the objects in groups. bool IsObjSelected( const SdrObject& rObj ) const; bool IsObjSameLevelWithMarked(const SdrObject* pObj) const; diff --git a/sw/sdi/grfsh.sdi b/sw/sdi/grfsh.sdi index 956a0c82b443..8451eae60eba 100644 --- a/sw/sdi/grfsh.sdi +++ b/sw/sdi/grfsh.sdi @@ -24,5 +24,14 @@ shell SwGrfShell : SwBaseShell { import TextGraphic; + + // RotGrfFlyFrame: need SID_OBJECT_ROTATE for FlyFrames with graphic + SID_OBJECT_ROTATE + [ + Export = FALSE; + ExecMethod = Execute ; + StateMethod = GetAttrState ; + DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; + ] } diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx index 6a21d0eb9d71..29e5e4a94715 100644 --- a/sw/source/core/draw/dflyobj.cxx +++ b/sw/source/core/draw/dflyobj.cxx @@ -49,6 +49,7 @@ #include "rootfrm.hxx" #include "wrtsh.hxx" #include <ndgrf.hxx> +#include <frmmgr.hxx> #include <svx/sdr/properties/defaultproperties.hxx> #include <basegfx/range/b2drange.hxx> @@ -354,6 +355,64 @@ basegfx::B2DRange SwVirtFlyDrawObj::getInnerBound() const return aInnerRange; } +bool SwVirtFlyDrawObj::ContainsSwGrfNode() const +{ + // RotGrfFlyFrame: Check if this is a SwGrfNode + const SwFlyFrame* pFlyFrame(GetFlyFrame()); + + if(nullptr != pFlyFrame && pFlyFrame->Lower() && pFlyFrame->Lower()->IsNoTextFrame()) + { + const SwContentFrame* pCntFr(static_cast<const SwContentFrame*>(pFlyFrame->Lower())); + + if(nullptr != pCntFr) + { + const SwGrfNode* pGrfNd(pCntFr->GetNode()->GetGrfNode()); + + return nullptr != pGrfNd; + } + } + + return false; +} + +bool SwVirtFlyDrawObj::HasLimitedRotation() const +{ + // RotGrfFlyFrame: If true, this SdrObject supports only limited rotation. + // This is the case for SwGrfNode instances + return ContainsSwGrfNode(); +} + +void SwVirtFlyDrawObj::Rotate(const Point& rRef, long nAngle, double sn, double cs) +{ + if(ContainsSwGrfNode()) + { + // RotGrfFlyFrame: Here is where the positively completed rotate interaction is executed. + // Rotation is in 1/100th degree and may be signed (!) + nAngle /= 10; + + while(nAngle < 0) + { + nAngle += 3600; + } + + if(0 != nAngle) + { + // RotGrfFlyFrame: Add transformation to placeholder object + Size aSize; + const sal_uInt16 nOldRot(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame(aSize)); + SwWrtShell *pSh = dynamic_cast<SwWrtShell*>( GetFlyFrame()->getRootFrame()->GetCurrShell() ); + SwFlyFrameAttrMgr aMgr(false, pSh, Frmmgr_Type::NONE); + + aMgr.SetRotation(nOldRot, (nOldRot + static_cast<sal_uInt16>(nAngle)) % 3600, aSize); + } + } + else + { + // call parent + SdrVirtObj::Rotate(rRef, nAngle, sn, cs); + } +} + sdr::contact::ViewContact* SwVirtFlyDrawObj::CreateObjectSpecificViewContact() { // need an own ViewContact (VC) to allow creation of a specialized primitive @@ -477,7 +536,9 @@ void SwVirtFlyDrawObj::TakeObjInfo( SdrObjTransformInfoRec& rInfo ) const rInfo.bMoveAllowed = rInfo.bResizeFreeAllowed = rInfo.bResizePropAllowed = true; - rInfo.bRotateFreeAllowed = rInfo.bRotate90Allowed = + // RotGrfFlyFrame: Some rotation may be allowed + rInfo.bRotateFreeAllowed = rInfo.bRotate90Allowed = HasLimitedRotation(); + rInfo.bMirrorFreeAllowed = rInfo.bMirror45Allowed = rInfo.bMirror90Allowed = rInfo.bShearAllowed = rInfo.bCanConvToPath = rInfo.bCanConvToPoly = @@ -924,7 +985,7 @@ void SwVirtFlyDrawObj::Crop(const Point& rRef, const Fraction& xFact, const Frac } // RotGrfFlyFrame: Helper to access possible rotation of Graphic contained in FlyFrame -sal_uInt16 SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame() const +sal_uInt16 SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame(Size& rSize) const { sal_uInt16 nRetval(0); const SwNoTextFrame* pNoTx = dynamic_cast< const SwNoTextFrame* >(GetFlyFrame()->Lower()); @@ -939,6 +1000,7 @@ sal_uInt16 SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame() const const SwAttrSet& rSet = pGrfNd->GetSwAttrSet(); const SwRotationGrf& rRotation = rSet.GetRotationGrf(); + rSize = rRotation.GetUnrotatedSize(); nRetval = rRotation.GetValue(); } } @@ -951,25 +1013,19 @@ SdrObject* SwVirtFlyDrawObj::getFullDragClone() const // call parent SdrObject* pRetval = SdrVirtObj::getFullDragClone(); - if(pRetval) + if(pRetval && ContainsSwGrfNode()) { // RotGrfFlyFrame: Add transformation to placeholder object - const sal_uInt16 nRotation(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame()); - - if(0 != nRotation) - { - const double fRotate(static_cast< double >(-nRotation) * (M_PI/1800.0)); - const tools::Rectangle aTmpOutRect(GetFlyFrame()->Frame().SVRect()); - const basegfx::B2DRange aTargetRange( - aTmpOutRect.Left(), aTmpOutRect.Top(), - aTmpOutRect.Right(), aTmpOutRect.Bottom()); - const basegfx::B2DHomMatrix aTargetTransform( - basegfx::utils::createRotateAroundCenterKeepAspectRatioStayInsideRange( - aTargetRange, - fRotate)); + Size aSize; + const sal_uInt16 nRotation(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame(aSize)); + const double fRotate(static_cast< double >(-nRotation) * (M_PI/1800.0)); + const basegfx::B2DRange aTargetRange(getInnerBound()); + const basegfx::B2DHomMatrix aTargetTransform( + basegfx::utils::createRotateAroundCenterKeepAspectRatioStayInsideRange( + aTargetRange, + fRotate)); - pRetval->TRSetBaseGeometry(aTargetTransform, basegfx::B2DPolyPolygon()); - } + pRetval->TRSetBaseGeometry(aTargetTransform, basegfx::B2DPolyPolygon()); } return pRetval; @@ -987,7 +1043,8 @@ void SwVirtFlyDrawObj::addCropHandles(SdrHdlList& rTarget) const if(!aTargetRange.isEmpty()) { - const sal_uInt16 nRotation(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame()); + Size aSize; + const sal_uInt16 nRotation(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame(aSize)); const double fRotate(static_cast< double >(-nRotation) * (M_PI/1800.0)); const basegfx::B2DHomMatrix aTargetTransform( basegfx::utils::createRotateAroundCenterKeepAspectRatioStayInsideRange( diff --git a/sw/source/core/draw/dview.cxx b/sw/source/core/draw/dview.cxx index d7c995ef552e..7db8e4946abd 100644 --- a/sw/source/core/draw/dview.cxx +++ b/sw/source/core/draw/dview.cxx @@ -44,6 +44,7 @@ #include "doc.hxx" #include "mdiexp.hxx" #include <ndole.hxx> +#include <ndgrf.hxx> #include <fmtanchr.hxx> #include "shellres.hxx" #include <IDocumentUndoRedo.hxx> @@ -814,6 +815,8 @@ void SwDrawView::CheckPossibilities() const SdrMarkList &rMrkList = GetMarkedObjectList(); bool bProtect = false; bool bSzProtect = false; + bool bRotate(false); + for ( size_t i = 0; !bProtect && i < rMrkList.GetMarkCount(); ++i ) { const SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj(); @@ -826,10 +829,18 @@ void SwDrawView::CheckPossibilities() pFrame = pFly->GetAnchorFrame(); if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() ) { - SwOLENode *pNd = const_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(pFly->Lower()))->GetNode()->GetOLENode(); - if ( pNd ) + // SwNoTextNode& rNoTNd = const_cast<SwNoTextNode&>(*static_cast<const SwNoTextNode*>((static_cast<const SwContentFrame*>(pFly->Lower()))->GetNode())); + // SwGrfNode* pGrfNd = rNoTNd.GetGrfNode(); + // SwOLENode* pOLENd = rNoTNd.GetOLENode(); + + const SwContentFrame* pCntFr = const_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(pFly->Lower())); + const SwOLENode* pOLENd = pCntFr->GetNode()->GetOLENode(); + const SwGrfNode* pGrfNd = pCntFr->GetNode()->GetGrfNode(); + + if ( pOLENd ) { - uno::Reference < embed::XEmbeddedObject > xObj = pNd->GetOLEObj().GetOleRef(); + const uno::Reference < embed::XEmbeddedObject > xObj = const_cast< SwOLEObj& >(pOLENd->GetOLEObj()).GetOleRef(); + if ( xObj.is() ) { // --> improvement for the future, when more @@ -847,6 +858,13 @@ void SwDrawView::CheckPossibilities() bMoveProtect = true; } } + else if(pGrfNd) + { + // RotGrfFlyFrame: GraphicNode allows rotation(s). The loop ew are in stops + // as soon as bMoveProtect is set, but since rotation is valid only with + // a single object selected this makes no difference + bRotate = true; + } } } } @@ -874,6 +892,10 @@ void SwDrawView::CheckPossibilities() } bMoveProtect |= bProtect; bResizeProtect |= bProtect || bSzProtect; + + // RotGrfFlyFrame: allow rotation when SwGrfNode is selected and not size protected + bRotateFreeAllowed |= bRotate && !bProtect; + bRotate90Allowed |= bRotateFreeAllowed; } /// replace marked <SwDrawVirtObj>-objects by its reference object for delete marked objects. diff --git a/sw/source/core/frmedt/feshview.cxx b/sw/source/core/frmedt/feshview.cxx index 5ed4bdae28a8..27893c02fae6 100644 --- a/sw/source/core/frmedt/feshview.cxx +++ b/sw/source/core/frmedt/feshview.cxx @@ -1161,6 +1161,29 @@ bool SwFEShell::IsObjSelected( const SdrObject& rObj ) const return Imp()->GetDrawView()->IsObjMarked( &rObj ); } +bool SwFEShell::IsRotationOfSwGrfNodePossible() const +{ + // RotGrfFlyFrame: check if RotationMode is possibe + const SdrView *pSdrView = Imp()->GetDrawView(); + + if(pSdrView) + { + const SdrMarkList& rList(pSdrView->GetMarkedObjectList()); + + if(1 == rList.GetMarkCount()) + { + const SwVirtFlyDrawObj* pVirtFlyDraw(dynamic_cast< const SwVirtFlyDrawObj* >(rList.GetMark(0)->GetMarkedSdrObj())); + + if(nullptr != pVirtFlyDraw) + { + return pVirtFlyDraw->ContainsSwGrfNode(); + } + } + } + + return false; +} + bool SwFEShell::IsObjSameLevelWithMarked(const SdrObject* pObj) const { if (pObj) diff --git a/sw/source/core/inc/dflyobj.hxx b/sw/source/core/inc/dflyobj.hxx index 528edc8aff39..8766b7980ebc 100644 --- a/sw/source/core/inc/dflyobj.hxx +++ b/sw/source/core/inc/dflyobj.hxx @@ -60,7 +60,7 @@ private: // RotGrfFlyFrame: Helper to acces sthe rotation angle (in 10th degrees, left-handed) // of a GraphicFrame - sal_uInt16 getPossibleRotationFromFraphicFrame() const; + sal_uInt16 getPossibleRotationFromFraphicFrame(Size& rSize) const; protected: // AW: Need own sdr::contact::ViewContact since AnchorPos from parent is @@ -77,6 +77,8 @@ public: basegfx::B2DRange getOuterBound() const; basegfx::B2DRange getInnerBound() const; + // RotGrfFlyFrame: Check if this is a SwGrfNode + bool ContainsSwGrfNode() const; SwVirtFlyDrawObj(SdrObject& rNew, SwFlyFrame* pFly); virtual ~SwVirtFlyDrawObj() override; @@ -105,6 +107,7 @@ public: const Fraction& yFact, bool bUnsetRelative = true) override; virtual void Crop(const Point& rRef, const Fraction& xFact, const Fraction& yFact) override; virtual void addCropHandles(SdrHdlList& rTarget) const override; + virtual void Rotate(const Point& rRef, long nAngle, double sn, double cs) override; // FullDrag support virtual SdrObject* getFullDragClone() const override; @@ -122,6 +125,9 @@ public: virtual bool HasMacro() const override; virtual SdrObject* CheckMacroHit (const SdrObjMacroHitRec& rRec) const override; virtual Pointer GetMacroPointer (const SdrObjMacroHitRec& rRec) const override; + + // RotGrfFlyFrame: If true, this SdrObject supports only limited rotation. + virtual bool HasLimitedRotation() const override; }; #endif diff --git a/sw/source/uibase/frmdlg/frmmgr.cxx b/sw/source/uibase/frmdlg/frmmgr.cxx index c73238be62ea..7cd7c2702333 100644 --- a/sw/source/uibase/frmdlg/frmmgr.cxx +++ b/sw/source/uibase/frmdlg/frmmgr.cxx @@ -577,9 +577,9 @@ void SwFlyFrameAttrMgr::SetHeightSizeType( SwFrameSize eType ) void SwFlyFrameAttrMgr::SetRotation(sal_uInt16 nOld, sal_uInt16 nNew, const Size& rUnrotatedSize) { // RotGrfFlyFrame: Central handling of real change of rotation here, all adaptions use this. - // Adaption of pos/size may be wanted in the future. Already tried to keep last SIze in + // Adaption of pos/size may be wanted in the future. Already tried to keep last Size in // UnrotatedSize in the SwRotationGrf Item, but this will lead to various problems. Also tried - // to use m_aSet.Put(...) as in other methods (also read methods for Rotation/UnrotatedSize) but + // to use m_aSet.Put(...) as in other methods (also tried read methods for Rotation/UnrotatedSize) but // somehow the needed ID (RES_GRFATR_ROTATION) is *not* in the SfxItemSet of the Frame, so for // now set directly. Undo/Redo is preserved by AttributeChange if(nOld != nNew) diff --git a/sw/source/uibase/shells/grfsh.cxx b/sw/source/uibase/shells/grfsh.cxx index 0914846b7857..23857b2b4745 100644 --- a/sw/source/uibase/shells/grfsh.cxx +++ b/sw/source/uibase/shells/grfsh.cxx @@ -123,6 +123,27 @@ void SwGrfShell::Execute(SfxRequest &rReq) sal_uInt16 nSlot = rReq.GetSlot(); switch(nSlot) { + case SID_OBJECT_ROTATE: + { + // RotGrfFlyFrame: start rotation when possible + SdrView* pSdrView = rSh.GetDrawViewWithValidMarkList(); + + if(rSh.IsRotationOfSwGrfNodePossible() && pSdrView->IsRotateAllowed()) + { + if(GetView().IsDrawRotate()) + { + rSh.SetDragMode(SdrDragMode::Move); + } + else + { + rSh.SetDragMode(SdrDragMode::Rotate); + } + + GetView().FlipDrawRotate(); + } + } + break; + case SID_TWAIN_TRANSFER: { GetView().ExecuteScan( rReq ); @@ -721,6 +742,23 @@ void SwGrfShell::GetAttrState(SfxItemSet &rSet) bool bDisable = bParentCntProt; switch( nWhich ) { + case SID_OBJECT_ROTATE: + { + // RotGrfFlyFrame: steer rotation state + const bool bIsRotate(GetView().IsDrawRotate()); + SdrView* pSdrView = rSh.GetDrawViewWithValidMarkList(); + + if(!bIsRotate && !pSdrView->IsRotateAllowed()) + { + rSet.DisableItem(nWhich); + } + else + { + rSet.Put(SfxBoolItem(nWhich, bIsRotate)); + } + + break; + } case SID_INSERT_GRAPHIC: case FN_FORMAT_GRAFIC_DLG: case SID_TWAIN_TRANSFER: diff --git a/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml b/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml index c1ba2219af1b..6494546daebd 100644 --- a/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml +++ b/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml @@ -28,6 +28,7 @@ <toolbar:toolbaritem xlink:href=".uno:FlipHorizontal"/> <toolbar:toolbaritem xlink:href=".uno:RotateLeft"/> <toolbar:toolbaritem xlink:href=".uno:RotateRight"/> + <toolbar:toolbaritem xlink:href=".uno:ToggleObjectRotateMode"/> <toolbar:toolbaritem xlink:href=".uno:Rotate180" toolbar:visible="false"/> <toolbar:toolbaritem xlink:href=".uno:RotateReset" toolbar:visible="false"/> <toolbar:toolbarseparator/> commit 93f5800e181372d3e5f02c825fd3b09f2756cac7 Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Fri Sep 29 12:35:44 2017 +0200 RotGrfFlyFrame: Corrected position for CropHandles Position was taken from OuterBound FlyFrame, even in current master which is wrong. There can be a distance defined between InnerBound and OuterBound that has to be taken into account Change-Id: Id88f99c0b218bd26fa1daa5e8215eced00c0baa6 diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx index 358085bd2760..6a21d0eb9d71 100644 --- a/sw/source/core/draw/dflyobj.cxx +++ b/sw/source/core/draw/dflyobj.cxx @@ -48,6 +48,7 @@ #include "pagefrm.hxx" #include "rootfrm.hxx" #include "wrtsh.hxx" +#include <ndgrf.hxx> #include <svx/sdr/properties/defaultproperties.hxx> #include <basegfx/range/b2drange.hxx> @@ -958,10 +959,10 @@ SdrObject* SwVirtFlyDrawObj::getFullDragClone() const if(0 != nRotation) { const double fRotate(static_cast< double >(-nRotation) * (M_PI/1800.0)); - const tools::Rectangle aOutRect(GetFlyFrame()->Frame().SVRect()); + const tools::Rectangle aTmpOutRect(GetFlyFrame()->Frame().SVRect()); const basegfx::B2DRange aTargetRange( - aOutRect.Left(), aOutRect.Top(), - aOutRect.Right(), aOutRect.Bottom()); + aTmpOutRect.Left(), aTmpOutRect.Top(), + aTmpOutRect.Right(), aTmpOutRect.Bottom()); const basegfx::B2DHomMatrix aTargetTransform( basegfx::utils::createRotateAroundCenterKeepAspectRatioStayInsideRange( aTargetRange, @@ -979,10 +980,10 @@ void SwVirtFlyDrawObj::addCropHandles(SdrHdlList& rTarget) const // RotGrfFlyFrame: Adapt to possible rotated Graphic contained in FlyFrame if(GetFlyFrame()->Frame().HasArea()) { - const tools::Rectangle aOutRect(GetFlyFrame()->Frame().SVRect()); - const basegfx::B2DRange aTargetRange( - aOutRect.Left(), aOutRect.Top(), - aOutRect.Right(), aOutRect.Bottom()); + // Use InnerBound, OuterBound (same as GetFlyFrame()->Frame().SVRect()) + // may have a distance to InnerBound which needs to be taken into acocunt. + // The Graphic is mapped to InnerBound, as is the rotated Graphic. + const basegfx::B2DRange aTargetRange(getInnerBound()); if(!aTargetRange.isEmpty()) { diff --git a/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml b/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml index 172d8b4d52b5..c1ba2219af1b 100644 --- a/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml +++ b/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml @@ -29,7 +29,7 @@ <toolbar:toolbaritem xlink:href=".uno:RotateLeft"/> <toolbar:toolbaritem xlink:href=".uno:RotateRight"/> <toolbar:toolbaritem xlink:href=".uno:Rotate180" toolbar:visible="false"/> - <toolbar:toolbaritem xlink:href=".uno:RotateReset"/> + <toolbar:toolbaritem xlink:href=".uno:RotateReset" toolbar:visible="false"/> <toolbar:toolbarseparator/> <toolbar:toolbaritem xlink:href=".uno:GrafTransparence"/> <toolbar:toolbarseparator/> diff --git a/sw/uiconfig/swxform/toolbar/graphicobjectbar.xml b/sw/uiconfig/swxform/toolbar/graphicobjectbar.xml index 6e2c6a2b4823..19662053bc76 100644 --- a/sw/uiconfig/swxform/toolbar/graphicobjectbar.xml +++ b/sw/uiconfig/swxform/toolbar/graphicobjectbar.xml @@ -30,8 +30,8 @@ <toolbar:toolbaritem xlink:href=".uno:FlipHorizontal"/> <toolbar:toolbaritem xlink:href=".uno:RotateLeft"/> <toolbar:toolbaritem xlink:href=".uno:RotateRight"/> - <toolbar:toolbaritem xlink:href=".uno:Rotate180"/> - <toolbar:toolbaritem xlink:href=".uno:RotateReset"/> + <toolbar:toolbaritem xlink:href=".uno:Rotate180" toolbar:visible="false"/> + <toolbar:toolbaritem xlink:href=".uno:RotateReset" toolbar:visible="false"/> <toolbar:toolbaritem xlink:href=".uno:Crop"/> <toolbar:toolbarseparator/> <toolbar:toolbaritem xlink:href=".uno:FrameDialog"/> commit 73360bdf0b60370c76d9669502c2b0e5a9d4e504 Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Fri Sep 29 10:42:43 2017 +0200 RotGrfFlyFrame: Implemented Handle Update on rotation change WIth rotaiton being allowed the handle visualisation may be dependent on this, so it is necessary to refresh their visualisation on rotation chnage, e.g. for crop handles Change-Id: I218e326894999381fc4058b7eba432491a0cf23b diff --git a/include/basegfx/matrix/b2dhommatrixtools.hxx b/include/basegfx/matrix/b2dhommatrixtools.hxx index e462bad54b8e..3bc3627dfbf5 100644 --- a/include/basegfx/matrix/b2dhommatrixtools.hxx +++ b/include/basegfx/matrix/b2dhommatrixtools.hxx @@ -229,6 +229,7 @@ namespace basegfx const B2DVector& getScale() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return maScale; } const B2DVector& getTranslate() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return maTranslate; } double getRotate() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return mfRotate; } + double getShearX() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return mfShearX; } }; } // end of namespace utils diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx index 72279ec410a8..3348579bd508 100644 --- a/svx/source/svdraw/svddrgmt.cxx +++ b/svx/source/svdraw/svddrgmt.cxx @@ -595,14 +595,14 @@ void SdrDragMethod::applyCurrentTransformationToSdrObject(SdrObject& rTarget) { // do something special since the object size is in the polygon // break up matrix to get the scale - const basegfx::utils::B2DHomMatrixBufferedDecompose aDecomp(aObjectTransform); + const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aObjectTransform); // get polygon's position and size const basegfx::B2DRange aPolyRange(aObjectPolyPolygon.getB2DRange()); // get the scaling factors (do not mirror, this is in the object transformation) - const double fScaleX(fabs(aDecomp.getScale().getX()) / (basegfx::fTools::equalZero(aPolyRange.getWidth()) ? 1.0 : aPolyRange.getWidth())); - const double fScaleY(fabs(aDecomp.getScale().getY()) / (basegfx::fTools::equalZero(aPolyRange.getHeight()) ? 1.0 : aPolyRange.getHeight())); + const double fScaleX(fabs(aTmpDecomp.getScale().getX()) / (basegfx::fTools::equalZero(aPolyRange.getWidth()) ? 1.0 : aPolyRange.getWidth())); + const double fScaleY(fabs(aTmpDecomp.getScale().getY()) / (basegfx::fTools::equalZero(aPolyRange.getHeight()) ? 1.0 : aPolyRange.getHeight())); // prepare transform matrix for polygon basegfx::B2DHomMatrix aPolyTransform( @@ -3657,16 +3657,16 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/) pObj->TRGetBaseGeometry(aOriginalMatrix, aPolyPolygon); { // correct shear, it comes currently mirrored from TRGetBaseGeometry, can be removed with aw080 - const basegfx::utils::B2DHomMatrixBufferedDecompose aDecomp(aOriginalMatrix); + const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aOriginalMatrix); - if(!basegfx::fTools::equalZero(aDecomp.getShearX())) + if(!basegfx::fTools::equalZero(aTmpDecomp.getShearX())) { bShearCorrected = true; aOriginalMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( - aDecomp.getScale(), - -aDecomp.getShearX(), - aDecomp.getRotate(), - aDecomp.getTranslate()); + aTmpDecomp.getScale(), + -aTmpDecomp.getShearX(), + aTmpDecomp.getRotate(), + aTmpDecomp.getTranslate()); } } @@ -3740,13 +3740,13 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/) // aDiscreteChangeMatrix, go to concrete sizes now. // Create the unrotated original rectangle and the unrotated modified // rectangle as Ranges - const basegfx::utils::B2DHomMatrixBufferedDecompose aDecomp(aOriginalMatrix); + const basegfx::utils::B2DHomMatrixBufferedDecompose aOriginalMatrixDecomp(aOriginalMatrix); // prepare unsheared/unrotated versions of the old and new transformation const basegfx::B2DHomMatrix aOriginalMatrixNoShearNoRotate( basegfx::utils::createScaleTranslateB2DHomMatrix( - basegfx::absolute(aDecomp.getScale()), - aDecomp.getTranslate())); + basegfx::absolute(aOriginalMatrixDecomp.getScale()), + aOriginalMatrixDecomp.getTranslate())); // create the ranges for these basegfx::B2DRange aRangeOriginalNoShearNoRotate(0.0, 0.0, 1.0, 1.0); @@ -3784,13 +3784,13 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/) if(bShearCorrected) { // back-correct shear - const basegfx::utils::B2DHomMatrixBufferedDecompose aDecomp(aNewObjectMatrix); + const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aNewObjectMatrix); aNewObjectMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( - aDecomp.getScale(), - -aDecomp.getShearX(), - aDecomp.getRotate(), - aDecomp.getTranslate()); + aTmpDecomp.getScale(), + -aTmpDecomp.getShearX(), + aTmpDecomp.getRotate(), + aTmpDecomp.getTranslate()); } // apply change to object by applying the unit coordinate change followed diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx index 6a23088246c4..a1154b2977d5 100644 --- a/sw/source/core/doc/notxtfrm.cxx +++ b/sw/source/core/doc/notxtfrm.cxx @@ -626,6 +626,27 @@ void SwNoTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew ) GetItemState( n, false )) { CLEARCACHE + + if(RES_GRFATR_ROTATION == n) + { + // RotGrfFlyFrame: Update Handles in view, these may be rotation-dependent + // (e.g. crop handles) and need a visualisation update + if ( GetNode()->GetNodeType() == SwNodeType::Grf ) + { + SwGrfNode* pNd = static_cast<SwGrfNode*>( GetNode()); + SwViewShell *pVSh = pNd->GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell(); + + if(pVSh) + { + SdrView* pDrawView = pVSh->GetDrawView(); + + if(pDrawView) + { + pDrawView->AdjustMarkHdl(nullptr); + } + } + } + } break; } if( RES_GRFATR_END == n ) // not found commit a6fc51cbe40b98674ade29e090f1b45e1f530062 Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Thu Sep 28 13:08:35 2017 +0200 RotGrfFlyFrame: Encapsulated matrix decomposes Change-Id: I432766970ef06c7d85a0056d3f24280cf2acd47d diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx index 90a6ad41f452..72279ec410a8 100644 --- a/svx/source/svdraw/svddrgmt.cxx +++ b/svx/source/svdraw/svddrgmt.cxx @@ -595,21 +595,20 @@ void SdrDragMethod::applyCurrentTransformationToSdrObject(SdrObject& rTarget) { // do something special since the object size is in the polygon // break up matrix to get the scale - basegfx::B2DTuple aScale; - basegfx::B2DTuple aTranslate; - double fRotate, fShearX; - aObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX); + const basegfx::utils::B2DHomMatrixBufferedDecompose aDecomp(aObjectTransform); // get polygon's position and size const basegfx::B2DRange aPolyRange(aObjectPolyPolygon.getB2DRange()); // get the scaling factors (do not mirror, this is in the object transformation) - const double fScaleX(fabs(aScale.getX()) / (basegfx::fTools::equalZero(aPolyRange.getWidth()) ? 1.0 : aPolyRange.getWidth())); - const double fScaleY(fabs(aScale.getY()) / (basegfx::fTools::equalZero(aPolyRange.getHeight()) ? 1.0 : aPolyRange.getHeight())); + const double fScaleX(fabs(aDecomp.getScale().getX()) / (basegfx::fTools::equalZero(aPolyRange.getWidth()) ? 1.0 : aPolyRange.getWidth())); + const double fScaleY(fabs(aDecomp.getScale().getY()) / (basegfx::fTools::equalZero(aPolyRange.getHeight()) ? 1.0 : aPolyRange.getHeight())); // prepare transform matrix for polygon - basegfx::B2DHomMatrix aPolyTransform(basegfx::utils::createTranslateB2DHomMatrix( - -aPolyRange.getMinX(), -aPolyRange.getMinY())); + basegfx::B2DHomMatrix aPolyTransform( + basegfx::utils::createTranslateB2DHomMatrix( + -aPolyRange.getMinX(), + -aPolyRange.getMinY())); aPolyTransform.scale(fScaleX, fScaleY); // transform the polygon @@ -3658,18 +3657,16 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/) pObj->TRGetBaseGeometry(aOriginalMatrix, aPolyPolygon); { // correct shear, it comes currently mirrored from TRGetBaseGeometry, can be removed with aw080 - basegfx::B2DTuple aScale, aTranslate; - double fRotate(0.0), fShearX(0.0); - aOriginalMatrix.decompose(aScale, aTranslate, fRotate, fShearX); + const basegfx::utils::B2DHomMatrixBufferedDecompose aDecomp(aOriginalMatrix); - if(!basegfx::fTools::equalZero(fShearX)) + if(!basegfx::fTools::equalZero(aDecomp.getShearX())) { bShearCorrected = true; aOriginalMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( - aScale, - -fShearX, - fRotate, - aTranslate); + aDecomp.getScale(), + -aDecomp.getShearX(), + aDecomp.getRotate(), + aDecomp.getTranslate()); } } @@ -3743,17 +3740,13 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/) // aDiscreteChangeMatrix, go to concrete sizes now. // Create the unrotated original rectangle and the unrotated modified // rectangle as Ranges - basegfx::B2DTuple aScale, aTranslate; - double fRotate, fShearX; - - // get access to scale and translate - aOriginalMatrix.decompose(aScale, aTranslate, fRotate, fShearX); + const basegfx::utils::B2DHomMatrixBufferedDecompose aDecomp(aOriginalMatrix); // prepare unsheared/unrotated versions of the old and new transformation const basegfx::B2DHomMatrix aOriginalMatrixNoShearNoRotate( basegfx::utils::createScaleTranslateB2DHomMatrix( - basegfx::absolute(aScale), - aTranslate)); + basegfx::absolute(aDecomp.getScale()), + aDecomp.getTranslate())); // create the ranges for these basegfx::B2DRange aRangeOriginalNoShearNoRotate(0.0, 0.0, 1.0, 1.0); @@ -3791,16 +3784,13 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/) if(bShearCorrected) { // back-correct shear - basegfx::B2DTuple aScale; - basegfx::B2DTuple aTranslate; - double fRotate(0.0), fShearX(0.0); + const basegfx::utils::B2DHomMatrixBufferedDecompose aDecomp(aNewObjectMatrix); - aNewObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX); aNewObjectMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( - aScale, - -fShearX, - fRotate, - aTranslate); + aDecomp.getScale(), + -aDecomp.getShearX(), + aDecomp.getRotate(), + aDecomp.getTranslate()); } // apply change to object by applying the unit coordinate change followed commit d9b16effeda21488911d1b5035f9d3be05731ca2 Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Thu Sep 28 10:20:15 2017 +0200 RotGrfFlyFrame: Adapt Crop functionality to rotated Graphic The FlyFrame which may contain a Graphic needs working Crop, interactive and in core. Adapted this to work with now possible rotation, changed common code in svx which has to handle cases for Draw/Impress/Calc and Writer differently. Tried to use as much in common as possible. Additionally furter adaptions to rotation itself. Change-Id: Ia961e9490e2627c74220b186116f5aa4fcabca78 diff --git a/basegfx/source/matrix/b2dhommatrixtools.cxx b/basegfx/source/matrix/b2dhommatrixtools.cxx index a267b05b96d1..26936aff2e5c 100644 --- a/basegfx/source/matrix/b2dhommatrixtools.cxx +++ b/basegfx/source/matrix/b2dhommatrixtools.cxx @@ -358,6 +358,48 @@ namespace basegfx return aRetval; } + BASEGFX_DLLPUBLIC B2DHomMatrix createRotateAroundCenterKeepAspectRatioStayInsideRange( + const basegfx::B2DRange& rTargetRange, + double fRotate) + { + basegfx::B2DHomMatrix aRetval; + + // RotGrfFlyFrame: Take rotation into account. Rotation is in 10th degrees + if(0.0 != fRotate) + { + // Fit rotated graphic to center of available space, keeping page ratio: + // Adapt scaling ratio of unit object and rotate it + aRetval.scale(1.0, rTargetRange.getHeight() / rTargetRange.getWidth()); + aRetval.rotate(fRotate); + + // get the range to see where we are in unit coordinates + basegfx::B2DRange aFullRange(0.0, 0.0, 1.0, 1.0); + aFullRange.transform(aRetval); + + // detect needed scales in X/Y and choose the smallest for staying inside the + // available space while keeping aspect ratio of the source + const double fScaleX(rTargetRange.getWidth() / aFullRange.getWidth()); + const double fScaleY(rTargetRange.getHeight() / aFullRange.getHeight()); + const double fScaleMin(std::min(fScaleX, fScaleY)); + + // TopLeft to zero, then scale, then move to center of available space + aRetval.translate(-aFullRange.getMinX(), -aFullRange.getMinY()); + aRetval.scale(fScaleMin, fScaleMin); + aRetval.translate( + rTargetRange.getCenterX() - (0.5 * fScaleMin * aFullRange.getWidth()), + rTargetRange.getCenterY() - (0.5 * fScaleMin * aFullRange.getHeight())); + } + else + { + // just scale/translate needed + aRetval *= createScaleTranslateB2DHomMatrix( + rTargetRange.getRange(), + rTargetRange.getMinimum()); + } + + return aRetval; + } + /// special for the case to map from source range to target range B2DHomMatrix createSourceRangeTargetRangeTransform( const B2DRange& rSourceRange, diff --git a/include/basegfx/matrix/b2dhommatrixtools.hxx b/include/basegfx/matrix/b2dhommatrixtools.hxx index c60a6ac96c21..e462bad54b8e 100644 --- a/include/basegfx/matrix/b2dhommatrixtools.hxx +++ b/include/basegfx/matrix/b2dhommatrixtools.hxx @@ -126,6 +126,13 @@ namespace basegfx fRadiant); } + /// special for creating a mapping for a Range rotated around it's center + /// while keeping AspectRatio unchanged and staying inside the given Range + /// by optimally using the available space (no overlap or outside allowed) + BASEGFX_DLLPUBLIC B2DHomMatrix createRotateAroundCenterKeepAspectRatioStayInsideRange( + const basegfx::B2DRange& rTargetRange, + double fRotate); + /// special for the case to map from source range to target range BASEGFX_DLLPUBLIC B2DHomMatrix createSourceRangeTargetRangeTransform( const B2DRange& rSourceRange, diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx index aed40a9f13d1..90a6ad41f452 100644 --- a/svx/source/svdraw/svddrgmt.cxx +++ b/svx/source/svdraw/svddrgmt.cxx @@ -3585,200 +3585,62 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/) { Hide(); - if( DragStat().GetDX()==0 && DragStat().GetDY()==0 ) + if(0 == DragStat().GetDX() && 0 == DragStat().GetDY()) + { + // no change, done return false; + } const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList(); - if( rMarkList.GetMarkCount() != 1 ) + if(1 != rMarkList.GetMarkCount()) + { + // Crop only with single Object selected return false; + } - SdrObject* pSdrObject = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); - - // tdf#34555: in order to implement visual crop in Writer, we need to handle two - // cases: - // EndSdrDrag when called in Impress/Draw/...: pSdrObject is a SdrGrafObj - // EndSdrDrag when called in Writer: pSdrObject is a SwVirtFlyDrawObj - // Main principle: if marked object is not SdrGrafObj, we start a generic handling - // based on virtual methods added to SdrObject, on MM100/Twip coordinates and so on. - // If marked object is SdrGrafObj, we do all the work here with matrix based - // coordinates. - if (dynamic_cast<const SdrGrafObj*>( pSdrObject) == nullptr) { - const bool bUndo = getSdrDragView().IsUndoEnabled(); - if( bUndo ) - { - OUString aUndoStr; - ImpTakeDescriptionStr(STR_DragMethCrop, aUndoStr); - getSdrDragView().BegUndo( aUndoStr ); - getSdrDragView().AddUndo( getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pSdrObject)); - // also need attr undo, the SdrGrafCropItem will be changed - getSdrDragView().AddUndo( getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pSdrObject)); - } - - // We need to produce a reference point and two (X & Y) scales - SdrHdl* pRef1=GetHdlList().GetHdl(SdrHdlKind::UpperLeft); - SdrHdl* pRef2=GetHdlList().GetHdl(SdrHdlKind::LowerRight); - - if (pRef1==nullptr || pRef2==nullptr) - return false; - - tools::Rectangle rect(pRef1->GetPos(),pRef2->GetPos()); - - Point aEnd(DragStat().GetNow()); - Point aStart(DragStat().GetStart()); - Point aRef(rect.Center()); - - // Reference point is the point opposed to the dragged handle - switch(GetDragHdlKind()) - { - case SdrHdlKind::UpperLeft: aRef = rect.BottomRight(); break; - case SdrHdlKind::Upper: aRef = rect.BottomCenter(); DragStat().SetHorFixed(true); break; - case SdrHdlKind::UpperRight: aRef = rect.BottomLeft(); break; - case SdrHdlKind::Left : aRef = rect.RightCenter(); DragStat().SetVerFixed(true); break; - case SdrHdlKind::Right: aRef = rect.LeftCenter(); DragStat().SetVerFixed(true); break; - case SdrHdlKind::LowerLeft: aRef = rect.TopRight(); break; - case SdrHdlKind::Lower: aRef = rect.TopCenter(); DragStat().SetHorFixed(true); break; - case SdrHdlKind::LowerRight: aRef = rect.TopLeft(); break; - default: break; - } - - // By default, scale is new size / old size - long nXDiv = aStart.X()-aRef.X(); if (nXDiv==0) nXDiv=1; - long nYDiv = aStart.Y()-aRef.Y(); if (nYDiv==0) nYDiv=1; - long nXMul = aEnd.X()-aRef.X(); - long nYMul = aEnd.Y()-aRef.Y(); - - if (nXDiv<0) - { - nXDiv=-nXDiv; - nXMul=-nXMul; - } - - if (nYDiv<0) - { - nYDiv=-nYDiv; - nYMul=-nYMul; - } - - // Take ortho into account. - bool bXNeg=nXMul<0; if (bXNeg) nXMul=-nXMul; - bool bYNeg=nYMul<0; if (bYNeg) nYMul=-nYMul; - bool bOrtho=getSdrDragView().IsOrtho() || !getSdrDragView().IsResizeAllowed(); - - if (!DragStat().IsHorFixed() && !DragStat().IsVerFixed()) - { - if (std::abs(nXDiv)<=1 || std::abs(nYDiv)<=1) - bOrtho=false; - - if (bOrtho) - { - if ((Fraction(nXMul,nXDiv)>Fraction(nYMul,nYDiv)) !=getSdrDragView().IsBigOrtho()) - { - nXMul=nYMul; - nXDiv=nYDiv; - } - else - { - nYMul=nXMul; - nYDiv=nXDiv; - } - } - } - else - { - if (bOrtho) - { - if (DragStat().IsHorFixed()) - { - bXNeg=false; - nXMul=nYMul; - nXDiv=nYDiv; - } - - if (DragStat().IsVerFixed()) - { - bYNeg=false; - nYMul=nXMul; - nYDiv=nXDiv; - } - } - else - { - if (DragStat().IsHorFixed()) - { - bXNeg=false; - nXMul=1; - nXDiv=1; - } + // prepare for SdrGrafObj or others. This code has to work with usual + // SdrGrafObj's from Draw/Impress/Calc, but also with SdrObjects from + // Writer. It would be better to handle this in Writer directly, but + // there are currently no easy mechanisms to plug an alternative interaction + // from there + SdrObject* pSdrObject = rMarkList.GetMark(0)->GetMarkedSdrObj(); + struct SdrObjDeleter { void operator()(SdrObject* b) { SdrObject::Free(b); }}; + std::unique_ptr< SdrObject, SdrObjDeleter > pFullDragClone; + bool bExternal(false); + SdrObject* pExternalSdrObject(nullptr); - if (DragStat().IsVerFixed()) - { - bYNeg=false; - nYMul=1; - nYDiv=1; - } - } - } - Fraction aXFact(nXMul,nXDiv); - Fraction aYFact(nYMul,nYDiv); - Fraction aMaxFact(0x7FFFFFFF,1); + // RotGrfFlyFrame: Crop decision for DrawingLayer/Writer now + // locally, no two-in-one methods any more + if (nullptr != pSdrObject && dynamic_cast< const SdrGrafObj* >(pSdrObject) == nullptr) + { + // If Writer, get the already offered for interaction SdrGrafObj + // and set up for using that replacement object that contains the + // real transformation. That SdrObject is owned and has to be deleted, + // so use a std::unique_ptr with special handling for the protected + // SDrObject destructor + pFullDragClone.reset(pSdrObject->getFullDragClone()); - if (bOrtho) + if(pFullDragClone && dynamic_cast< SdrGrafObj* >(pFullDragClone.get())) { - if (aXFact>aMaxFact) - { - aXFact=aMaxFact; - aYFact=aMaxFact; - } - - if (aYFact>aMaxFact) - { - aXFact=aMaxFact; - aYFact=aMaxFact; - } + bExternal = true; + pExternalSdrObject = pSdrObject; + pSdrObject = pFullDragClone.get(); } - - if (bXNeg) - aXFact=Fraction(-aXFact.GetNumerator(),aXFact.GetDenominator()); - - if (bYNeg) - aYFact=Fraction(-aYFact.GetNumerator(),aYFact.GetDenominator()); - - // With Ref point (opposed to dragged point), X scale and Y scale, - // we call crop (virtual method) on pSdrObject which calls VirtFlyDrawObj - // crop - pSdrObject->Crop(aRef, aXFact, aYFact); - - if( bUndo ) - getSdrDragView().EndUndo(); - - // Job's done - return true; } - // This part of code handles the case where pSdrObject is SdrGrafObj - + // get and check for SdrGrafObj now SdrGrafObj* pObj = dynamic_cast<SdrGrafObj*>( pSdrObject ); - if( !pObj || (pObj->GetGraphicType() == GraphicType::NONE) || (pObj->GetGraphicType() == GraphicType::Default) ) - return false; - const GraphicObject& rGraphicObject = pObj->GetGraphicObject(); - const MapMode aMapMode100thmm(MapUnit::Map100thMM); - Size aGraphicSize(rGraphicObject.GetPrefSize()); - - if( MapUnit::MapPixel == rGraphicObject.GetPrefMapMode().GetMapUnit() ) - aGraphicSize = Application::GetDefaultDevice()->PixelToLogic( aGraphicSize, aMapMode100thmm ); - else - aGraphicSize = OutputDevice::LogicToLogic( aGraphicSize, rGraphicObject.GetPrefMapMode(), aMapMode100thmm); - - if( aGraphicSize.Width() == 0 || aGraphicSize.Height() == 0 ) + if(!pObj) + { return false; + } - const SdrGrafCropItem& rOldCrop = static_cast<const SdrGrafCropItem&>(pObj->GetMergedItem(SDRATTR_GRAFCROP)); - - const bool bUndo = getSdrDragView().IsUndoEnabled(); + // no undo for external needed, done there + const bool bUndo(!bExternal && getSdrDragView().IsUndoEnabled()); - if( bUndo ) + if(bUndo) { OUString aUndoStr; ImpTakeDescriptionStr(STR_DragMethCrop, aUndoStr); @@ -3789,20 +3651,15 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/) getSdrDragView().AddUndo( getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj)); } - // new part to commute the user's drag activities // get the original objects transformation basegfx::B2DHomMatrix aOriginalMatrix; basegfx::B2DPolyPolygon aPolyPolygon; bool bShearCorrected(false); - - // get transformation from object pObj->TRGetBaseGeometry(aOriginalMatrix, aPolyPolygon); { // correct shear, it comes currently mirrored from TRGetBaseGeometry, can be removed with aw080 - basegfx::B2DTuple aScale; - basegfx::B2DTuple aTranslate; + basegfx::B2DTuple aScale, aTranslate; double fRotate(0.0), fShearX(0.0); - aOriginalMatrix.decompose(aScale, aTranslate, fRotate, fShearX); if(!basegfx::fTools::equalZero(fShearX)) @@ -3816,11 +3673,6 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/) } } - // invert it to be able to work on unit coordinates - basegfx::B2DHomMatrix aInverse(aOriginalMatrix); - - aInverse.invert(); - // generate start point of original drag vector in unit coordinates (the // vis-a-vis of the drag point) basegfx::B2DPoint aLocalStart(0.0, 0.0); @@ -3839,7 +3691,10 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/) default: break; } - // create the current drag position in unit coordinates + // create the current drag position in unit coordinates. To get there, + // transform back the DragPoint to UnitCoordinates + basegfx::B2DHomMatrix aInverse(aOriginalMatrix); + aInverse.invert(); basegfx::B2DPoint aLocalCurrent(aInverse * basegfx::B2DPoint(DragStat().GetNow().X(), DragStat().GetNow().Y())); // if one of the edge handles is used, limit to X or Y drag only @@ -3884,48 +3739,18 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/) } } - // preparematrix to apply to object; evtl. back-correct shear - basegfx::B2DHomMatrix aNewObjectMatrix(aOriginalMatrix * aDiscreteChangeMatrix); - - if(bShearCorrected) - { - // back-correct shear - basegfx::B2DTuple aScale; - basegfx::B2DTuple aTranslate; - double fRotate(0.0), fShearX(0.0); - - aNewObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX); - aNewObjectMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( - aScale, - -fShearX, - fRotate, - aTranslate); - } - - // apply change to object by applying the unit coordinate change followed - // by the original change - pObj->TRSetBaseGeometry(aNewObjectMatrix, aPolyPolygon); - - // the following old code uses aOldRect/aNewRect to calculate the crop change for - // the crop item. It implies unrotated objects, so create the unrotated original - // rectangle and the unrotated modified rectangle. Latter can in case of shear and/or - // rotation not be fetched by using - - //Rectangle aNewRect( pObj->GetLogicRect() ); - - // as it was done before because the top-left of that new rect *will* have an offset - // caused by the evtl. existing shear and/or rotation, so calculate a unrotated - // rectangle how it would be as a result when applying the unit coordinate change - // to the unrotated original transformation. - basegfx::B2DTuple aScale; - basegfx::B2DTuple aTranslate; + // We now have the whole executed Crop in UnitCoordinates in + // aDiscreteChangeMatrix, go to concrete sizes now. + // Create the unrotated original rectangle and the unrotated modified + // rectangle as Ranges + basegfx::B2DTuple aScale, aTranslate; double fRotate, fShearX; // get access to scale and translate aOriginalMatrix.decompose(aScale, aTranslate, fRotate, fShearX); // prepare unsheared/unrotated versions of the old and new transformation - const basegfx::B2DHomMatrix aMatrixOriginalNoShearNoRotate( + const basegfx::B2DHomMatrix aOriginalMatrixNoShearNoRotate( basegfx::utils::createScaleTranslateB2DHomMatrix( basegfx::absolute(aScale), aTranslate)); @@ -3933,55 +3758,129 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/) // create the ranges for these basegfx::B2DRange aRangeOriginalNoShearNoRotate(0.0, 0.0, 1.0, 1.0); basegfx::B2DRange aRangeNewNoShearNoRotate(0.0, 0.0, 1.0, 1.0); + aRangeOriginalNoShearNoRotate.transform(aOriginalMatrixNoShearNoRotate); + aRangeNewNoShearNoRotate.transform(aOriginalMatrixNoShearNoRotate * aDiscreteChangeMatrix); + + if(bExternal) + { + // With Ref point (opposed to dragged point), X scale and Y scale, + // we call crop (virtual method) on pSdrObject which calls VirtFlyDrawObj + // crop. aRef needs to be adapted to concrete Object's boundaries which + // is different from Crop-Ranges. This is because the Graphic and it's + // SdrObject representaion is inside the FlyFrame, but not identical + // with it. + const tools::Rectangle& rOutRect(pExternalSdrObject->GetCurrentBoundRect()); + const basegfx::B2DHomMatrix aExternalTransform( + basegfx::utils::createScaleTranslateB2DHomMatrix( + rOutRect.getWidth(), rOutRect.getHeight(), + rOutRect.Left(), rOutRect.Top())); + const basegfx::B2DPoint aRef(aExternalTransform * aLocalStart); + const double fScaleX(aRangeNewNoShearNoRotate.getWidth() / aRangeOriginalNoShearNoRotate.getWidth()); + const double fScaleY(aRangeNewNoShearNoRotate.getHeight() / aRangeOriginalNoShearNoRotate.getHeight()); + + pExternalSdrObject->Crop( + Point(basegfx::fround(aRef.getX()), basegfx::fround(aRef.getY())), + Fraction(fScaleX), + Fraction(fScaleY)); + } + else + { + // prepare matrix to apply to object; evtl. back-correct shear + basegfx::B2DHomMatrix aNewObjectMatrix(aOriginalMatrix * aDiscreteChangeMatrix); + + if(bShearCorrected) + { + // back-correct shear + basegfx::B2DTuple aScale; + basegfx::B2DTuple aTranslate; + double fRotate(0.0), fShearX(0.0); - aRangeOriginalNoShearNoRotate.transform(aMatrixOriginalNoShearNoRotate); - aRangeNewNoShearNoRotate.transform(aMatrixOriginalNoShearNoRotate * aDiscreteChangeMatrix); - - // extract the old Rectangle structures - tools::Rectangle aOldRect( - basegfx::fround(aRangeOriginalNoShearNoRotate.getMinX()), - basegfx::fround(aRangeOriginalNoShearNoRotate.getMinY()), - basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxX()), - basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxY())); - tools::Rectangle aNewRect( - basegfx::fround(aRangeNewNoShearNoRotate.getMinX()), - basegfx::fround(aRangeNewNoShearNoRotate.getMinY()), - basegfx::fround(aRangeNewNoShearNoRotate.getMaxX()), - basegfx::fround(aRangeNewNoShearNoRotate.getMaxY())); - - // continue with the old original stuff - if (!aOldRect.GetWidth() || !aOldRect.GetHeight()) - throw o3tl::divide_by_zero(); - - double fScaleX = ( aGraphicSize.Width() - rOldCrop.GetLeft() - rOldCrop.GetRight() ) / (double)aOldRect.GetWidth(); - double fScaleY = ( aGraphicSize.Height() - rOldCrop.GetTop() - rOldCrop.GetBottom() ) / (double)aOldRect.GetHeight(); - - sal_Int32 nDiffLeft = aNewRect.Left() - aOldRect.Left(); - sal_Int32 nDiffTop = aNewRect.Top() - aOldRect.Top(); - sal_Int32 nDiffRight = aNewRect.Right() - aOldRect.Right(); - sal_Int32 nDiffBottom = aNewRect.Bottom() - aOldRect.Bottom(); - - if(pObj->IsMirrored()) - { - // mirrored X or Y, for old stuff, exchange X - // check for aw080 - sal_Int32 nTmp(nDiffLeft); - nDiffLeft = -nDiffRight; - nDiffRight = -nTmp; - } - - sal_Int32 nLeftCrop = static_cast<sal_Int32>( rOldCrop.GetLeft() + nDiffLeft * fScaleX ); - sal_Int32 nTopCrop = static_cast<sal_Int32>( rOldCrop.GetTop() + nDiffTop * fScaleY ); - sal_Int32 nRightCrop = static_cast<sal_Int32>( rOldCrop.GetRight() - nDiffRight * fScaleX ); - sal_Int32 nBottomCrop = static_cast<sal_Int32>( rOldCrop.GetBottom() - nDiffBottom * fScaleY ); - - SfxItemPool& rPool = getSdrDragView().GetModel()->GetItemPool(); - SfxItemSet aSet( rPool, svl::Items<SDRATTR_GRAFCROP, SDRATTR_GRAFCROP>{} ); - aSet.Put( SdrGrafCropItem( nLeftCrop, nTopCrop, nRightCrop, nBottomCrop ) ); - getSdrDragView().SetAttributes( aSet, false ); - - if( bUndo ) + aNewObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX); + aNewObjectMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( + aScale, + -fShearX, + fRotate, + aTranslate); + } + + // apply change to object by applying the unit coordinate change followed + // by the original change + pObj->TRSetBaseGeometry(aNewObjectMatrix, aPolyPolygon); + + // extract the old Rectangle structures + tools::Rectangle aOldRect( + basegfx::fround(aRangeOriginalNoShearNoRotate.getMinX()), + basegfx::fround(aRangeOriginalNoShearNoRotate.getMinY()), + basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxX()), + basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxY())); + tools::Rectangle aNewRect( + basegfx::fround(aRangeNewNoShearNoRotate.getMinX()), + basegfx::fround(aRangeNewNoShearNoRotate.getMinY()), + basegfx::fround(aRangeNewNoShearNoRotate.getMaxX()), + basegfx::fround(aRangeNewNoShearNoRotate.getMaxY())); + + // continue with the old original stuff + if (!aOldRect.GetWidth() || !aOldRect.GetHeight()) + { + throw o3tl::divide_by_zero(); + } + + if((pObj->GetGraphicType() == GraphicType::NONE) || (pObj->GetGraphicType() == GraphicType::Default)) + { + return false; + } + + const GraphicObject& rGraphicObject = pObj->GetGraphicObject(); + const MapMode aMapMode100thmm(MapUnit::Map100thMM); + Size aGraphicSize(rGraphicObject.GetPrefSize()); + + if(MapUnit::MapPixel == rGraphicObject.GetPrefMapMode().GetMapUnit()) + { + aGraphicSize = Application::GetDefaultDevice()->PixelToLogic(aGraphicSize, aMapMode100thmm); + } + else + { + aGraphicSize = OutputDevice::LogicToLogic(aGraphicSize, rGraphicObject.GetPrefMapMode(), aMapMode100thmm); + } + + if(0 == aGraphicSize.Width() || 0 == aGraphicSize.Height()) + { + return false; + } + + const SdrGrafCropItem& rOldCrop = static_cast<const SdrGrafCropItem&>(pObj->GetMergedItem(SDRATTR_GRAFCROP)); + double fScaleX = ( aGraphicSize.Width() - rOldCrop.GetLeft() - rOldCrop.GetRight() ) / (double)aOldRect.GetWidth(); + double fScaleY = ( aGraphicSize.Height() - rOldCrop.GetTop() - rOldCrop.GetBottom() ) / (double)aOldRect.GetHeight(); + + sal_Int32 nDiffLeft = aNewRect.Left() - aOldRect.Left(); + sal_Int32 nDiffTop = aNewRect.Top() - aOldRect.Top(); + sal_Int32 nDiffRight = aNewRect.Right() - aOldRect.Right(); + sal_Int32 nDiffBottom = aNewRect.Bottom() - aOldRect.Bottom(); + + if(pObj->IsMirrored()) + { + // mirrored X or Y, for old stuff, exchange X + // check for aw080 + sal_Int32 nTmp(nDiffLeft); + nDiffLeft = -nDiffRight; + nDiffRight = -nTmp; + } + + sal_Int32 nLeftCrop = static_cast<sal_Int32>( rOldCrop.GetLeft() + nDiffLeft * fScaleX ); + sal_Int32 nTopCrop = static_cast<sal_Int32>( rOldCrop.GetTop() + nDiffTop * fScaleY ); + sal_Int32 nRightCrop = static_cast<sal_Int32>( rOldCrop.GetRight() - nDiffRight * fScaleX ); + sal_Int32 nBottomCrop = static_cast<sal_Int32>( rOldCrop.GetBottom() - nDiffBottom * fScaleY ); + + SfxItemPool& rPool = getSdrDragView().GetModel()->GetItemPool(); + SfxItemSet aSet( rPool, svl::Items<SDRATTR_GRAFCROP, SDRATTR_GRAFCROP>{} ); + aSet.Put( SdrGrafCropItem( nLeftCrop, nTopCrop, nRightCrop, nBottomCrop ) ); + getSdrDragView().SetAttributes( aSet, false ); + } + + if(bUndo) + { getSdrDragView().EndUndo(); + } return true; } diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx index 42eac79c45ee..6a23088246c4 100644 --- a/sw/source/core/doc/notxtfrm.cxx +++ b/sw/source/core/doc/notxtfrm.cxx @@ -757,53 +757,24 @@ bool paintUsingPrimitivesHelper( return false; } -void paintGraphicUsingPrimitivesHelper(vcl::RenderContext & rOutputDevice, - GraphicObject const& rGrfObj, GraphicAttr const& rGraphicAttr, - SwRect const& rAlignedGrfArea) +void paintGraphicUsingPrimitivesHelper( + vcl::RenderContext & rOutputDevice, + GraphicObject const& rGrfObj, + GraphicAttr const& rGraphicAttr, + SwRect const& rAlignedGrfArea) { - // unify using GraphicPrimitive2D + // RotGrfFlyFrame: unify using GraphicPrimitive2D // -> the primitive handles all crop and mirror stuff // -> the primitive renderer will create the needed pdf export data // -> if bitmap content, it will be cached system-dependent const basegfx::B2DRange aTargetRange( rAlignedGrfArea.Left(), rAlignedGrfArea.Top(), rAlignedGrfArea.Right(), rAlignedGrfArea.Bottom()); - basegfx::B2DHomMatrix aTargetTransform; - - // RotGrfFlyFrame: Take rotation into account. Rotation is in 10th degrees - if(0 != rGraphicAttr.GetRotation()) - { - // Fit rotated graphic to center of available space, keeping page ratio: - // Adapt scaling ratio of unit object and rotate it - const double fRotate(static_cast< double >(-rGraphicAttr.GetRotation()) * (M_PI/1800.0)); - aTargetTransform.scale(1.0, aTargetRange.getHeight() / aTargetRange.getWidth()); - aTargetTransform.rotate(fRotate); - - // get the range to see where we are in unit coordinates - basegfx::B2DRange aFullRange(0.0, 0.0, 1.0, 1.0); - aFullRange.transform(aTargetTransform); - - // detect needed scales in X/Y and choose the smallest for staying inside the - // available space while keeping aspect ratio of the source - const double fScaleX(aTargetRange.getWidth() / aFullRange.getWidth()); - const double fScaleY(aTargetRange.getHeight() / aFullRange.getHeight()); - const double fScaleMin(std::min(fScaleX, fScaleY)); - - // TopLeft to zero, then scale, then move to center of available space - aTargetTransform.translate(-aFullRange.getMinX(), -aFullRange.getMinY()); - aTargetTransform.scale(fScaleMin, fScaleMin); - aTargetTransform.translate( - aTargetRange.getCenterX() - (0.5 * fScaleMin * aFullRange.getWidth()), - aTargetRange.getCenterY() - (0.5 * fScaleMin * aFullRange.getHeight())); - } - else - { - // just scale/translate needed - aTargetTransform *= basegfx::utils::createScaleTranslateB2DHomMatrix( - aTargetRange.getRange(), - aTargetRange.getMinimum()); - } - + const double fRotate(static_cast< double >(-rGraphicAttr.GetRotation()) * (M_PI/1800.0)); + const basegfx::B2DHomMatrix aTargetTransform( + basegfx::utils::createRotateAroundCenterKeepAspectRatioStayInsideRange( + aTargetRange, + fRotate)); drawinglayer::primitive2d::Primitive2DContainer aContent(1); bool bDone(false); diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx index 0696af0e59d1..358085bd2760 100644 --- a/sw/source/core/draw/dflyobj.cxx +++ b/sw/source/core/draw/dflyobj.cxx @@ -59,6 +59,8 @@ #include <drawinglayer/primitive2d/baseprimitive2d.hxx> #include <sw_primitivetypes2d.hxx> #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <notxtfrm.hxx> using namespace ::com::sun::star; @@ -920,20 +922,96 @@ void SwVirtFlyDrawObj::Crop(const Point& rRef, const Fraction& xFact, const Frac GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false); } -void SwVirtFlyDrawObj::addCropHandles(SdrHdlList& rTarget) const +// RotGrfFlyFrame: Helper to access possible rotation of Graphic contained in FlyFrame +sal_uInt16 SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame() const { - tools::Rectangle aRect(GetSnapRect()); + sal_uInt16 nRetval(0); + const SwNoTextFrame* pNoTx = dynamic_cast< const SwNoTextFrame* >(GetFlyFrame()->Lower()); - if(!aRect.IsEmpty()) + if(pNoTx) { - rTarget.AddHdl(new SdrCropHdl(aRect.TopLeft() , SdrHdlKind::UpperLeft, 0, 0)); - rTarget.AddHdl(new SdrCropHdl(aRect.TopCenter() , SdrHdlKind::Upper, 0, 0)); - rTarget.AddHdl(new SdrCropHdl(aRect.TopRight() , SdrHdlKind::UpperRight, 0, 0)); - rTarget.AddHdl(new SdrCropHdl(aRect.LeftCenter() , SdrHdlKind::Left , 0, 0)); - rTarget.AddHdl(new SdrCropHdl(aRect.RightCenter() , SdrHdlKind::Right, 0, 0)); - rTarget.AddHdl(new SdrCropHdl(aRect.BottomLeft() , SdrHdlKind::LowerLeft, 0, 0)); - rTarget.AddHdl(new SdrCropHdl(aRect.BottomCenter(), SdrHdlKind::Lower, 0, 0)); - rTarget.AddHdl(new SdrCropHdl(aRect.BottomRight() , SdrHdlKind::LowerRight, 0, 0)); + SwNoTextNode& rNoTNd = const_cast< SwNoTextNode& >(*static_cast<const SwNoTextNode*>(pNoTx->GetNode())); + SwGrfNode* pGrfNd = rNoTNd.GetGrfNode(); + + if(nullptr != pGrfNd) + { + const SwAttrSet& rSet = pGrfNd->GetSwAttrSet(); + const SwRotationGrf& rRotation = rSet.GetRotationGrf(); + + nRetval = rRotation.GetValue(); + } + } + + return nRetval; +} + +SdrObject* SwVirtFlyDrawObj::getFullDragClone() const +{ + // call parent + SdrObject* pRetval = SdrVirtObj::getFullDragClone(); + + if(pRetval) + { + // RotGrfFlyFrame: Add transformation to placeholder object + const sal_uInt16 nRotation(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame()); + + if(0 != nRotation) + { + const double fRotate(static_cast< double >(-nRotation) * (M_PI/1800.0)); + const tools::Rectangle aOutRect(GetFlyFrame()->Frame().SVRect()); + const basegfx::B2DRange aTargetRange( + aOutRect.Left(), aOutRect.Top(), + aOutRect.Right(), aOutRect.Bottom()); + const basegfx::B2DHomMatrix aTargetTransform( + basegfx::utils::createRotateAroundCenterKeepAspectRatioStayInsideRange( + aTargetRange, + fRotate)); + + pRetval->TRSetBaseGeometry(aTargetTransform, basegfx::B2DPolyPolygon()); + } + } + + return pRetval; +} + +void SwVirtFlyDrawObj::addCropHandles(SdrHdlList& rTarget) const +{ + // RotGrfFlyFrame: Adapt to possible rotated Graphic contained in FlyFrame + if(GetFlyFrame()->Frame().HasArea()) + { + const tools::Rectangle aOutRect(GetFlyFrame()->Frame().SVRect()); + const basegfx::B2DRange aTargetRange( + aOutRect.Left(), aOutRect.Top(), + aOutRect.Right(), aOutRect.Bottom()); + + if(!aTargetRange.isEmpty()) + { + const sal_uInt16 nRotation(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame()); + const double fRotate(static_cast< double >(-nRotation) * (M_PI/1800.0)); + const basegfx::B2DHomMatrix aTargetTransform( + basegfx::utils::createRotateAroundCenterKeepAspectRatioStayInsideRange( + aTargetRange, + fRotate)); + basegfx::B2DPoint aPos; + const double fShearX(0.0); + + aPos = aTargetTransform * basegfx::B2DPoint(0.0, 0.0); + rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::UpperLeft, fShearX, fRotate)); + aPos = aTargetTransform * basegfx::B2DPoint(0.5, 0.0); + rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Upper, fShearX, fRotate)); + aPos = aTargetTransform * basegfx::B2DPoint(1.0, 0.0); + rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::UpperRight, fShearX, fRotate)); + aPos = aTargetTransform * basegfx::B2DPoint(0.0, 0.5); + rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Left , fShearX, fRotate)); + aPos = aTargetTransform * basegfx::B2DPoint(1.0, 0.5); + rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Right, fShearX, fRotate)); + aPos = aTargetTransform * basegfx::B2DPoint(0.0, 1.0); + rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::LowerLeft, fShearX, fRotate)); + aPos = aTargetTransform * basegfx::B2DPoint(0.5, 1.0); + rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Lower, fShearX, fRotate)); + aPos = aTargetTransform * basegfx::B2DPoint(1.0, 1.0); + rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::LowerRight, fShearX, fRotate)); + } } } diff --git a/sw/source/core/inc/dflyobj.hxx b/sw/source/core/inc/dflyobj.hxx index 9368eb893b07..528edc8aff39 100644 --- a/sw/source/core/inc/dflyobj.hxx +++ b/sw/source/core/inc/dflyobj.hxx @@ -58,6 +58,10 @@ class SwVirtFlyDrawObj : public SdrVirtObj private: SwFlyFrame *m_pFlyFrame; + // RotGrfFlyFrame: Helper to acces sthe rotation angle (in 10th degrees, left-handed) + // of a GraphicFrame + sal_uInt16 getPossibleRotationFromFraphicFrame() const; + protected: // AW: Need own sdr::contact::ViewContact since AnchorPos from parent is // not used but something own (top left of new SnapRect minus top left @@ -102,6 +106,9 @@ public: virtual void Crop(const Point& rRef, const Fraction& xFact, const Fraction& yFact) override; virtual void addCropHandles(SdrHdlList& rTarget) const override; + // FullDrag support + virtual SdrObject* getFullDragClone() const override; + const SwFrameFormat *GetFormat() const; SwFrameFormat *GetFormat(); diff --git a/sw/source/core/inc/frmtool.hxx b/sw/source/core/inc/frmtool.hxx index 305c8ffb5495..f0351fa6de29 100644 --- a/sw/source/core/inc/frmtool.hxx +++ b/sw/source/core/inc/frmtool.hxx @@ -72,10 +72,11 @@ bool DrawFillAttributes( const basegfx::utils::B2DClipState& rClipState, OutputDevice& rOut); +// RotGrfFlyFrame: Adapted to rotation void paintGraphicUsingPrimitivesHelper( - OutputDevice & rOutputDevice, - GraphicObject const& rGraphicObj, GraphicAttr const& rGraphicAttr, - SwRect const& rAlignedGrfArea); + OutputDevice & rOutputDevice, + GraphicObject const& rGraphicObj, GraphicAttr const& rGraphicAttr, + SwRect const& rAlignedGrfArea); // method to align rectangle. // Created declaration here to avoid <extern> declarations commit 4ddd74e2d119eb7b25df75a65fcb214ce08ec672 Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Tue Sep 26 15:41:23 2017 +0200 RotGrfFlyFrame: Minimal working rotation solution This version allows rotation (in 10th degrees) and perserves it over save/load cycles. Rotation of multiples of 90 degree behave close to original except not changing the contained Graphic and being adaptable to all kinds of graphic. The rotated Graphic is displayed centered and under preserved AspectRatio in the available frame space (so no rotation, 180 degree is identical, 90/-90 is identical with 1:1 ratio of the graphic) Change-Id: I54b3385f709ee0d34a55324aca919dcd2ce0c009 diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx index a35f679d10be..42eac79c45ee 100644 --- a/sw/source/core/doc/notxtfrm.cxx +++ b/sw/source/core/doc/notxtfrm.cxx @@ -773,16 +773,36 @@ void paintGraphicUsingPrimitivesHelper(vcl::RenderContext & rOutputDevice, // RotGrfFlyFrame: Take rotation into account. Rotation is in 10th degrees if(0 != rGraphicAttr.GetRotation()) { + // Fit rotated graphic to center of available space, keeping page ratio: + // Adapt scaling ratio of unit object and rotate it const double fRotate(static_cast< double >(-rGraphicAttr.GetRotation()) * (M_PI/1800.0)); - aTargetTransform.translate(-0.5, -0.5); + aTargetTransform.scale(1.0, aTargetRange.getHeight() / aTargetRange.getWidth()); aTargetTransform.rotate(fRotate); - aTargetTransform.translate(0.5, 0.5); - } - // needed scale/translate - aTargetTransform *= basegfx::utils::createScaleTranslateB2DHomMatrix( - aTargetRange.getRange(), - aTargetRange.getMinimum()); + // get the range to see where we are in unit coordinates + basegfx::B2DRange aFullRange(0.0, 0.0, 1.0, 1.0); + aFullRange.transform(aTargetTransform); + + // detect needed scales in X/Y and choose the smallest for staying inside the + // available space while keeping aspect ratio of the source + const double fScaleX(aTargetRange.getWidth() / aFullRange.getWidth()); + const double fScaleY(aTargetRange.getHeight() / aFullRange.getHeight()); + const double fScaleMin(std::min(fScaleX, fScaleY)); + + // TopLeft to zero, then scale, then move to center of available space + aTargetTransform.translate(-aFullRange.getMinX(), -aFullRange.getMinY()); + aTargetTransform.scale(fScaleMin, fScaleMin); + aTargetTransform.translate( + aTargetRange.getCenterX() - (0.5 * fScaleMin * aFullRange.getWidth()), + aTargetRange.getCenterY() - (0.5 * fScaleMin * aFullRange.getHeight())); + } + else + { + // just scale/translate needed + aTargetTransform *= basegfx::utils::createScaleTranslateB2DHomMatrix( + aTargetRange.getRange(), + aTargetRange.getMinimum()); + } drawinglayer::primitive2d::Primitive2DContainer aContent(1); bool bDone(false); diff --git a/sw/source/uibase/frmdlg/frmmgr.cxx b/sw/source/uibase/frmdlg/frmmgr.cxx index fdc883b6a22a..c73238be62ea 100644 --- a/sw/source/uibase/frmdlg/frmmgr.cxx +++ b/sw/source/uibase/frmdlg/frmmgr.cxx @@ -46,10 +46,15 @@ using namespace ::com::sun::star; static sal_uInt16 aFrameMgrRange[] = { - RES_FRMATR_BEGIN, RES_FRMATR_END-1, + RES_FRMATR_BEGIN, RES_FRMATR_END-1, // 87-129 + + // RotGrfFlyFrame: Support here, but seems not to be + // added in range of m_pOwnSh->GetFlyFrameAttr result + // (see below). Tried to find, but could not identify + RES_GRFATR_ROTATION, RES_GRFATR_ROTATION, // 132 // FillAttribute support - XATTR_FILL_FIRST, XATTR_FILL_LAST, + XATTR_FILL_FIRST, XATTR_FILL_LAST, // 1014-1033 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER, FN_SET_FRM_NAME, FN_SET_FRM_NAME, @@ -569,13 +574,17 @@ void SwFlyFrameAttrMgr::SetHeightSizeType( SwFrameSize eType ) m_aSet.Put( aSize ); } -void SwFlyFrameAttrMgr::SetRotation(sal_uInt32 nOld, sal_uInt32 nNew, Size aUnrotatedSize) +void SwFlyFrameAttrMgr::SetRotation(sal_uInt16 nOld, sal_uInt16 nNew, const Size& rUnrotatedSize) { - // RotGrfFlyFrame: Central handling of real change of rotation here. Adaption of pos/size - // may be wanted in the future + // RotGrfFlyFrame: Central handling of real change of rotation here, all adaptions use this. + // Adaption of pos/size may be wanted in the future. Already tried to keep last SIze in + // UnrotatedSize in the SwRotationGrf Item, but this will lead to various problems. Also tried + // to use m_aSet.Put(...) as in other methods (also read methods for Rotation/UnrotatedSize) but + // somehow the needed ID (RES_GRFATR_ROTATION) is *not* in the SfxItemSet of the Frame, so for + // now set directly. Undo/Redo is preserved by AttributeChange if(nOld != nNew) { - m_pOwnSh->SetAttrItem(SwRotationGrf(static_cast<sal_uInt16>(nNew), aUnrotatedSize)); + m_pOwnSh->SetAttrItem(SwRotationGrf(nNew, rUnrotatedSize)); } } diff --git a/sw/source/uibase/inc/frmmgr.hxx b/sw/source/uibase/inc/frmmgr.hxx index cdc3680ab894..e0f939ff2223 100644 --- a/sw/source/uibase/inc/frmmgr.hxx +++ b/sw/source/uibase/inc/frmmgr.hxx @@ -93,7 +93,7 @@ public: void SetHeightSizeType(SwFrameSize eType); // rotation - void SetRotation(sal_uInt32 nOld, sal_uInt32 nNew, Size aUnrotatedSize); + void SetRotation(sal_uInt16 nOld, sal_uInt16 nNew, const Size& rUnrotatedSize); // space to content void SetLRSpace( long nLeft, diff --git a/sw/source/uibase/shells/grfsh.cxx b/sw/source/uibase/shells/grfsh.cxx index 7b2e034ae670..0914846b7857 100644 --- a/sw/source/uibase/shells/grfsh.cxx +++ b/sw/source/uibase/shells/grfsh.cxx @@ -893,12 +893,6 @@ void SwGrfShell::GetAttrState(SfxItemSet &rSet) void SwGrfShell::ExecuteRotation(SfxRequest const &rReq) { // RotGrfFlyFrame: Modify rotation attribute instead of manipulating the graphic - SwWrtShell& rShell = GetShell(); - SfxItemSet aSet( rShell.GetAttrPool(), svl::Items< - RES_GRFATR_ROTATION, RES_GRFATR_ROTATION, - SID_ATTR_TRANSFORM_ANGLE, SID_ATTR_TRANSFORM_ANGLE>{} ); - rShell.GetCurAttr( aSet ); - const SwRotationGrf& rRotation = static_cast<const SwRotationGrf&>(aSet.Get(RES_GRFATR_ROTATION)); sal_uInt16 aRotation(0); if (rReq.GetSlot() == SID_ROTATE_GRAPHIC_LEFT) @@ -916,22 +910,23 @@ void SwGrfShell::ExecuteRotation(SfxRequest const &rReq) if (rReq.GetSlot() == SID_ROTATE_GRAPHIC_RESET || 0 != aRotation) { - rShell.StartAllAction(); - rShell.StartUndo(SwUndoId::START); + SwWrtShell& rShell = GetShell(); + SfxItemSet aSet( rShell.GetAttrPool(), svl::Items<RES_GRFATR_ROTATION, RES_GRFATR_ROTATION>{} ); + rShell.GetCurAttr( aSet ); + const SwRotationGrf& rRotation = static_cast<const SwRotationGrf&>(aSet.Get(RES_GRFATR_ROTATION)); + SwFlyFrameAttrMgr aMgr(false, &rShell, rShell.IsFrameSelected() ? Frmmgr_Type::NONE : Frmmgr_Type::GRF); + // RotGrfFlyFrame: Possible rotation change here, SwFlyFrameAttrMgr aMgr is available if (rReq.GetSlot() == SID_ROTATE_GRAPHIC_RESET) { - rShell.SetAttrItem(SwRotationGrf(0, rRotation.GetUnrotatedSize())); + aMgr.SetRotation(rRotation.GetValue(), 0, rRotation.GetUnrotatedSize()); } else if(0 != aRotation) { - sal_uInt16 aNewRotation((aRotation + rRotation.GetValue()) % 3600); + const sal_uInt16 aNewRotation((aRotation + rRotation.GetValue()) % 3600); - rShell.SetAttrItem(SwRotationGrf(aNewRotation, rRotation.GetUnrotatedSize())); + aMgr.SetRotation(rRotation.GetValue(), aNewRotation, rRotation.GetUnrotatedSize()); } - - rShell.EndUndo(SwUndoId::END); - rShell.EndAllAction(); } } commit a42b0985c7619efdc934bb1cf19e5e2c2b6faea2 Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Fri Sep 22 15:28:33 2017 +0200 RotGrfFlyFrame: Initial adaptions To allow free rotation of Graphic FlyFrames in Writer, several adaptions are necessary. This change takes care of all needed changes to internally support a freely definable rotation angle for that case. Save/Load round trip is working, the graphic does no longer get modified and added in 90-degree-changed state to the object, the original will be preserved. Support for needed slot in core/ui is implemented. Rotation can be applied from Menus/Toolbars in the known 90/180 degree steps. Added a slot/Button/command to reset rotation in these cases. Added support in Sidebar to rotate using the rotation wheel and/or numeric field. These fields and support added to Image TabPage, too, fully functional. Missing now is a solution for displaying the rotated Graphic. For now, it just gets rotated, but this will not be the final state of this change. Change-Id: I6f3b85ebb5be2b4ad3311c536d54f27a37a494e7 RotGrfFlyFrame: Linux build adaptions Change-Id: I365287ecd6525b1972e8436d61332f7121d88649 diff --git a/include/svx/svxids.hrc b/include/svx/svxids.hrc index 84103287e776..79ebc50726c1 100644 --- a/include/svx/svxids.hrc +++ b/include/svx/svxids.hrc @@ -919,7 +919,7 @@ #define SID_ROTATE_GRAPHIC_LEFT ( SID_SVX_START + 1121 ) #define SID_ROTATE_GRAPHIC_RIGHT ( SID_SVX_START + 1122 ) #define SID_ROTATE_GRAPHIC_180 ( SID_SVX_START + 1123 ) - +#define SID_ROTATE_GRAPHIC_RESET ( SID_SVX_START + 1092 ) /* RotGrfFlyFrame: new slot */ // new slots for panels #define SID_ATTR_FILL_TRANSPARENCE ( SID_SVX_START + 1124 ) diff --git a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu index 5803979d41f8..52fec078a080 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu @@ -983,6 +983,14 @@ <value>1</value> </prop> </node> + <node oor:name=".uno:RotateReset" oor:op="replace"> + <prop oor:name="Label" oor:type="xs:string"> + <value xml:lang="en-US">Reset R~otation</value> + </prop> + <prop oor:name="Properties" oor:type="xs:int"> + <value>1</value> + </prop> + </node> <node oor:name=".uno:NewHtmlDoc" oor:op="replace"> <prop oor:name="Label" oor:type="xs:string"> <value xml:lang="en-US">Create ~HTML Document</value> diff --git a/svx/sdi/svx.sdi b/svx/sdi/svx.sdi index 932aef3cb2c2..acd7f4c91f6b 100644 --- a/svx/sdi/svx.sdi +++ b/svx/sdi/svx.sdi @@ -4305,6 +4305,23 @@ SfxVoidItem RotateRight SID_ROTATE_GRAPHIC_RIGHT GroupId = SfxGroupId::Graphic; ] +SfxVoidItem RotateReset SID_ROTATE_GRAPHIC_RESET + +[ + AutoUpdate = FALSE, + FastCall = FALSE, + ReadOnlyDoc = TRUE, + Toggle = FALSE, + Container = FALSE, + RecordAbsolute = FALSE, + RecordPerSet; + + AccelConfig = TRUE, + MenuConfig = TRUE, + ToolBoxConfig = TRUE, + GroupId = SfxGroupId::Graphic; +] + SfxBoolItem Crop SID_OBJECT_CROP () [ diff --git a/svx/source/sidebar/possize/PosSizePropertyPanel.cxx b/svx/source/sidebar/possize/PosSizePropertyPanel.cxx index ab27b80cdc68..3895b2a41208 100644 --- a/svx/source/sidebar/possize/PosSizePropertyPanel.cxx +++ b/svx/source/sidebar/possize/PosSizePropertyPanel.cxx @@ -270,6 +270,7 @@ void PosSizePropertyPanel::HandleContextChange( case CombinedEnumContext(Application::WriterVariants, Context::Graphic): bShowFlip = true; + bShowAngle = true; // RotGrfFlyFrame: Writer FlyFrames for Graphics now support angle break; case CombinedEnumContext(Application::Calc, Context::Draw): diff --git a/sw/sdi/_grfsh.sdi b/sw/sdi/_grfsh.sdi index 1dc453608103..8291745966bb 100644 --- a/sw/sdi/_grfsh.sdi +++ b/sw/sdi/_grfsh.sdi @@ -94,6 +94,20 @@ interface BaseTextGraphic DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; ] + SID_ROTATE_GRAPHIC_RESET + [ + ExecMethod = ExecuteRotation ; + StateMethod = GetAttrStateForRotation ; + DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; + ] + + SID_ATTR_TRANSFORM_ANGLE + [ + ExecMethod = ExecuteRotation ; + StateMethod = GetAttrStateForRotation ; + DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; + ] + SID_OBJECT_CROP [ ExecMethod = Execute ; diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx index c4791e086d4b..a35f679d10be 100644 --- a/sw/source/core/doc/notxtfrm.cxx +++ b/sw/source/core/doc/notxtfrm.cxx @@ -768,10 +768,21 @@ void paintGraphicUsingPrimitivesHelper(vcl::RenderContext & rOutputDevice, const basegfx::B2DRange aTargetRange( rAlignedGrfArea.Left(), rAlignedGrfArea.Top(), rAlignedGrfArea.Right(), rAlignedGrfArea.Bottom()); - const basegfx::B2DHomMatrix aTargetTransform( - basegfx::utils::createScaleTranslateB2DHomMatrix( - aTargetRange.getRange(), - aTargetRange.getMinimum())); + basegfx::B2DHomMatrix aTargetTransform; + + // RotGrfFlyFrame: Take rotation into account. Rotation is in 10th degrees + if(0 != rGraphicAttr.GetRotation()) + { + const double fRotate(static_cast< double >(-rGraphicAttr.GetRotation()) * (M_PI/1800.0)); + aTargetTransform.translate(-0.5, -0.5); + aTargetTransform.rotate(fRotate); + aTargetTransform.translate(0.5, 0.5); + } + + // needed scale/translate + aTargetTransform *= basegfx::utils::createScaleTranslateB2DHomMatrix( + aTargetRange.getRange(), + aTargetRange.getMinimum()); drawinglayer::primitive2d::Primitive2DContainer aContent(1); bool bDone(false); diff --git a/sw/source/ui/frmdlg/frmpage.cxx b/sw/source/ui/frmdlg/frmpage.cxx index e36595431cee..f1abe60c19fe 100644 --- a/sw/source/ui/frmdlg/frmpage.cxx +++ b/sw/source/ui/frmdlg/frmpage.cxx @@ -2388,6 +2388,12 @@ SwGrfExtPage::SwGrfExtPage(vcl::Window *pParent, const SfxItemSet &rSet) get(m_pBmpWin, "preview"); m_pBmpWin->SetBitmapEx(get<FixedImage>("fallback")->GetImage().GetBitmapEx()); + // RotGrfFlyFrame: Need Angle and RotateControls now + get(m_pFlAngle, "FL_ANGLE"); + get(m_pNfAngle, "NF_ANGLE"); + get(m_pCtlAngle, "CTL_ANGLE"); + m_pCtlAngle->SetLinkedField( m_pNfAngle, 2 ); + SetExchangeSupport(); m_pMirrorHorzBox->SetClickHdl( LINK(this, SwGrfExtPage, MirrorHdl)); m_pMirrorVertBox->SetClickHdl( LINK(this, SwGrfExtPage, MirrorHdl)); @@ -2411,6 +2417,12 @@ void SwGrfExtPage::dispose() m_pBmpWin.clear(); m_pConnectED.clear(); m_pBrowseBT.clear(); + + // RotGrfFlyFrame: Support RotationAngle + m_pFlAngle.clear(); + m_pNfAngle.clear(); + m_pCtlAngle.clear(); + SfxTabPage::dispose(); } @@ -2432,6 +2444,17 @@ void SwGrfExtPage::Reset(const SfxItemSet *rSet) m_pConnectED->SetReadOnly(false); } + // RotGrfFlyFrame: Get RotationAngle and set at control + if(SfxItemState::SET == rSet->GetItemState( SID_ATTR_TRANSFORM_ANGLE, false, &pItem)) + { + m_pCtlAngle->SetRotation(static_cast<const SfxInt32Item*>(pItem)->GetValue()); + } + else + { + m_pCtlAngle->SetRotation(0); + } + m_pCtlAngle->SaveValue(); + ActivatePage(*rSet); } @@ -2559,6 +2582,14 @@ bool SwGrfExtPage::FillItemSet( SfxItemSet *rSet ) rSet->Put( SvxBrushItem( aGrfName, aFilterName, GPOS_LT, SID_ATTR_GRAF_GRAPHIC )); } + + // RotGrfFlyFrame: Safe rotation if modified + if(m_pCtlAngle->IsValueModified()) + { + rSet->Put(SfxInt32Item(GetWhich(SID_ATTR_TRANSFORM_ANGLE), m_pCtlAngle->GetRotation())); + bModified = true; + } + return bModified; } diff --git a/sw/source/uibase/frmdlg/frmmgr.cxx b/sw/source/uibase/frmdlg/frmmgr.cxx index 73df037c9fdf..fdc883b6a22a 100644 --- a/sw/source/uibase/frmdlg/frmmgr.cxx +++ b/sw/source/uibase/frmdlg/frmmgr.cxx @@ -41,6 +41,7 @@ #include <com/sun/star/text/HoriOrientation.hpp> #include <com/sun/star/text/VertOrientation.hpp> #include <com/sun/star/text/RelOrientation.hpp> +#include <grfatr.hxx> using namespace ::com::sun::star; ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits