RotateFlyFrame3: Corrected interactive Crop
To correct interactive Crop in transformed states, I had to
rework some stuff involved that anyways was in a non optimal
state. Added functionality to translate the object to make
Crop seem to work more seamlessly. Some mapping was needed
to make the Cropped, transformed object to be in the correct
relative position to the uncropped, untransfomed one.
Restructured TransformableSwFrame to directly re-create
last non-transformed SwFrame(s) from the SwFrameAreaDefinition
from the current Transformations, offering the untransformed
SwRect(s) now for usage.
Identified and corrected error when FlyFrame was translated
using keyboard, the accessing method needed to adapt position
in the transformed case.
Started to look at Contour stuff, adapted a set contour to be
correctly used by adapting it as needed in the transformed case.
Change-Id: I0d5f14958bcd6f826b9abd53f1f47b7d0bc5a0e2
diff --git a/include/svx/svdobj.hxx b/include/svx/svdobj.hxx
index 2a7c629..bf227c9 100644
--- a/include/svx/svdobj.hxx
+++ b/include/svx/svdobj.hxx
@@ -75,10 +75,9 @@ class OutputDevice;
class Fraction;
namespace basegfx {
class B2DPoint;
class B2DPolyPolygon;
class B2DHomMatrix;
}
namespace sdr
@@ -511,14 +510,14 @@ public:
/// Nbc means "no broadcast".
virtual void NbcMove (const Size& rSiz);
virtual void NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact);
virtual void NbcCrop (const Point& rRef, const Fraction& xFact, const Fraction& yFact);
virtual void NbcCrop (const basegfx::B2DPoint& rRef, double fxFact, double fyFact);
virtual void NbcRotate(const Point& rRef, long nAngle, double sn, double cs);
virtual void NbcMirror(const Point& rRef1, const Point& rRef2);
virtual void NbcShear (const Point& rRef, long nAngle, double tn, bool bVShear);
virtual void Move (const Size& rSiz);
virtual void Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative = true);
virtual void Crop (const Point& rRef, const Fraction& xFact, const Fraction& yFact);
virtual void Crop (const basegfx::B2DPoint& rRef, double fxFact, double fyFact);
virtual void Rotate(const Point& rRef, long nAngle, double sn, double cs);
virtual void Mirror(const Point& rRef1, const Point& rRef2);
virtual void Shear (const Point& rRef, long nAngle, double tn, bool bVShear);
diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx
index 714d4e6..1e3344c 100644
--- a/svx/source/svdraw/svddrgmt.cxx
+++ b/svx/source/svdraw/svddrgmt.cxx
@@ -3766,25 +3766,17 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
if(bExternal)
{
// With Ref point (opposed to dragged point), X scale and Y scale,
// With aLocalStart 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 representation 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);
// crop. Use aLocalStart unchanged, so being relative to the Crop-Action,
// the called instance knows best how to use it
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));
aLocalStart,
fScaleX,
fScaleY);
}
else
{
diff --git a/svx/source/svdraw/svdobj.cxx b/svx/source/svdraw/svdobj.cxx
index d5ef63b..020c756 100644
--- a/svx/source/svdraw/svdobj.cxx
+++ b/svx/source/svdraw/svdobj.cxx
@@ -1485,8 +1485,10 @@ void SdrObject::Move(const Size& rSiz)
}
}
void SdrObject::NbcCrop(const Point& /*rRef*/, const Fraction& /*xFact*/, const Fraction& /*yFact*/) {
// Default: does nothing. Real behaviour in SwVirtFlyDrawObj and SdrGrafObj
void SdrObject::NbcCrop(const basegfx::B2DPoint& /*aRef*/, double /*fxFact*/, double /*fyFact*/)
{
// Default: does nothing. Real behaviour in SwVirtFlyDrawObj and SdrDragCrop::EndSdrDrag.
// Where SwVirtFlyDrawObj is the only real user of it to do something local
}
void SdrObject::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative)
@@ -1507,10 +1509,10 @@ void SdrObject::Resize(const Point& rRef, const Fraction& xFact, const Fraction&
}
}
void SdrObject::Crop(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
void SdrObject::Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
{
tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
NbcCrop(rRef, xFact, yFact);
NbcCrop(rRef, fxFact, fyFact);
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::Resize,aBoundRect0);
diff --git a/svx/source/uitest/sdrobject.cxx b/svx/source/uitest/sdrobject.cxx
index f70cb2e..4fdd4c3 100644
--- a/svx/source/uitest/sdrobject.cxx
+++ b/svx/source/uitest/sdrobject.cxx
@@ -99,6 +99,8 @@ void SdrUIObject::execute(const OUString& rAction,
}
else if (rAction == "CROP")
{
// RotateFlyFrame3: Note: Crop does nothing at SdrObject
// anymore, see comment at SdrObject::NbcCrop
auto itrNX = rParameters.find("X");
if (itrNX == rParameters.end())
throw css::uno::RuntimeException("missing parameter X");
@@ -107,23 +109,21 @@ void SdrUIObject::execute(const OUString& rAction,
if (itrNY == rParameters.end())
throw css::uno::RuntimeException("missing parameter Y");
long nX = itrNX->second.toInt32();
long nY = itrNY->second.toInt32();
Point aPos(nX, nY);
const double fX(itrNX->second.toDouble());
const double fY(itrNY->second.toDouble());
const basegfx::B2DPoint aPos(fX, fY);
auto itrFracX = rParameters.find("FRAC_X");
if (itrFracX == rParameters.end())
throw css::uno::RuntimeException("missing parameter FRAC_X");
double nFracX = itrFracX->second.toDouble();
Fraction aFracX(nFracX);
const double fFracX(itrFracX->second.toDouble());
auto itrFracY = rParameters.find("FRAC_Y");
if (itrFracY == rParameters.end())
throw css::uno::RuntimeException("missing parameter FRAC_Y");
double nFracY = itrFracY->second.toDouble();
Fraction aFracY(nFracY);
const double fFracY(itrFracY->second.toDouble());
pObj->Crop(aPos, aFracX, aFracY);
pObj->Crop(aPos, fFracX, fFracY);
}
else if (rAction == "ROTATE")
{
diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx
index e1035a3..a4466f1 100644
--- a/sw/source/core/draw/dflyobj.cxx
+++ b/sw/source/core/draw/dflyobj.cxx
@@ -634,9 +634,9 @@ void SwVirtFlyDrawObj::NbcMove(const Size& rSiz)
{
if(GetFlyFrame()->IsFlyFreeFrame() && static_cast<SwFlyFreeFrame*>(GetFlyFrame())->isTransformableSwFrame())
{
// When we have a change in transformed state, we need to fall back to the
// state without possible transformations. Restore FrameArea and use aOutRect
// from old FrameArea. From here, all former actions below should be fine
// When we have a change and are in transformed state (e.g. rotation used),
// we need to fall back to the un-transformed state to keep the old code below
// working properly. Restore FrameArea and use aOutRect from old FrameArea.
TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
pTransformableSwFrame->restoreFrameAreas();
aOutRect = GetFlyFrame()->getFrameArea().SVRect();
@@ -788,7 +788,7 @@ void SwVirtFlyDrawObj::NbcMove(const Size& rSiz)
}
void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
void SwVirtFlyDrawObj::NbcCrop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
{
// Get Wrt Shell
SwWrtShell *pSh = dynamic_cast<SwWrtShell*>( GetFlyFrame()->getRootFrame()->GetCurrShell() );
@@ -805,33 +805,6 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
return;
}
const bool bIsTransformableSwFrame(
GetFlyFrame()->IsFlyFreeFrame() &&
static_cast<SwFlyFreeFrame*>(GetFlyFrame())->isTransformableSwFrame());
if(bIsTransformableSwFrame)
{
// When we have a change in transformed state, we need to fall back to the
// state without possible transformations. Restore FrameArea and use aOutRect
// from old FrameArea. From here, all former actions below should be fine
TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
pTransformableSwFrame->restoreFrameAreas();
aOutRect = GetFlyFrame()->getFrameArea().SVRect();
}
// Compute old and new rect. This will give us the deformation to apply to
// the object to crop
const long nOldWidth(aOutRect.GetWidth());
const long nOldHeight(aOutRect.GetHeight());
if (!nOldWidth || !nOldHeight)
{
return;
}
tools::Rectangle aNewRect( aOutRect );
ResizeRect( aNewRect, rRef, xFact, yFact );
// Get graphic object size in 100th of mm
const MapMode aMapMode100thmm(MapUnit::Map100thMM);
Size aGraphicSize(pGraphicObject->GetPrefSize());
@@ -850,6 +823,48 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
return ;
}
const bool bIsTransformableSwFrame(
GetFlyFrame()->IsFlyFreeFrame() &&
static_cast<SwFlyFreeFrame*>(GetFlyFrame())->isTransformableSwFrame());
if(bIsTransformableSwFrame)
{
// When we have a change and are in transformed state (e.g. rotation used),
// we need to fall back to the un-transformed state to keep the old code below
// working properly. Restore FrameArea and use aOutRect from old FrameArea.
TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
pTransformableSwFrame->restoreFrameAreas();
aOutRect = GetFlyFrame()->getFrameArea().SVRect();
}
// Compute old and new rect. This will give us the deformation to apply to
// the object to crop. OldRect is the inner frame, see getFullDragClone()
// below where getFramePrintAreaTransformation is used as object geometry for Crop
const tools::Rectangle aOldRect(
GetFlyFrame()->getFrameArea().TopLeft() + GetFlyFrame()->getFramePrintArea().TopLeft(),
GetFlyFrame()->getFramePrintArea().SSize());
const long nOldWidth(aOldRect.GetWidth());
const long nOldHeight(aOldRect.GetHeight());
if (!nOldWidth || !nOldHeight)
{
return;
}
// rRef is relative to the Crop-Action, si in X/Y-Ranges of [0.0 .. 1.0],
// to get the correct absolute position, transform using the old Rect
const Point aRef(
aOldRect.Left() + basegfx::fround(aOldRect.GetWidth() * rRef.getX()),
aOldRect.Top() + basegfx::fround(aOldRect.GetHeight() * rRef.getY()));
// appy transformation, use old ResizeRect for now
tools::Rectangle aNewRect( aOldRect );
ResizeRect(
aNewRect,
aRef,
Fraction(fxFact),
Fraction(fyFact));
// Get old values for crop in 10th of mm
SfxItemSet aSet( pSh->GetAttrPool(), svl::Items<RES_GRFATR_CROPGRF, RES_GRFATR_CROPGRF>{} );
pSh->GetCurAttr( aSet );
@@ -865,10 +880,10 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
double fScaleX = ( aGraphicSize.Width() - aCropRectangle.Left() - aCropRectangle.Right() ) / (double)nOldWidth;
double fScaleY = ( aGraphicSize.Height() - aCropRectangle.Top() - aCropRectangle.Bottom() ) / (double)nOldHeight;
sal_Int32 nDiffLeft = aNewRect.Left() - aOutRect.Left();
sal_Int32 nDiffTop = aNewRect.Top() - aOutRect.Top();
sal_Int32 nDiffRight = aNewRect.Right() - aOutRect.Right();
sal_Int32 nDiffBottom = aNewRect.Bottom() - aOutRect.Bottom();
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();
// Compute new values in 10th of mm
sal_Int32 nLeftCrop = static_cast<sal_Int32>( aCropRectangle.Left() + nDiffLeft * fScaleX );
@@ -878,7 +893,7 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
// Apply values
pSh->StartAllAction();
// pSh->StartUndo(SwUndoId::START);
// pSh->StartUndo(SwUndoId::START);
// Set new crop values in twips
aCrop.SetLeft (convertMm100ToTwip(nLeftCrop));
@@ -890,15 +905,21 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
// Set new frame size
SwFrameFormat *pFormat = GetFormat();
SwFormatFrameSize aSz( pFormat->GetFrameSize() );
aSz.SetWidth(aNewRect.GetWidth());
aSz.SetHeight(aNewRect.GetHeight());
const long aNewWidth(aNewRect.GetWidth() + (aOutRect.GetWidth() - aOldRect.GetWidth()));
const long aNewHeight(aNewRect.GetHeight() + (aOutRect.GetHeight() - aOldRect.GetHeight()));
aSz.SetWidth(aNewWidth);
aSz.SetHeight(aNewHeight);
pFormat->GetDoc()->SetAttr( aSz, *pFormat );
// add move - to make result look better. Fill with defaults
// for the untransformed case
Point aNewTopLeft(aNewRect.TopLeft());
const Point aOldTopLeft(aOldRect.TopLeft());
if(bIsTransformableSwFrame)
{
// Need to correct the TopLeft position in rotated state to make
// the interaction look correct. First, extract rotation (and others
// currently not used)
// Need to correct the NewTopLeft position in transformed state to make
// the interaction look correct. First, extract rotation
basegfx::B2DVector aScale, aTranslate;
double fRotate, fShearX;
GetFlyFrame()->getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
@@ -922,22 +943,22 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
// Create the new TopLeft of the unrotated, cropped object by creating
// as if re-rceating the unrotated geometry
const Point aNewTopLeft(
aNewTopLeft = Point(
basegfx::fround(aRotNewCenter.getX() - (0.5 * aNewRect.getWidth())),
basegfx::fround(aRotNewCenter.getY() - (0.5 * aNewRect.getHeight())));
// checvk if we have movement and execute if yes
const Size aDeltaMove(
basegfx::fround(aNewTopLeft.getX() - aOutRect.Left()),
basegfx::fround(aNewTopLeft.getY() - aOutRect.Top()));
if(0 != aDeltaMove.Width() || 0 != aDeltaMove.Height())
{
NbcMove(aDeltaMove);
}
}
// pSh->EndUndo(SwUndoId::END);
// check if we have movement and execute if yes
const Size aDeltaMove(
aNewTopLeft.X() - aOldTopLeft.X(),
aNewTopLeft.Y() - aOldTopLeft.Y());
if(0 != aDeltaMove.Width() || 0 != aDeltaMove.Height())
{
NbcMove(aDeltaMove);
}
// pSh->EndUndo(SwUndoId::END);
pSh->EndAllAction();
}
@@ -979,13 +1000,14 @@ void SwVirtFlyDrawObj::NbcResize(const Point& rRef, const Fraction& xFact, const
basegfx::B2DVector aScale, aTranslate;
double fRotate, fShearX;
aNewMat.decompose(aScale, aTranslate, fRotate, fShearX);
const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
// create new modified OutRect
// create new modified, but untransformed OutRect
aOutRect = tools::Rectangle(
basegfx::fround(aCenter.getX() - (0.5 * aScale.getX())),
basegfx::fround(aCenter.getY() - (0.5 * aScale.getY())),
basegfx::fround(aCenter.getX() + (0.5 * aScale.getX())),
basegfx::fround(aCenter.getY() + (0.5 * aScale.getY())));
basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())),
basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())),
basegfx::fround(aCenter.getX() + (0.5 * aAbsScale.getX())),
basegfx::fround(aCenter.getY() + (0.5 * aAbsScale.getY())));
// restore FrameAreas so that actions below not adapted to new
// full transformations take the correct actions
@@ -1115,9 +1137,9 @@ void SwVirtFlyDrawObj::Resize(const Point& rRef,
GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
}
void SwVirtFlyDrawObj::Crop(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
void SwVirtFlyDrawObj::Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
{
NbcCrop( rRef, xFact, yFact );
NbcCrop( rRef, fxFact, fyFact );
SetChanged();
GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
}
diff --git a/sw/source/core/frmedt/fefly1.cxx b/sw/source/core/frmedt/fefly1.cxx
index f36eac3..105689d 100644
--- a/sw/source/core/frmedt/fefly1.cxx
+++ b/sw/source/core/frmedt/fefly1.cxx
@@ -368,7 +368,24 @@ void SwFEShell::SetFlyPos( const Point& rAbsPos )
// Set an anchor starting from the absolute position for paragraph bound Flys
// Anchor and new RelPos will be calculated and set by the Fly
if ( pFly->IsFlyAtContentFrame() )
static_cast<SwFlyAtContentFrame*>(pFly)->SetAbsPos( rAbsPos );
{
if(pFly->IsFlyFreeFrame() && static_cast<SwFlyFreeFrame*>(pFly)->isTransformableSwFrame())
{
// RotateFlyFrame3: When we have a change and are in transformed state (e.g. rotation used),
// we need to correct the absolute position (rAbsPos) which was created in
// transformed coordinates to untransformed state
TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(pFly)->getTransformableSwFrame());
const SwRect aUntransformedFrameArea(pTransformableSwFrame->getUntransformedFrameArea());
const Point aNewAbsPos(
rAbsPos.X() + aUntransformedFrameArea.Left() - pFly->getFrameArea().Left(),
rAbsPos.Y() + aUntransformedFrameArea.Top() - pFly->getFrameArea().Top());
static_cast<SwFlyAtContentFrame*>(pFly)->SetAbsPos(aNewAbsPos);
}
else
{
static_cast<SwFlyAtContentFrame*>(pFly)->SetAbsPos( rAbsPos );
}
}
else
{
const SwFrame *pAnch = pFly->GetAnchorFrame();
diff --git a/sw/source/core/inc/dflyobj.hxx b/sw/source/core/inc/dflyobj.hxx
index e2fcac5..77df706 100644
--- a/sw/source/core/inc/dflyobj.hxx
+++ b/sw/source/core/inc/dflyobj.hxx
@@ -101,11 +101,11 @@ public:
virtual void NbcMove (const Size& rSiz) override;
virtual void NbcResize(const Point& rRef, const Fraction& xFact,
const Fraction& yFact) override;
virtual void NbcCrop(const Point& rRef, const Fraction& xFact, const Fraction& yFact) override;
virtual void NbcCrop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact) override;
virtual void Move (const Size& rSiz) override;
virtual void Resize(const Point& rRef, const Fraction& xFact,
const Fraction& yFact, bool bUnsetRelative = true) override;
virtual void Crop(const Point& rRef, const Fraction& xFact, const Fraction& yFact) override;
virtual void Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact) override;
virtual void addCropHandles(SdrHdlList& rTarget) const override;
virtual void Rotate(const Point& rRef, long nAngle, double sn, double cs) override;
diff --git a/sw/source/core/inc/flyfrms.hxx b/sw/source/core/inc/flyfrms.hxx
index 5334a02..eaae5b8 100644
--- a/sw/source/core/inc/flyfrms.hxx
+++ b/sw/source/core/inc/flyfrms.hxx
@@ -25,6 +25,7 @@
// #i28701#
class SwFlyAtContentFrame;
class SwNoTextFrame;
double getLocalFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame);
diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index 811bd39..cc455a9 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -146,6 +146,7 @@ protected:
public:
SwFrameAreaDefinition();
virtual ~SwFrameAreaDefinition();
// read access to mb*Valid flags
bool isFrameAreaPositionValid() const { return mbFrameAreaPositionValid; }
@@ -212,8 +213,8 @@ public:
};
/// RotateFlyFrame3: Helper class when you want to make your SwFrame derivate
/// transformable. It provides some tooling to do so. To use,
/// derive your SwFrame from it
/// transformable. It provides some tooling to do so. To use, add as member
/// (see e.g. SwFlyFreeFrame which uses 'std::unique_ptr< TransformableSwFrame >')
class SW_DLLPUBLIC TransformableSwFrame
{
private:
@@ -221,54 +222,50 @@ private:
SwFrameAreaDefinition& mrSwFrameAreaDefinition;
// FrameAreaTransformation and FramePrintAreaTransformation
// here when more than translate/scale is used (e.g. rotation)
// !identtity when needed (translate/scale is used (e.g. rotation))
basegfx::B2DHomMatrix maFrameAreaTransformation;
basegfx::B2DHomMatrix maFramePrintAreaTransformation;
// last saved versions of SwRect(s) from SwFrameAreaDefinition,
// set from adaptFrameAreasToTransformations before modifying
// SwFrameAreaDefinition(s), used for restore from
// restoreFrameAreas
SwRect maSavedFrameArea;
SwRect maSavedFramePrintArea;
public:
TransformableSwFrame(SwFrameAreaDefinition& rSwFrameAreaDefinition)
: mrSwFrameAreaDefinition(rSwFrameAreaDefinition),
maFrameAreaTransformation(),
maFramePrintAreaTransformation(),
maSavedFrameArea(),
maSavedFramePrintArea()
maFramePrintAreaTransformation()
{
}
// Support for Transformations for inner frame of a SwGrfNode
// get SwFrameArea in transformation form
const basegfx::B2DHomMatrix& getLocalFrameAreaTransformation() const
{
return maFrameAreaTransformation;
}
// get SwFramePrintArea in transformation form
const basegfx::B2DHomMatrix& getLocalFramePrintAreaTransformation() const
{
return maFramePrintAreaTransformation;
}
// Helpers to re-create the untransformed SwRect(s) originally
// in the SwFrameAreaDefinition, based on the current Transformations.
SwRect getUntransformedFrameArea() const;
SwRect getUntransformedFramePrintArea() const;
// Helper method to re-create FrameAreaTransformations based on the
// curent FrameAreaDefinition, given rotation and Center
// curent FrameAreaDefinition transformed by given rotation and Center
void createFrameAreaTransformations(
double fRotation,
const basegfx::B2DPoint& rCenter);
// Tooling method to reset the SwRect(s) in the current
// SwFrameAreaDefinition which are already apapted to
// Transformation back to the untransformed state that was
// last saved (see adaptFrameAreasToTransformations).
// Transformation back to the untransformed state, using
// the getUntransformedFrame*Area calls above when needed.
// Only the SwRect(s) are changed back, not the transformations.
void restoreFrameAreas();
// Re-Creates the SwRect(s) as BoundAreas based on the current
// set Transformations, also saves the last SwRect(s) to the save
// values.
// set Transformations.
void adaptFrameAreasToTransformations();
// Modify current definitions by applying the given transformation
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index 684b989..5163fbb 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -62,6 +62,8 @@
#include <IDocumentLayoutAccess.hxx>
#include <textboxhelper.hxx>
#include <txtfly.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
using namespace ::com::sun::star;
@@ -2431,8 +2433,9 @@ bool SwFlyFrame::GetContour( tools::PolyPolygon& rContour,
{
vcl::RenderContext* pRenderContext = getRootFrame()->GetCurrShell()->GetOut();
bool bRet = false;
if( GetFormat()->GetSurround().IsContour() && Lower() &&
Lower()->IsNoTextFrame() )
const bool bIsCandidate(Lower() && Lower()->IsNoTextFrame());
if(bIsCandidate && GetFormat()->GetSurround().IsContour())
{
SwNoTextNode *pNd = const_cast<SwNoTextNode*>(static_cast<const SwNoTextNode*>(static_cast<const SwContentFrame*>(Lower())->GetNode()));
// OD 16.04.2003 #i13147# - determine <GraphicObject> instead of <Graphic>
@@ -2524,6 +2527,31 @@ bool SwFlyFrame::GetContour( tools::PolyPolygon& rContour,
bRet = true;
}
}
if(bRet &&
rContour.Count() &&
IsFlyFreeFrame() &&
static_cast<const SwFlyFreeFrame*>(this)->isTransformableSwFrame())
{
// RotateFlyFrame: Need to adapt contour to transformation
basegfx::B2DVector aScale, aTranslate;
double fRotate, fShearX;
getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
if(!basegfx::fTools::equalZero(fRotate))
{
basegfx::B2DPolyPolygon aSource(rContour.getB2DPolyPolygon());
const basegfx::B2DPoint aCenter(getFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5));
const basegfx::B2DHomMatrix aRotateAroundCenter(
basegfx::utils::createRotateAroundPoint(
aCenter.getX(),
aCenter.getY(),
fRotate));
aSource.transform(aRotateAroundCenter);
rContour = tools::PolyPolygon(aSource);
}
}
return bRet;
}
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 7f7068e..08debf8 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -65,6 +65,10 @@ SwFrameAreaDefinition::SwFrameAreaDefinition()
{
}
SwFrameAreaDefinition::~SwFrameAreaDefinition()
{
}
void SwFrameAreaDefinition::setFrameAreaPositionValid(bool bNew)
{
if(mbFrameAreaPositionValid != bNew)
@@ -146,6 +150,55 @@ void SwFrameAreaDefinition::transform_translate(const Point& rOffset)
}
}
SwRect TransformableSwFrame::getUntransformedFrameArea() const
{
const basegfx::B2DHomMatrix& rSource(getLocalFrameAreaTransformation());
if(rSource.isIdentity())
{
return mrSwFrameAreaDefinition.getFrameArea();
}
else
{
basegfx::B2DVector aScale, aTranslate;
double fRotate, fShearX;
rSource.decompose(aScale, aTranslate, fRotate, fShearX);
const basegfx::B2DPoint aCenter(rSource * basegfx::B2DPoint(0.5, 0.5));
const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
return SwRect(
basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())),
basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())),
basegfx::fround(aAbsScale.getX()),
basegfx::fround(aAbsScale.getY()));
}
}
SwRect TransformableSwFrame::getUntransformedFramePrintArea() const
{
const basegfx::B2DHomMatrix& rSource(getLocalFramePrintAreaTransformation());
if(rSource.isIdentity())
{
return mrSwFrameAreaDefinition.getFramePrintArea();
}
else
{
basegfx::B2DVector aScale, aTranslate;
double fRotate, fShearX;
rSource.decompose(aScale, aTranslate, fRotate, fShearX);
const basegfx::B2DPoint aCenter(rSource * basegfx::B2DPoint(0.5, 0.5));
const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
const SwRect aUntransformedFrameArea(getUntransformedFrameArea());
return SwRect(
basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())) - aUntransformedFrameArea.Left(),
basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())) - aUntransformedFrameArea.Top(),
basegfx::fround(aAbsScale.getX()),
basegfx::fround(aAbsScale.getY()));
}
}
void TransformableSwFrame::createFrameAreaTransformations(
double fRotation,
const basegfx::B2DPoint& rCenter)
@@ -178,7 +231,6 @@ void TransformableSwFrame::adaptFrameAreasToTransformations()
if(aNewFrm != mrSwFrameAreaDefinition.getFrameArea())
{
maSavedFrameArea = mrSwFrameAreaDefinition.getFrameArea();
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(mrSwFrameAreaDefinition);
aFrm.setSwRect(aNewFrm);
}
@@ -196,7 +248,6 @@ void TransformableSwFrame::adaptFrameAreasToTransformations()
if(aNewPrt != mrSwFrameAreaDefinition.getFramePrintArea())
{
maSavedFramePrintArea = mrSwFrameAreaDefinition.getFramePrintArea();
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(mrSwFrameAreaDefinition);
aPrt.setSwRect(aNewPrt);
}
@@ -206,20 +257,17 @@ void TransformableSwFrame::adaptFrameAreasToTransformations()
void TransformableSwFrame::restoreFrameAreas()
{
// This can be done fully based on the Transformations currently
// set (and I did this in the beginning and it may be necessary
// again later), but for simplicity and performance now done using
// the last save values for the SwRect(s), see above
if(!getLocalFrameAreaTransformation().isIdentity() && maSavedFrameArea != mrSwFrameAreaDefinition.getFrameArea())
// set, so use this. Only needed when transformation *is* used
if(!getLocalFrameAreaTransformation().isIdentity())
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(mrSwFrameAreaDefinition);
aFrm.setSwRect(maSavedFrameArea);
aFrm.setSwRect(getUntransformedFrameArea());
}
if(!getLocalFramePrintAreaTransformation().isIdentity() && maSavedFramePrintArea != mrSwFrameAreaDefinition.getFramePrintArea())
if(!getLocalFramePrintAreaTransformation().isIdentity())
{
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(mrSwFrameAreaDefinition);
aPrt.setSwRect(maSavedFramePrintArea);
aPrt.setSwRect(getUntransformedFramePrintArea());
}
}