Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / draw / dflyobj.cxx
blob31a193a45119d8be9810e9d522cd9f0fee493737
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <hintids.hxx>
21 #include <comphelper/lok.hxx>
22 #include <osl/diagnose.h>
23 #include <tools/mapunit.hxx>
24 #include <tools/UnitConversion.hxx>
25 #include <svx/svdhdl.hxx>
26 #include <svx/svdtrans.hxx>
27 #include <editeng/protitem.hxx>
28 #include <svx/svdpage.hxx>
29 #include <vcl/canvastools.hxx>
30 #include <vcl/gdimtf.hxx>
31 #include <vcl/svapp.hxx>
32 #include <vcl/ptrstyle.hxx>
34 #include <fmtclds.hxx>
35 #include <fmtornt.hxx>
36 #include <fmtfsize.hxx>
37 #include <fmturl.hxx>
38 #include <viewsh.hxx>
39 #include <frmatr.hxx>
40 #include <doc.hxx>
41 #include <IDocumentUndoRedo.hxx>
42 #include <dflyobj.hxx>
43 #include <flyfrm.hxx>
44 #include <frmfmt.hxx>
45 #include <viewopt.hxx>
46 #include <frmtool.hxx>
47 #include <flyfrms.hxx>
48 #include <ndnotxt.hxx>
49 #include <grfatr.hxx>
50 #include <pagefrm.hxx>
51 #include <rootfrm.hxx>
52 #include <textboxhelper.hxx>
53 #include <wrtsh.hxx>
54 #include <ndgrf.hxx>
55 #include <frmmgr.hxx>
57 #include <svx/sdr/properties/defaultproperties.hxx>
58 #include <basegfx/range/b2drange.hxx>
59 #include <basegfx/polygon/b2dpolygontools.hxx>
60 #include <basegfx/polygon/b2dpolygon.hxx>
62 // AW: For VCOfDrawVirtObj and stuff
63 #include <svx/sdr/contact/viewcontactofvirtobj.hxx>
64 #include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
65 #include <drawinglayer/geometry/viewinformation2d.hxx>
66 #include <sw_primitivetypes2d.hxx>
67 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
68 #include <basegfx/matrix/b2dhommatrixtools.hxx>
69 #include <notxtfrm.hxx>
71 using namespace ::com::sun::star;
73 static bool bInResize = false;
76 namespace sdr::contact
78 namespace {
80 /**
81 * @see #i95264#
83 * currently needed since createViewIndependentPrimitive2DSequence() is called when
84 * RecalcBoundRect() is used. There should currently no VOCs being constructed since it
85 * gets not visualized (instead the corresponding SwVirtFlyDrawObj's referencing this one
86 * are visualized).
88 class VCOfSwFlyDrawObj : public ViewContactOfSdrObj
90 protected:
91 /** This method is responsible for creating the graphical visualisation data
93 * @note ONLY based on model data
95 virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
97 public:
98 /// basic constructor, used from SdrObject.
99 explicit VCOfSwFlyDrawObj(SwFlyDrawObj& rObj)
100 : ViewContactOfSdrObj(rObj)
107 void VCOfSwFlyDrawObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor&) const
109 // currently gets not visualized, return empty sequence
112 } // end of namespace sdr::contact
114 std::unique_ptr<sdr::properties::BaseProperties> SwFlyDrawObj::CreateObjectSpecificProperties()
116 // create default properties
117 return std::make_unique<sdr::properties::DefaultProperties>(*this);
120 std::unique_ptr<sdr::contact::ViewContact> SwFlyDrawObj::CreateObjectSpecificViewContact()
122 // needs an own VC since createViewIndependentPrimitive2DSequence()
123 // is called when RecalcBoundRect() is used
124 return std::make_unique<sdr::contact::VCOfSwFlyDrawObj>(*this);
127 SwFlyDrawObj::SwFlyDrawObj(SdrModel& rSdrModel)
128 : SdrObject(rSdrModel),
129 mbIsTextBox(false)
133 SwFlyDrawObj::SwFlyDrawObj(SdrModel& rSdrModel, SwFlyDrawObj const& rSource)
134 : SdrObject(rSdrModel, rSource)
135 , mbIsTextBox(false)
139 SwFlyDrawObj::~SwFlyDrawObj()
143 // SwFlyDrawObj - Factory-Methods
144 SdrInventor SwFlyDrawObj::GetObjInventor() const
146 return SdrInventor::Swg;
149 SdrObjKind SwFlyDrawObj::GetObjIdentifier() const
151 return SdrObjKind::SwFlyDrawObjIdentifier;
154 rtl::Reference<SdrObject> SwFlyDrawObj::CloneSdrObject(SdrModel& rTargetModel) const
156 return new SwFlyDrawObj(rTargetModel);
159 void SwFlyDrawObj::NbcRotate(const Point& /*rRef*/, Degree100 /*nAngle*/, double /*sinAngle*/, double /*cosAngle*/)
161 assert(false);
164 // TODO: Need own primitive to get the FlyFrame paint working
165 namespace drawinglayer::primitive2d
167 namespace {
169 class SwVirtFlyDrawObjPrimitive : public BufferedDecompositionPrimitive2D
171 private:
172 const SwVirtFlyDrawObj& mrSwVirtFlyDrawObj;
173 const basegfx::B2DRange maOuterRange;
175 protected:
176 /// method which is to be used to implement the local decomposition of a 2D primitive
177 virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const override;
179 public:
180 SwVirtFlyDrawObjPrimitive(
181 const SwVirtFlyDrawObj& rSwVirtFlyDrawObj,
182 const basegfx::B2DRange &rOuterRange)
183 : mrSwVirtFlyDrawObj(rSwVirtFlyDrawObj),
184 maOuterRange(rOuterRange)
188 virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
190 virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override;
192 // override to allow callbacks to wrap_DoPaintObject
193 virtual void get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const override;
195 // data read access
196 const SwVirtFlyDrawObj& getSwVirtFlyDrawObj() const { return mrSwVirtFlyDrawObj; }
197 const basegfx::B2DRange& getOuterRange() const { return maOuterRange; }
199 /// provide unique ID
200 virtual sal_uInt32 getPrimitive2DID() const override;
204 } // end of namespace drawinglayer::primitive2d
206 namespace drawinglayer::primitive2d
208 void SwVirtFlyDrawObjPrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
210 if(getOuterRange().isEmpty())
211 return;
213 // currently this SW object has no primitive representation. As long as this is the case,
214 // create invisible geometry to allow correct HitTest and BoundRect calculations for the
215 // object. Use a filled primitive to get 'inside' as default object hit. The special cases from
216 // the old SwVirtFlyDrawObj::CheckHit implementation are handled now in SwDrawView::PickObj;
217 // this removed the 'hack' to get a view from inside model data or to react on null-tolerance
218 // as it was done in the old implementation
219 rContainer.push_back(
220 createHiddenGeometryPrimitives2D(
221 true,
222 getOuterRange()));
225 bool SwVirtFlyDrawObjPrimitive::operator==(const BasePrimitive2D& rPrimitive) const
227 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
229 const SwVirtFlyDrawObjPrimitive& rCompare = static_cast<const SwVirtFlyDrawObjPrimitive&>(rPrimitive);
231 return (&getSwVirtFlyDrawObj() == &rCompare.getSwVirtFlyDrawObj()
232 && getOuterRange() == rCompare.getOuterRange());
235 return false;
238 basegfx::B2DRange SwVirtFlyDrawObjPrimitive::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
240 return getOuterRange();
243 void SwVirtFlyDrawObjPrimitive::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const
245 // This is the callback to keep the FlyFrame painting in SW alive as long as it
246 // is not changed to primitives. This is the method which will be called by the processors
247 // when they do not know this primitive (and they do not). Inside wrap_DoPaintObject
248 // there needs to be a test that paint is only done during SW repaints (see there).
249 // Using this mechanism guarantees the correct Z-Order of the VirtualObject-based FlyFrames.
250 getSwVirtFlyDrawObj().wrap_DoPaintObject(rViewInformation);
252 // call parent
253 BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
256 // provide unique ID
257 sal_uInt32 SwVirtFlyDrawObjPrimitive::getPrimitive2DID() const
259 return PRIMITIVE2D_ID_SWVIRTFLYDRAWOBJPRIMITIVE2D;
262 } // end of namespace drawinglayer::primitive2d
264 // AW: own sdr::contact::ViewContact (VC) sdr::contact::ViewObjectContact (VOC) needed
265 // since offset is defined different from SdrVirtObj's sdr::contact::ViewContactOfVirtObj.
266 // For paint, that offset is used by setting at the OutputDevice; for primitives this is
267 // not possible since we have no OutputDevice, but define the geometry itself.
269 namespace sdr::contact
271 namespace {
273 class VCOfSwVirtFlyDrawObj : public ViewContactOfVirtObj
275 protected:
276 /** This method is responsible for creating the graphical visualisation data
278 * @note ONLY based on model data
280 virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
282 public:
283 /// basic constructor, used from SdrObject.
284 explicit VCOfSwVirtFlyDrawObj(SwVirtFlyDrawObj& rObj)
285 : ViewContactOfVirtObj(rObj)
289 /// access to SwVirtFlyDrawObj
290 SwVirtFlyDrawObj& GetSwVirtFlyDrawObj() const
292 return static_cast<SwVirtFlyDrawObj&>(mrObject);
297 } // end of namespace sdr::contact
299 namespace sdr::contact
301 void VCOfSwVirtFlyDrawObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
303 const SdrObject& rReferencedObject = GetSwVirtFlyDrawObj().GetReferencedObj();
305 // check if it is a SwFlyDrawObj*
306 if (rReferencedObject.GetObjIdentifier() == SdrObjKind::SwFlyDrawObjIdentifier)
308 // create an own specialized primitive which is used as repaint callpoint and HitTest
309 // for HitTest processor (see primitive implementation above)
310 const basegfx::B2DRange aOuterRange(GetSwVirtFlyDrawObj().getOuterBound());
312 if(!aOuterRange.isEmpty())
314 const drawinglayer::primitive2d::Primitive2DReference xPrimitive(
315 new drawinglayer::primitive2d::SwVirtFlyDrawObjPrimitive(
316 GetSwVirtFlyDrawObj(),
317 aOuterRange));
319 rVisitor.visit(xPrimitive);
324 } // end of namespace sdr::contact
326 basegfx::B2DRange SwVirtFlyDrawObj::getOuterBound() const
328 basegfx::B2DRange aOuterRange;
329 const SdrObject& rReferencedObject = GetReferencedObj();
331 // check if it is a SwFlyDrawObj*
332 if (rReferencedObject.GetObjIdentifier() == SdrObjKind::SwFlyDrawObjIdentifier)
334 const SwFlyFrame* pFlyFrame = GetFlyFrame();
336 if(pFlyFrame)
338 const tools::Rectangle aOuterRectangle(pFlyFrame->getFrameArea().Pos(), pFlyFrame->getFrameArea().SSize());
340 if(!aOuterRectangle.IsEmpty())
342 aOuterRange.expand(basegfx::B2DTuple(aOuterRectangle.Left(), aOuterRectangle.Top()));
343 aOuterRange.expand(basegfx::B2DTuple(aOuterRectangle.Right(), aOuterRectangle.Bottom()));
348 return aOuterRange;
351 basegfx::B2DRange SwVirtFlyDrawObj::getInnerBound() const
353 basegfx::B2DRange aInnerRange;
354 const SdrObject& rReferencedObject = GetReferencedObj();
356 if(dynamic_cast<const SwFlyDrawObj*>( &rReferencedObject) != nullptr)
358 const SwFlyFrame* pFlyFrame = GetFlyFrame();
360 if(pFlyFrame)
362 const tools::Rectangle aInnerRectangle(pFlyFrame->getFrameArea().Pos() + pFlyFrame->getFramePrintArea().Pos(), pFlyFrame->getFramePrintArea().SSize());
364 if(!aInnerRectangle.IsEmpty())
366 aInnerRange.expand(basegfx::B2DTuple(aInnerRectangle.Left(), aInnerRectangle.Top()));
367 aInnerRange.expand(basegfx::B2DTuple(aInnerRectangle.Right(), aInnerRectangle.Bottom()));
372 return aInnerRange;
375 bool SwVirtFlyDrawObj::ContainsSwGrfNode() const
377 // RotGrfFlyFrame: Check if this is a SwGrfNode
378 const SwFlyFrame* pFlyFrame(GetFlyFrame());
380 if(nullptr != pFlyFrame && pFlyFrame->Lower() && pFlyFrame->Lower()->IsNoTextFrame())
382 const SwNoTextFrame *const pNTF(static_cast<const SwNoTextFrame*>(pFlyFrame->Lower()));
384 const SwGrfNode *const pGrfNd(pNTF->GetNode()->GetGrfNode());
386 return nullptr != pGrfNd;
389 return false;
392 bool SwVirtFlyDrawObj::HasLimitedRotation() const
394 // RotGrfFlyFrame: If true, this SdrObject supports only limited rotation.
395 // This is the case for SwGrfNode instances
396 return ContainsSwGrfNode();
399 void SwVirtFlyDrawObj::Rotate(const Point& rRef, Degree100 nAngle100, double sn, double cs)
401 if(ContainsSwGrfNode())
403 // RotGrfFlyFrame: Here is where the positively completed rotate interaction is executed.
404 // Rotation is in 1/100th degree and may be signed (!)
405 Degree10 nAngle10 = to<Degree10>(nAngle100);
407 while(nAngle10 < 0_deg10)
409 nAngle10 += 3600_deg10;
412 SwWrtShell *pShForAngle = nAngle10 ? dynamic_cast<SwWrtShell*>(GetFlyFrame()->getRootFrame()->GetCurrShell()) : nullptr;
413 if (pShForAngle)
415 // RotGrfFlyFrame: Add transformation to placeholder object
416 Size aSize;
417 const Degree10 nOldRot(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame(aSize));
418 SwFlyFrameAttrMgr aMgr(false, pShForAngle, Frmmgr_Type::NONE, nullptr);
420 aMgr.SetRotation(nOldRot, (nOldRot + nAngle10) % 3600_deg10, aSize);
423 else
425 // call parent
426 SdrVirtObj::Rotate(rRef, nAngle100, sn, cs);
430 std::unique_ptr<sdr::contact::ViewContact> SwVirtFlyDrawObj::CreateObjectSpecificViewContact()
432 // need an own ViewContact (VC) to allow creation of a specialized primitive
433 // for being able to visualize the FlyFrames in primitive renderers
434 return std::make_unique<sdr::contact::VCOfSwVirtFlyDrawObj>(*this);
437 SwVirtFlyDrawObj::SwVirtFlyDrawObj(
438 SdrModel& rSdrModel,
439 SdrObject& rNew,
440 SwFlyFrame* pFly)
441 : SdrVirtObj(rSdrModel, rNew),
442 m_pFlyFrame(pFly)
444 const SvxProtectItem &rP = m_pFlyFrame->GetFormat()->GetProtect();
445 m_bMovProt = rP.IsPosProtected();
446 m_bSizProt = rP.IsSizeProtected();
449 SwVirtFlyDrawObj::~SwVirtFlyDrawObj()
451 assert (!getSdrPageFromSdrObject() && "should have already been removed");
454 const SwFrameFormat *SwVirtFlyDrawObj::GetFormat() const
456 return GetFlyFrame()->GetFormat();
458 SwFrameFormat *SwVirtFlyDrawObj::GetFormat()
460 return GetFlyFrame()->GetFormat();
463 // --> OD #i102707#
464 namespace
466 class RestoreMapMode
468 public:
469 explicit RestoreMapMode( SwViewShell const * pViewShell )
470 : mbMapModeRestored( false )
471 , mpOutDev( pViewShell->GetOut() )
473 if ( pViewShell->getPrePostMapMode() == mpOutDev->GetMapMode() )
474 return;
476 mpOutDev->Push(vcl::PushFlags::MAPMODE);
478 GDIMetaFile* pMetaFile = mpOutDev->GetConnectMetaFile();
479 if ( pMetaFile &&
480 pMetaFile->IsRecord() && !pMetaFile->IsPause() )
482 OSL_FAIL( "MapMode restoration during meta file creation is somehow suspect - using <SetRelativeMapMode(..)>, but not sure, if correct." );
483 mpOutDev->SetRelativeMapMode( pViewShell->getPrePostMapMode() );
485 else
487 mpOutDev->SetMapMode( pViewShell->getPrePostMapMode() );
490 mbMapModeRestored = true;
493 ~RestoreMapMode()
495 if ( mbMapModeRestored )
497 mpOutDev->Pop();
501 private:
502 bool mbMapModeRestored;
503 VclPtr<OutputDevice> mpOutDev;
506 // <--
508 void SwVirtFlyDrawObj::wrap_DoPaintObject(
509 drawinglayer::geometry::ViewInformation2D const& rViewInformation) const
511 SwViewShell* pShell = m_pFlyFrame->getRootFrame()->GetCurrShell();
513 // Only paint when we have a current shell and a DrawingLayer paint is in progress.
514 // This avoids evtl. problems with renderers which do processing stuff,
515 // but no paints. IsPaintInProgress() depends on SW repaint, so, as long
516 // as SW paints self and calls DrawLayer() for Heaven and Hell, this will
517 // be correct
518 if ( !(pShell && pShell->IsDrawingLayerPaintInProgress()) )
519 return;
521 bool bDrawObject(true);
523 if ( !SwFlyFrame::IsPaint( const_cast<SwVirtFlyDrawObj*>(this), pShell ) )
525 bDrawObject = false;
528 if ( !bDrawObject )
529 return;
531 // if there's no viewport set, all fly-frames will be painted,
532 // which is slow, wastes memory, and can cause other trouble.
533 (void) rViewInformation; // suppress "unused parameter" warning
534 assert(comphelper::LibreOfficeKit::isActive() || !rViewInformation.getViewport().isEmpty());
535 if ( m_pFlyFrame->IsFlyInContentFrame() )
536 return;
538 // it is also necessary to restore the VCL MapMode from ViewInformation since e.g.
539 // the VCL PixelRenderer resets it at the used OutputDevice. Unfortunately, this
540 // excludes shears and rotates which are not expressible in MapMode.
541 // OD #i102707#
542 // new helper class to restore MapMode - restoration, only if
543 // needed and consideration of paint for meta file creation .
544 RestoreMapMode aRestoreMapModeIfNeeded( pShell );
546 // paint the FlyFrame (use standard VCL-Paint)
547 m_pFlyFrame->PaintSwFrame( *pShell->GetOut(), m_pFlyFrame->GetPageFrame()->getFrameArea());
550 void SwVirtFlyDrawObj::TakeObjInfo( SdrObjTransformInfoRec& rInfo ) const
552 rInfo.bMoveAllowed =
553 rInfo.bResizeFreeAllowed = rInfo.bResizePropAllowed = true;
555 // RotGrfFlyFrame: Some rotation may be allowed
556 rInfo.bRotateFreeAllowed = rInfo.bRotate90Allowed = HasLimitedRotation();
558 rInfo.bMirrorFreeAllowed = rInfo.bMirror45Allowed =
559 rInfo.bMirror90Allowed = rInfo.bShearAllowed =
560 rInfo.bCanConvToPath = rInfo.bCanConvToPoly =
561 rInfo.bCanConvToPathLineToArea = rInfo.bCanConvToPolyLineToArea = false;
564 // SwVirtFlyDrawObj - Size Determination
566 void SwVirtFlyDrawObj::SetRect() const
568 auto* pWritableThis = const_cast<SwVirtFlyDrawObj*>(this);
569 if ( GetFlyFrame()->getFrameArea().HasArea() )
570 pWritableThis->setOutRectangle(GetFlyFrame()->getFrameArea().SVRect());
571 else
572 pWritableThis->resetOutRectangle();
575 const tools::Rectangle& SwVirtFlyDrawObj::GetCurrentBoundRect() const
577 SetRect();
578 return getOutRectangle();
581 const tools::Rectangle& SwVirtFlyDrawObj::GetLastBoundRect() const
583 return GetCurrentBoundRect();
586 void SwVirtFlyDrawObj::RecalcBoundRect()
588 SetRect();
591 void SwVirtFlyDrawObj::RecalcSnapRect()
593 SetRect();
596 const tools::Rectangle& SwVirtFlyDrawObj::GetSnapRect() const
598 SetRect();
599 return getOutRectangle();
602 void SwVirtFlyDrawObj::SetSnapRect(const tools::Rectangle& )
604 tools::Rectangle aTmp( GetLastBoundRect() );
605 SetRect();
606 SetChanged();
607 BroadcastObjectChange();
608 if (m_pUserCall!=nullptr)
609 m_pUserCall->Changed(*this, SdrUserCallType::Resize, aTmp);
612 void SwVirtFlyDrawObj::NbcSetSnapRect(const tools::Rectangle& )
614 SetRect();
617 const tools::Rectangle& SwVirtFlyDrawObj::GetLogicRect() const
619 SetRect();
620 return getOutRectangle();
623 void SwVirtFlyDrawObj::SetLogicRect(const tools::Rectangle& )
625 tools::Rectangle aTmp( GetLastBoundRect() );
626 SetRect();
627 SetChanged();
628 BroadcastObjectChange();
629 if (m_pUserCall!=nullptr)
630 m_pUserCall->Changed(*this, SdrUserCallType::Resize, aTmp);
633 void SwVirtFlyDrawObj::NbcSetLogicRect(const tools::Rectangle& )
635 SetRect();
638 ::basegfx::B2DPolyPolygon SwVirtFlyDrawObj::TakeXorPoly() const
640 const tools::Rectangle aSourceRectangle(GetFlyFrame()->getFrameArea().SVRect());
641 const ::basegfx::B2DRange aSourceRange = vcl::unotools::b2DRectangleFromRectangle(aSourceRectangle);
642 ::basegfx::B2DPolyPolygon aRetval;
644 aRetval.append(::basegfx::utils::createPolygonFromRect(aSourceRange));
646 return aRetval;
649 // SwVirtFlyDrawObj::Move() and Resize()
650 void SwVirtFlyDrawObj::NbcMove(const Size& rSiz)
652 if(GetFlyFrame()->IsFlyFreeFrame() && static_cast< SwFlyFreeFrame* >(GetFlyFrame())->isTransformableSwFrame())
654 // RotateFlyFrame3: When we have a change and are in transformed state (e.g. rotation used),
655 // we need to fall back to the un-transformed state to keep the old code below
656 // working properly. Restore FrameArea and use aOutRect from old FrameArea.
657 TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
658 pTransformableSwFrame->restoreFrameAreas();
659 setOutRectangle(GetFlyFrame()->getFrameArea().SVRect());
662 moveOutRectangle(rSiz.Width(), rSiz.Height());
664 const Point aOldPos( GetFlyFrame()->getFrameArea().Pos() );
665 const Point aNewPos(getOutRectangle().TopLeft());
666 const SwRect aFlyRect(getOutRectangle());
668 //If the Fly has an automatic align (right or top),
669 //so preserve the automatic.
670 SwFrameFormat *pFormat = GetFlyFrame()->GetFormat();
671 const sal_Int16 eHori = pFormat->GetHoriOrient().GetHoriOrient();
672 const sal_Int16 eVert = pFormat->GetVertOrient().GetVertOrient();
673 const sal_Int16 eRelHori = pFormat->GetHoriOrient().GetRelationOrient();
674 const sal_Int16 eRelVert = pFormat->GetVertOrient().GetRelationOrient();
675 //On paragraph bound Flys starting from the new position a new
676 //anchor must be set. Anchor and the new RelPos is calculated and
677 //placed by the Fly itself.
678 if( GetFlyFrame()->IsFlyAtContentFrame() )
680 static_cast<SwFlyAtContentFrame*>(GetFlyFrame())->SetAbsPos( aNewPos );
682 else
684 const SwFrameFormat *pTmpFormat = GetFormat();
685 const SwFormatVertOrient &rVert = pTmpFormat->GetVertOrient();
686 const SwFormatHoriOrient &rHori = pTmpFormat->GetHoriOrient();
687 tools::Long lXDiff = aNewPos.X() - aOldPos.X();
688 if( rHori.IsPosToggle() && text::HoriOrientation::NONE == eHori &&
689 !GetFlyFrame()->FindPageFrame()->OnRightPage() )
690 lXDiff = -lXDiff;
692 if( GetFlyFrame()->GetAnchorFrame()->IsRightToLeft() &&
693 text::HoriOrientation::NONE == eHori )
694 lXDiff = -lXDiff;
696 tools::Long lYDiff = aNewPos.Y() - aOldPos.Y();
697 if( GetFlyFrame()->GetAnchorFrame()->IsVertical() )
699 //lXDiff -= rVert.GetPos();
700 //lYDiff += rHori.GetPos();
702 if ( GetFlyFrame()->GetAnchorFrame()->IsVertLR() )
704 lXDiff += rVert.GetPos();
705 lXDiff = -lXDiff;
707 else
709 lXDiff -= rVert.GetPos();
710 lYDiff += rHori.GetPos();
713 else
715 lXDiff += rHori.GetPos();
716 lYDiff += rVert.GetPos();
719 if( GetFlyFrame()->GetAnchorFrame()->IsRightToLeft() &&
720 text::HoriOrientation::NONE != eHori )
721 lXDiff = GetFlyFrame()->GetAnchorFrame()->getFrameArea().Width() -
722 aFlyRect.Width() - lXDiff;
724 const Point aTmp( lXDiff, lYDiff );
725 GetFlyFrame()->ChgRelPos( aTmp );
728 SwAttrSet aSet( pFormat->GetDoc()->GetAttrPool(),
729 RES_VERT_ORIENT, RES_HORI_ORIENT );
730 SwFormatHoriOrient aHori( pFormat->GetHoriOrient() );
731 SwFormatVertOrient aVert( pFormat->GetVertOrient() );
732 bool bPut = false;
734 if( !GetFlyFrame()->IsFlyLayFrame() &&
735 ::GetHtmlMode(pFormat->GetDoc()->GetDocShell()) )
737 //In HTML-Mode only automatic aligns are allowed.
738 //Only we can try a snap to left/right respectively left-/right border
739 const SwFrame* pAnch = GetFlyFrame()->GetAnchorFrame();
740 bool bNextLine = false;
742 if( !GetFlyFrame()->IsAutoPos() || text::RelOrientation::PAGE_FRAME != aHori.GetRelationOrient() )
744 if( text::RelOrientation::CHAR == eRelHori )
746 aHori.SetHoriOrient( text::HoriOrientation::LEFT );
747 aHori.SetRelationOrient( text::RelOrientation::CHAR );
749 else
751 bNextLine = true;
752 //Horizontal Align:
753 const bool bLeftFrame =
754 aFlyRect.Left() < pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Left(),
755 bLeftPrt = aFlyRect.Left() + aFlyRect.Width() <
756 pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Width()/2;
757 if ( bLeftFrame || bLeftPrt )
759 aHori.SetHoriOrient( text::HoriOrientation::LEFT );
760 aHori.SetRelationOrient( bLeftFrame ? text::RelOrientation::FRAME : text::RelOrientation::PRINT_AREA );
762 else
764 const bool bRightFrame = aFlyRect.Left() >
765 pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Width();
766 aHori.SetHoriOrient( text::HoriOrientation::RIGHT );
767 aHori.SetRelationOrient( bRightFrame ? text::RelOrientation::FRAME : text::RelOrientation::PRINT_AREA );
770 aSet.Put( aHori );
772 //Vertical alignment simply is retained principally,
773 //only on manual align will be switched over.
774 bool bRelChar = text::RelOrientation::CHAR == eRelVert;
775 aVert.SetVertOrient( eVert != text::VertOrientation::NONE ? eVert :
776 GetFlyFrame()->IsFlyInContentFrame() ? text::VertOrientation::CHAR_CENTER :
777 bRelChar && bNextLine ? text::VertOrientation::CHAR_TOP : text::VertOrientation::TOP );
778 if( bRelChar )
779 aVert.SetRelationOrient( text::RelOrientation::CHAR );
780 else
781 aVert.SetRelationOrient( text::RelOrientation::PRINT_AREA );
782 aSet.Put( aVert );
783 bPut = true;
786 //We want preferably not to lose the automatic alignments.
787 if ( !bPut && bInResize )
789 if ( text::HoriOrientation::NONE != eHori )
791 aHori.SetHoriOrient( eHori );
792 aHori.SetRelationOrient( eRelHori );
793 aSet.Put( aHori );
794 bPut = true;
796 if ( text::VertOrientation::NONE != eVert )
798 aVert.SetVertOrient( eVert );
799 aVert.SetRelationOrient( eRelVert );
800 aSet.Put( aVert );
801 bPut = true;
804 if ( bPut )
805 pFormat->SetFormatAttr( aSet );
809 void SwVirtFlyDrawObj::NbcCrop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
811 // Get Wrt Shell
812 SwWrtShell *pSh = dynamic_cast<SwWrtShell*>( GetFlyFrame()->getRootFrame()->GetCurrShell() );
814 if (!pSh)
816 return;
819 GraphicObject const *pGraphicObject = pSh->GetGraphicObj();
821 if (!pGraphicObject)
823 return;
826 // Get graphic object size in 100th of mm
827 const MapMode aMapMode100thmm(MapUnit::Map100thMM);
828 Size aGraphicSize(pGraphicObject->GetPrefSize());
830 if( MapUnit::MapPixel == pGraphicObject->GetPrefMapMode().GetMapUnit() )
832 aGraphicSize = Application::GetDefaultDevice()->PixelToLogic( aGraphicSize, aMapMode100thmm );
834 else
836 aGraphicSize = OutputDevice::LogicToLogic( aGraphicSize, pGraphicObject->GetPrefMapMode(), aMapMode100thmm);
839 if( aGraphicSize.IsEmpty() )
841 return ;
844 const bool bIsTransformableSwFrame(
845 GetFlyFrame()->IsFlyFreeFrame() &&
846 static_cast< SwFlyFreeFrame* >(GetFlyFrame())->isTransformableSwFrame());
848 if(bIsTransformableSwFrame)
850 // When we have a change and are in transformed state (e.g. rotation used),
851 // we need to fall back to the un-transformed state to keep the old code below
852 // working properly. Restore FrameArea and use aOutRect from old FrameArea.
853 TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
854 pTransformableSwFrame->restoreFrameAreas();
855 setOutRectangle(GetFlyFrame()->getFrameArea().SVRect());
858 // Compute old and new rect. This will give us the deformation to apply to
859 // the object to crop. OldRect is the inner frame, see getFullDragClone()
860 // below where getFramePrintAreaTransformation is used as object geometry for Crop
861 const tools::Rectangle aOldRect(
862 GetFlyFrame()->getFrameArea().TopLeft() + GetFlyFrame()->getFramePrintArea().TopLeft(),
863 GetFlyFrame()->getFramePrintArea().SSize());
864 const tools::Long nOldWidth(aOldRect.GetWidth());
865 const tools::Long nOldHeight(aOldRect.GetHeight());
867 if (!nOldWidth || !nOldHeight)
869 return;
872 // rRef is relative to the Crop-Action, si in X/Y-Ranges of [0.0 .. 1.0],
873 // to get the correct absolute position, transform using the old Rect
874 const Point aRef(
875 aOldRect.Left() + basegfx::fround(aOldRect.GetWidth() * rRef.getX()),
876 aOldRect.Top() + basegfx::fround(aOldRect.GetHeight() * rRef.getY()));
878 // apply transformation, use old ResizeRect for now
879 tools::Rectangle aNewRect( aOldRect );
880 ResizeRect(
881 aNewRect,
882 aRef,
883 Fraction(fxFact),
884 Fraction(fyFact));
886 // Get old values for crop in 10th of mm
887 SfxItemSetFixed<RES_GRFATR_CROPGRF, RES_GRFATR_CROPGRF> aSet( pSh->GetAttrPool() );
888 pSh->GetCurAttr( aSet );
889 SwCropGrf aCrop( aSet.Get(RES_GRFATR_CROPGRF) );
891 tools::Rectangle aCropRectangle(
892 convertTwipToMm100(aCrop.GetLeft()),
893 convertTwipToMm100(aCrop.GetTop()),
894 convertTwipToMm100(aCrop.GetRight()),
895 convertTwipToMm100(aCrop.GetBottom()) );
897 // Compute delta to apply
898 double fScaleX = ( aGraphicSize.Width() - aCropRectangle.Left() - aCropRectangle.Right() ) / static_cast<double>(nOldWidth);
899 double fScaleY = ( aGraphicSize.Height() - aCropRectangle.Top() - aCropRectangle.Bottom() ) / static_cast<double>(nOldHeight);
901 sal_Int32 nDiffLeft = aNewRect.Left() - aOldRect.Left();
902 sal_Int32 nDiffTop = aNewRect.Top() - aOldRect.Top();
903 sal_Int32 nDiffRight = aNewRect.Right() - aOldRect.Right();
904 sal_Int32 nDiffBottom = aNewRect.Bottom() - aOldRect.Bottom();
906 // Compute new values in 10th of mm
907 sal_Int32 nLeftCrop = static_cast<sal_Int32>( aCropRectangle.Left() + nDiffLeft * fScaleX );
908 sal_Int32 nTopCrop = static_cast<sal_Int32>( aCropRectangle.Top() + nDiffTop * fScaleY );
909 sal_Int32 nRightCrop = static_cast<sal_Int32>( aCropRectangle.Right() - nDiffRight * fScaleX );
910 sal_Int32 nBottomCrop = static_cast<sal_Int32>( aCropRectangle.Bottom() - nDiffBottom * fScaleY );
912 // Apply values
913 pSh->StartAllAction();
914 // pSh->StartUndo(SwUndoId::START);
916 // Set new crop values in twips
917 aCrop.SetLeft (o3tl::toTwips(nLeftCrop, o3tl::Length::mm100));
918 aCrop.SetTop (o3tl::toTwips(nTopCrop, o3tl::Length::mm100));
919 aCrop.SetRight (o3tl::toTwips(nRightCrop, o3tl::Length::mm100));
920 aCrop.SetBottom(o3tl::toTwips(nBottomCrop, o3tl::Length::mm100));
921 pSh->SetAttrItem(aCrop);
923 // Set new frame size
924 SwFrameFormat *pFormat = GetFormat();
925 SwFormatFrameSize aSz( pFormat->GetFrameSize() );
926 const tools::Long aNewWidth(aNewRect.GetWidth() + (getOutRectangle().GetWidth() - aOldRect.GetWidth()));
927 const tools::Long aNewHeight(aNewRect.GetHeight() + (getOutRectangle().GetHeight() - aOldRect.GetHeight()));
928 aSz.SetWidth(aNewWidth);
929 aSz.SetHeight(aNewHeight);
930 pFormat->GetDoc()->SetAttr( aSz, *pFormat );
932 // add move - to make result look better. Fill with defaults
933 // for the untransformed case
934 Point aNewTopLeft(aNewRect.TopLeft());
935 const Point aOldTopLeft(aOldRect.TopLeft());
937 if(bIsTransformableSwFrame)
939 // Need to correct the NewTopLeft position in transformed state to make
940 // the interaction look correct. First, extract rotation
941 basegfx::B2DVector aScale, aTranslate;
942 double fRotate, fShearX;
943 GetFlyFrame()->getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
945 // calc the center of the unchanged object
946 const basegfx::B2DPoint aFormerCenter(
947 GetFlyFrame()->getFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5));
949 // define the existing rotation around that former center
950 const basegfx::B2DHomMatrix aRotFormerCenter(
951 basegfx::utils::createRotateAroundPoint(
952 aFormerCenter.getX(),
953 aFormerCenter.getY(),
954 fRotate));
956 // use the new center of the unrotated object, rotate it around the
957 // former center
958 const Point aNewCenter(aNewRect.Center());
959 const basegfx::B2DPoint aRotNewCenter(
960 aRotFormerCenter * basegfx::B2DPoint(aNewCenter.X(), aNewCenter.Y()));
962 // Create the new TopLeft of the unrotated, cropped object by creating
963 // as if re-creating the unrotated geometry
964 aNewTopLeft = Point(
965 basegfx::fround(aRotNewCenter.getX() - (0.5 * aNewRect.getOpenWidth())),
966 basegfx::fround(aRotNewCenter.getY() - (0.5 * aNewRect.getOpenHeight())));
969 // check if we have movement and execute if yes
970 const Size aDeltaMove(
971 aNewTopLeft.X() - aOldTopLeft.X(),
972 aNewTopLeft.Y() - aOldTopLeft.Y());
974 if(0 != aDeltaMove.Width() || 0 != aDeltaMove.Height())
976 NbcMove(aDeltaMove);
979 // pSh->EndUndo(SwUndoId::END);
980 pSh->EndAllAction();
983 void SwVirtFlyDrawObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
985 const SwFrame* pTmpFrame = GetFlyFrame()->GetAnchorFrame();
987 if( !pTmpFrame )
989 pTmpFrame = GetFlyFrame();
992 const bool bVertX(pTmpFrame->IsVertical());
993 const bool bRTL(pTmpFrame->IsRightToLeft());
994 const bool bVertL2RX(pTmpFrame->IsVertLR());
995 const bool bUseRightEdge((bVertX && !bVertL2RX ) || bRTL);
996 const bool bIsTransformableSwFrame(
997 GetFlyFrame()->IsFlyFreeFrame() &&
998 static_cast< SwFlyFreeFrame* >(GetFlyFrame())->isTransformableSwFrame());
1000 tools::Rectangle aRectangle;
1002 if(bIsTransformableSwFrame)
1004 // When we have a change in transformed state, we need to fall back to the
1005 // state without possible transformations.
1006 // In the Resize case to correctly handle the changes, apply to the transformation
1007 // and extract the new, untransformed state from that modified transformation
1008 basegfx::B2DHomMatrix aNewMat(GetFlyFrame()->getFrameAreaTransformation());
1009 const basegfx::B2DPoint aRef(rRef.X(), rRef.Y());
1011 // apply state to already valid transformation
1012 aNewMat.translate(-aRef.getX(), -aRef.getY());
1013 aNewMat.scale(double(xFact), double(yFact));
1014 aNewMat.translate(aRef.getX(), aRef.getY());
1016 // get center of transformed state
1017 const basegfx::B2DPoint aCenter(aNewMat * basegfx::B2DPoint(0.5, 0.5));
1019 // decompose to extract scale
1020 basegfx::B2DVector aScale, aTranslate;
1021 double fRotate, fShearX;
1022 aNewMat.decompose(aScale, aTranslate, fRotate, fShearX);
1023 const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
1025 // create new modified, but untransformed OutRect
1026 setOutRectangle(tools::Rectangle(
1027 basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())),
1028 basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())),
1029 basegfx::fround(aCenter.getX() + (0.5 * aAbsScale.getX())),
1030 basegfx::fround(aCenter.getY() + (0.5 * aAbsScale.getY()))));
1032 // restore FrameAreas so that actions below not adapted to new
1033 // full transformations take the correct actions
1034 TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
1035 pTransformableSwFrame->restoreFrameAreas();
1037 else
1039 aRectangle = getOutRectangle();
1040 ResizeRect(aRectangle, rRef, xFact, yFact);
1041 setOutRectangle(aRectangle);
1044 // Position may also change, remember old one. This is now already
1045 // the one in the unrotated, old coordinate system
1046 Point aOldPos(bUseRightEdge ? GetFlyFrame()->getFrameArea().TopRight() : GetFlyFrame()->getFrameArea().Pos());
1048 // get target size in old coordinate system
1049 aRectangle = getOutRectangle();
1050 Size aSz(aRectangle.Right() - aRectangle.Left() + 1, aRectangle.Bottom() - aRectangle.Top() + 1);
1052 // compare with restored FrameArea
1053 if( aSz != GetFlyFrame()->getFrameArea().SSize() )
1055 //The width of the columns should not be too narrow
1056 if ( GetFlyFrame()->Lower() && GetFlyFrame()->Lower()->IsColumnFrame() )
1058 SwBorderAttrAccess aAccess( SwFrame::GetCache(), GetFlyFrame() );
1059 const SwBorderAttrs &rAttrs = *aAccess.Get();
1060 tools::Long nMin = rAttrs.CalcLeftLine()+rAttrs.CalcRightLine();
1061 const SwFormatCol& rCol = rAttrs.GetAttrSet().GetCol();
1062 if ( rCol.GetColumns().size() > 1 )
1064 for ( const auto &rC : rCol.GetColumns() )
1066 nMin += rC.GetLeft() + rC.GetRight() + MINFLY;
1068 nMin -= MINFLY;
1070 aSz.setWidth( std::max( aSz.Width(), nMin ) );
1073 SwFrameFormat *pFormat = GetFormat();
1074 const SwFormatFrameSize aOldFrameSz( pFormat->GetFrameSize() );
1075 GetFlyFrame()->ChgSize( aSz );
1076 SwFormatFrameSize aFrameSz( pFormat->GetFrameSize() );
1078 if ( aFrameSz.GetWidthPercent() || aFrameSz.GetHeightPercent() )
1080 tools::Long nRelWidth, nRelHeight;
1081 const SwFrame *pRel = GetFlyFrame()->IsFlyLayFrame() ?
1082 GetFlyFrame()->GetAnchorFrame() :
1083 GetFlyFrame()->GetAnchorFrame()->GetUpper();
1084 const SwViewShell *pSh = GetFlyFrame()->getRootFrame()->GetCurrShell();
1086 if ( pSh && pRel->IsBodyFrame() &&
1087 pSh->GetViewOptions()->getBrowseMode() &&
1088 pSh->VisArea().HasArea() )
1090 nRelWidth = pSh->GetBrowseWidth();
1091 nRelHeight = pSh->VisArea().Height();
1092 const Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() );
1093 nRelHeight -= 2*aBorder.Height();
1095 else
1097 nRelWidth = pRel->getFramePrintArea().Width();
1098 nRelHeight = pRel->getFramePrintArea().Height();
1101 if ( aFrameSz.GetWidthPercent() && aFrameSz.GetWidthPercent() != SwFormatFrameSize::SYNCED &&
1102 aOldFrameSz.GetWidth() != aFrameSz.GetWidth() )
1104 aFrameSz.SetWidthPercent( sal_uInt8(aSz.Width() * 100.0 / nRelWidth + 0.5) );
1107 if ( aFrameSz.GetHeightPercent() && aFrameSz.GetHeightPercent() != SwFormatFrameSize::SYNCED &&
1108 aOldFrameSz.GetHeight() != aFrameSz.GetHeight() )
1110 aFrameSz.SetHeightPercent( sal_uInt8(aSz.Height() * 100.0 / nRelHeight + 0.5) );
1113 pFormat->GetDoc()->SetAttr( aFrameSz, *pFormat );
1117 //Position can also be changed, get new one
1118 aRectangle = getOutRectangle();
1119 const Point aNewPos(bUseRightEdge ? aRectangle.Right() + 1 : aRectangle.Left(), aRectangle.Top());
1121 if ( aNewPos == aOldPos )
1122 return;
1124 // Former late change in aOutRect by ChgSize
1125 // is now taken into account directly by calculating
1126 // aNewPos *after* calling ChgSize (see old code).
1127 // Still need to adapt aOutRect since the 'Move' is already applied
1128 // here (see ResizeRect) and it's the same SdrObject
1129 const Size aDeltaMove(
1130 aNewPos.X() - aOldPos.X(),
1131 aNewPos.Y() - aOldPos.Y());
1133 moveOutRectangle(-aDeltaMove.Width(), -aDeltaMove.Height());
1135 // Now, move as needed (no empty delta which was a hack anyways)
1136 if(bIsTransformableSwFrame)
1138 // need to save aOutRect to FrameArea, will be restored to aOutRect in
1139 // SwVirtFlyDrawObj::NbcMove currently for TransformableSwFrames
1140 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*GetFlyFrame());
1141 aFrm.setSwRect(SwRect(getOutRectangle()));
1144 // keep old hack - not clear what happens here
1145 bInResize = true;
1146 NbcMove(aDeltaMove);
1147 bInResize = false;
1150 void SwVirtFlyDrawObj::Move(const Size& rSiz)
1152 NbcMove( rSiz );
1153 SetChanged();
1154 GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
1157 void SwVirtFlyDrawObj::Resize(const Point& rRef,
1158 const Fraction& xFact, const Fraction& yFact, bool /*bUnsetRelative*/)
1160 NbcResize( rRef, xFact, yFact );
1161 SetChanged();
1162 GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
1165 void SwVirtFlyDrawObj::Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
1167 NbcCrop( rRef, fxFact, fyFact );
1168 SetChanged();
1169 GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
1172 // RotGrfFlyFrame: Helper to access possible rotation of Graphic contained in FlyFrame
1173 Degree10 SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame(Size& rSize) const
1175 Degree10 nRetval;
1176 const SwNoTextFrame* pNoTx = dynamic_cast< const SwNoTextFrame* >(GetFlyFrame()->Lower());
1178 if(pNoTx)
1180 SwNoTextNode& rNoTNd = const_cast< SwNoTextNode& >(*static_cast<const SwNoTextNode*>(pNoTx->GetNode()));
1181 SwGrfNode* pGrfNd = rNoTNd.GetGrfNode();
1183 if(nullptr != pGrfNd)
1185 const SwAttrSet& rSet = pGrfNd->GetSwAttrSet();
1186 const SwRotationGrf& rRotation = rSet.GetRotationGrf();
1188 rSize = rRotation.GetUnrotatedSize();
1189 nRetval = rRotation.GetValue();
1193 return nRetval;
1196 Degree100 SwVirtFlyDrawObj::GetRotateAngle() const
1198 if(ContainsSwGrfNode())
1200 Size aSize;
1201 return to<Degree100>(getPossibleRotationFromFraphicFrame(aSize));
1203 else
1205 return SdrVirtObj::GetRotateAngle();
1209 rtl::Reference<SdrObject> SwVirtFlyDrawObj::getFullDragClone() const
1211 // call parent
1212 rtl::Reference<SdrObject> pRetval = SdrVirtObj::getFullDragClone();
1214 if(pRetval && GetFlyFrame() && ContainsSwGrfNode())
1216 // RotGrfFlyFrame3: get inner bounds/transformation
1217 const basegfx::B2DHomMatrix aTargetTransform(GetFlyFrame()->getFramePrintAreaTransformation());
1219 pRetval->TRSetBaseGeometry(aTargetTransform, basegfx::B2DPolyPolygon());
1222 return pRetval;
1225 void SwVirtFlyDrawObj::addCropHandles(SdrHdlList& rTarget) const
1227 // RotGrfFlyFrame: Adapt to possible rotated Graphic contained in FlyFrame
1228 if(!GetFlyFrame()->getFrameArea().HasArea())
1229 return;
1231 // Use InnerBound, OuterBound (same as GetFlyFrame()->getFrameArea().SVRect())
1232 // may have a distance to InnerBound which needs to be taken into account.
1233 // The Graphic is mapped to InnerBound, as is the rotated Graphic.
1234 const basegfx::B2DRange aTargetRange(getInnerBound());
1236 if(aTargetRange.isEmpty())
1237 return;
1239 // RotGrfFlyFrame3: get inner bounds/transformation
1240 const basegfx::B2DHomMatrix aTargetTransform(GetFlyFrame()->getFramePrintAreaTransformation());
1242 // break up matrix
1243 basegfx::B2DTuple aScale;
1244 basegfx::B2DTuple aTranslate;
1245 double fRotate(0.0);
1246 double fShearX(0.0);
1247 aTargetTransform.decompose(aScale, aTranslate, fRotate, fShearX);
1248 basegfx::B2DPoint aPos;
1250 aPos = aTargetTransform * basegfx::B2DPoint(0.0, 0.0);
1251 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::UpperLeft, fShearX, fRotate));
1252 aPos = aTargetTransform * basegfx::B2DPoint(0.5, 0.0);
1253 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Upper, fShearX, fRotate));
1254 aPos = aTargetTransform * basegfx::B2DPoint(1.0, 0.0);
1255 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::UpperRight, fShearX, fRotate));
1256 aPos = aTargetTransform * basegfx::B2DPoint(0.0, 0.5);
1257 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Left , fShearX, fRotate));
1258 aPos = aTargetTransform * basegfx::B2DPoint(1.0, 0.5);
1259 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Right, fShearX, fRotate));
1260 aPos = aTargetTransform * basegfx::B2DPoint(0.0, 1.0);
1261 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::LowerLeft, fShearX, fRotate));
1262 aPos = aTargetTransform * basegfx::B2DPoint(0.5, 1.0);
1263 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Lower, fShearX, fRotate));
1264 aPos = aTargetTransform * basegfx::B2DPoint(1.0, 1.0);
1265 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::LowerRight, fShearX, fRotate));
1268 // Macro
1270 PointerStyle SwVirtFlyDrawObj::GetMacroPointer(
1271 const SdrObjMacroHitRec& ) const
1273 return PointerStyle::RefHand;
1276 bool SwVirtFlyDrawObj::HasMacro() const
1278 const SwFormatURL &rURL = m_pFlyFrame->GetFormat()->GetURL();
1279 return rURL.GetMap() || !rURL.GetURL().isEmpty();
1282 SdrObject* SwVirtFlyDrawObj::CheckMacroHit( const SdrObjMacroHitRec& rRec ) const
1284 const SwFormatURL &rURL = m_pFlyFrame->GetFormat()->GetURL();
1285 if( rURL.GetMap() || !rURL.GetURL().isEmpty() )
1287 SwRect aRect;
1288 if ( m_pFlyFrame->Lower() && m_pFlyFrame->Lower()->IsNoTextFrame() )
1290 aRect = m_pFlyFrame->getFramePrintArea();
1291 aRect += m_pFlyFrame->getFrameArea().Pos();
1293 else
1294 aRect = m_pFlyFrame->getFrameArea();
1296 if( aRect.Contains( rRec.aPos ) )
1298 aRect.Pos().setX(aRect.Pos().getX() + rRec.nTol);
1299 aRect.Pos().setY(aRect.Pos().getY() + rRec.nTol);
1300 aRect.AddHeight( -(2 * rRec.nTol) );
1301 aRect.AddWidth( -(2 * rRec.nTol) );
1303 if( aRect.Contains( rRec.aPos ) )
1305 if( !rURL.GetMap() ||
1306 m_pFlyFrame->GetFormat()->GetIMapObject( rRec.aPos, m_pFlyFrame ))
1307 return const_cast<SwVirtFlyDrawObj*>(this);
1309 return nullptr;
1313 return SdrObject::CheckMacroHit( rRec );
1316 bool SwVirtFlyDrawObj::IsTextBox() const
1318 return SwTextBoxHelper::isTextBox(GetFormat(), RES_FLYFRMFMT, this);
1321 void SwVirtFlyDrawObj::dumpAsXml(xmlTextWriterPtr pWriter) const
1323 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwVirtFlyDrawObj"));
1324 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
1325 (void)xmlTextWriterWriteAttribute(
1326 pWriter, BAD_CAST("fly-frame"),
1327 BAD_CAST(OString::number(m_pFlyFrame->GetFrameId()).getStr()));
1329 SdrVirtObj::dumpAsXml(pWriter);
1331 (void)xmlTextWriterEndElement(pWriter);
1334 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */