nss: upgrade to release 3.73
[LibreOffice.git] / sw / source / core / draw / dflyobj.cxx
blob1d46ff307b6380b9719faae96a6836162a30a8f5
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 <tools/mapunit.hxx>
23 #include <svx/svdhdl.hxx>
24 #include <svx/svdtrans.hxx>
25 #include <editeng/protitem.hxx>
26 #include <svx/svdpage.hxx>
27 #include <vcl/canvastools.hxx>
28 #include <vcl/gdimtf.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/ptrstyle.hxx>
32 #include <fmtclds.hxx>
33 #include <fmtornt.hxx>
34 #include <fmtfsize.hxx>
35 #include <fmturl.hxx>
36 #include <viewsh.hxx>
37 #include <frmatr.hxx>
38 #include <doc.hxx>
39 #include <IDocumentUndoRedo.hxx>
40 #include <dflyobj.hxx>
41 #include <flyfrm.hxx>
42 #include <frmfmt.hxx>
43 #include <viewopt.hxx>
44 #include <frmtool.hxx>
45 #include <flyfrms.hxx>
46 #include <ndnotxt.hxx>
47 #include <grfatr.hxx>
48 #include <pagefrm.hxx>
49 #include <rootfrm.hxx>
50 #include <textboxhelper.hxx>
51 #include <wrtsh.hxx>
52 #include <ndgrf.hxx>
53 #include <frmmgr.hxx>
55 #include <svx/sdr/properties/defaultproperties.hxx>
56 #include <basegfx/range/b2drange.hxx>
57 #include <basegfx/polygon/b2dpolygontools.hxx>
58 #include <basegfx/polygon/b2dpolygon.hxx>
60 // AW: For VCOfDrawVirtObj and stuff
61 #include <svx/sdr/contact/viewcontactofvirtobj.hxx>
62 #include <drawinglayer/primitive2d/baseprimitive2d.hxx>
63 #include <drawinglayer/geometry/viewinformation2d.hxx>
64 #include <sw_primitivetypes2d.hxx>
65 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
66 #include <basegfx/matrix/b2dhommatrixtools.hxx>
67 #include <notxtfrm.hxx>
69 using namespace ::com::sun::star;
71 static bool bInResize = false;
74 namespace sdr::contact
76 namespace {
78 /**
79 * @see #i95264#
81 * currently needed since createViewIndependentPrimitive2DSequence() is called when
82 * RecalcBoundRect() is used. There should currently no VOCs being constructed since it
83 * gets not visualized (instead the corresponding SwVirtFlyDrawObj's referencing this one
84 * are visualized).
86 class VCOfSwFlyDrawObj : public ViewContactOfSdrObj
88 protected:
89 /** This method is responsible for creating the graphical visualisation data
91 * @note ONLY based on model data
93 virtual drawinglayer::primitive2d::Primitive2DContainer createViewIndependentPrimitive2DSequence() const override;
95 public:
96 /// basic constructor, used from SdrObject.
97 explicit VCOfSwFlyDrawObj(SwFlyDrawObj& rObj)
98 : ViewContactOfSdrObj(rObj)
105 drawinglayer::primitive2d::Primitive2DContainer VCOfSwFlyDrawObj::createViewIndependentPrimitive2DSequence() const
107 // currently gets not visualized, return empty sequence
108 return drawinglayer::primitive2d::Primitive2DContainer();
111 } // end of namespace sdr::contact
113 std::unique_ptr<sdr::properties::BaseProperties> SwFlyDrawObj::CreateObjectSpecificProperties()
115 // create default properties
116 return std::make_unique<sdr::properties::DefaultProperties>(*this);
119 std::unique_ptr<sdr::contact::ViewContact> SwFlyDrawObj::CreateObjectSpecificViewContact()
121 // needs an own VC since createViewIndependentPrimitive2DSequence()
122 // is called when RecalcBoundRect() is used
123 return std::make_unique<sdr::contact::VCOfSwFlyDrawObj>(*this);
126 SwFlyDrawObj::SwFlyDrawObj(SdrModel& rSdrModel)
127 : SdrObject(rSdrModel),
128 mbIsTextBox(false)
132 SwFlyDrawObj::~SwFlyDrawObj()
136 // SwFlyDrawObj - Factory-Methods
137 SdrInventor SwFlyDrawObj::GetObjInventor() const
139 return SdrInventor::Swg;
142 SdrObjKind SwFlyDrawObj::GetObjIdentifier() const
144 return SwFlyDrawObjIdentifier;
147 // TODO: Need own primitive to get the FlyFrame paint working
148 namespace drawinglayer::primitive2d
150 namespace {
152 class SwVirtFlyDrawObjPrimitive : public BufferedDecompositionPrimitive2D
154 private:
155 const SwVirtFlyDrawObj& mrSwVirtFlyDrawObj;
156 const basegfx::B2DRange maOuterRange;
158 protected:
159 /// method which is to be used to implement the local decomposition of a 2D primitive
160 virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const override;
162 public:
163 SwVirtFlyDrawObjPrimitive(
164 const SwVirtFlyDrawObj& rSwVirtFlyDrawObj,
165 const basegfx::B2DRange &rOuterRange)
166 : BufferedDecompositionPrimitive2D(),
167 mrSwVirtFlyDrawObj(rSwVirtFlyDrawObj),
168 maOuterRange(rOuterRange)
172 virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
174 virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override;
176 // override to allow callbacks to wrap_DoPaintObject
177 virtual void get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const override;
179 // data read access
180 const SwVirtFlyDrawObj& getSwVirtFlyDrawObj() const { return mrSwVirtFlyDrawObj; }
181 const basegfx::B2DRange& getOuterRange() const { return maOuterRange; }
183 /// provide unique ID
184 virtual sal_uInt32 getPrimitive2DID() const override;
188 } // end of namespace drawinglayer::primitive2d
190 namespace drawinglayer::primitive2d
192 void SwVirtFlyDrawObjPrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
194 if(getOuterRange().isEmpty())
195 return;
197 // currently this SW object has no primitive representation. As long as this is the case,
198 // create invisible geometry to allow correct HitTest and BoundRect calculations for the
199 // object. Use a filled primitive to get 'inside' as default object hit. The special cases from
200 // the old SwVirtFlyDrawObj::CheckHit implementation are handled now in SwDrawView::PickObj;
201 // this removed the 'hack' to get a view from inside model data or to react on null-tolerance
202 // as it was done in the old implementation
203 rContainer.push_back(
204 createHiddenGeometryPrimitives2D(
205 true,
206 getOuterRange()));
209 bool SwVirtFlyDrawObjPrimitive::operator==(const BasePrimitive2D& rPrimitive) const
211 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
213 const SwVirtFlyDrawObjPrimitive& rCompare = static_cast<const SwVirtFlyDrawObjPrimitive&>(rPrimitive);
215 return (&getSwVirtFlyDrawObj() == &rCompare.getSwVirtFlyDrawObj()
216 && getOuterRange() == rCompare.getOuterRange());
219 return false;
222 basegfx::B2DRange SwVirtFlyDrawObjPrimitive::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
224 return getOuterRange();
227 void SwVirtFlyDrawObjPrimitive::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const
229 // This is the callback to keep the FlyFrame painting in SW alive as long as it
230 // is not changed to primitives. This is the method which will be called by the processors
231 // when they do not know this primitive (and they do not). Inside wrap_DoPaintObject
232 // there needs to be a test that paint is only done during SW repaints (see there).
233 // Using this mechanism guarantees the correct Z-Order of the VirtualObject-based FlyFrames.
234 getSwVirtFlyDrawObj().wrap_DoPaintObject(rViewInformation);
236 // call parent
237 BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
240 // provide unique ID
241 ImplPrimitive2DIDBlock(SwVirtFlyDrawObjPrimitive, PRIMITIVE2D_ID_SWVIRTFLYDRAWOBJPRIMITIVE2D)
243 } // end of namespace drawinglayer::primitive2d
245 // AW: own sdr::contact::ViewContact (VC) sdr::contact::ViewObjectContact (VOC) needed
246 // since offset is defined different from SdrVirtObj's sdr::contact::ViewContactOfVirtObj.
247 // For paint, that offset is used by setting at the OutputDevice; for primitives this is
248 // not possible since we have no OutputDevice, but define the geometry itself.
250 namespace sdr::contact
252 namespace {
254 class VCOfSwVirtFlyDrawObj : public ViewContactOfVirtObj
256 protected:
257 /** This method is responsible for creating the graphical visualisation data
259 * @note ONLY based on model data
261 virtual drawinglayer::primitive2d::Primitive2DContainer createViewIndependentPrimitive2DSequence() const override;
263 public:
264 /// basic constructor, used from SdrObject.
265 explicit VCOfSwVirtFlyDrawObj(SwVirtFlyDrawObj& rObj)
266 : ViewContactOfVirtObj(rObj)
270 /// access to SwVirtFlyDrawObj
271 SwVirtFlyDrawObj& GetSwVirtFlyDrawObj() const
273 return static_cast<SwVirtFlyDrawObj&>(mrObject);
278 } // end of namespace sdr::contact
280 namespace sdr::contact
282 drawinglayer::primitive2d::Primitive2DContainer VCOfSwVirtFlyDrawObj::createViewIndependentPrimitive2DSequence() const
284 drawinglayer::primitive2d::Primitive2DContainer xRetval;
285 const SdrObject& rReferencedObject = GetSwVirtFlyDrawObj().GetReferencedObj();
287 if(dynamic_cast<const SwFlyDrawObj*>( &rReferencedObject) != nullptr)
289 // create an own specialized primitive which is used as repaint callpoint and HitTest
290 // for HitTest processor (see primitive implementation above)
291 const basegfx::B2DRange aOuterRange(GetSwVirtFlyDrawObj().getOuterBound());
293 if(!aOuterRange.isEmpty())
295 const drawinglayer::primitive2d::Primitive2DReference xPrimitive(
296 new drawinglayer::primitive2d::SwVirtFlyDrawObjPrimitive(
297 GetSwVirtFlyDrawObj(),
298 aOuterRange));
300 xRetval = drawinglayer::primitive2d::Primitive2DContainer { xPrimitive };
304 return xRetval;
307 } // end of namespace sdr::contact
309 basegfx::B2DRange SwVirtFlyDrawObj::getOuterBound() const
311 basegfx::B2DRange aOuterRange;
312 const SdrObject& rReferencedObject = GetReferencedObj();
314 if(dynamic_cast<const SwFlyDrawObj*>( &rReferencedObject) != nullptr)
316 const SwFlyFrame* pFlyFrame = GetFlyFrame();
318 if(pFlyFrame)
320 const tools::Rectangle aOuterRectangle(pFlyFrame->getFrameArea().Pos(), pFlyFrame->getFrameArea().SSize());
322 if(!aOuterRectangle.IsEmpty())
324 aOuterRange.expand(basegfx::B2DTuple(aOuterRectangle.Left(), aOuterRectangle.Top()));
325 aOuterRange.expand(basegfx::B2DTuple(aOuterRectangle.Right(), aOuterRectangle.Bottom()));
330 return aOuterRange;
333 basegfx::B2DRange SwVirtFlyDrawObj::getInnerBound() const
335 basegfx::B2DRange aInnerRange;
336 const SdrObject& rReferencedObject = GetReferencedObj();
338 if(dynamic_cast<const SwFlyDrawObj*>( &rReferencedObject) != nullptr)
340 const SwFlyFrame* pFlyFrame = GetFlyFrame();
342 if(pFlyFrame)
344 const tools::Rectangle aInnerRectangle(pFlyFrame->getFrameArea().Pos() + pFlyFrame->getFramePrintArea().Pos(), pFlyFrame->getFramePrintArea().SSize());
346 if(!aInnerRectangle.IsEmpty())
348 aInnerRange.expand(basegfx::B2DTuple(aInnerRectangle.Left(), aInnerRectangle.Top()));
349 aInnerRange.expand(basegfx::B2DTuple(aInnerRectangle.Right(), aInnerRectangle.Bottom()));
354 return aInnerRange;
357 bool SwVirtFlyDrawObj::ContainsSwGrfNode() const
359 // RotGrfFlyFrame: Check if this is a SwGrfNode
360 const SwFlyFrame* pFlyFrame(GetFlyFrame());
362 if(nullptr != pFlyFrame && pFlyFrame->Lower() && pFlyFrame->Lower()->IsNoTextFrame())
364 const SwNoTextFrame *const pNTF(static_cast<const SwNoTextFrame*>(pFlyFrame->Lower()));
366 const SwGrfNode *const pGrfNd(pNTF->GetNode()->GetGrfNode());
368 return nullptr != pGrfNd;
371 return false;
374 bool SwVirtFlyDrawObj::HasLimitedRotation() const
376 // RotGrfFlyFrame: If true, this SdrObject supports only limited rotation.
377 // This is the case for SwGrfNode instances
378 return ContainsSwGrfNode();
381 void SwVirtFlyDrawObj::Rotate(const Point& rRef, tools::Long nAngle, double sn, double cs)
383 if(ContainsSwGrfNode())
385 // RotGrfFlyFrame: Here is where the positively completed rotate interaction is executed.
386 // Rotation is in 1/100th degree and may be signed (!)
387 nAngle /= 10;
389 while(nAngle < 0)
391 nAngle += 3600;
394 SwWrtShell *pShForAngle = nAngle ? dynamic_cast<SwWrtShell*>(GetFlyFrame()->getRootFrame()->GetCurrShell()) : nullptr;
395 if (pShForAngle)
397 // RotGrfFlyFrame: Add transformation to placeholder object
398 Size aSize;
399 const sal_uInt16 nOldRot(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame(aSize));
400 SwFlyFrameAttrMgr aMgr(false, pShForAngle, Frmmgr_Type::NONE, nullptr);
402 aMgr.SetRotation(nOldRot, (nOldRot + static_cast<sal_uInt16>(nAngle)) % 3600, aSize);
405 else
407 // call parent
408 SdrVirtObj::Rotate(rRef, nAngle, sn, cs);
412 std::unique_ptr<sdr::contact::ViewContact> SwVirtFlyDrawObj::CreateObjectSpecificViewContact()
414 // need an own ViewContact (VC) to allow creation of a specialized primitive
415 // for being able to visualize the FlyFrames in primitive renderers
416 return std::make_unique<sdr::contact::VCOfSwVirtFlyDrawObj>(*this);
419 SwVirtFlyDrawObj::SwVirtFlyDrawObj(
420 SdrModel& rSdrModel,
421 SdrObject& rNew,
422 SwFlyFrame* pFly)
423 : SdrVirtObj(rSdrModel, rNew),
424 m_pFlyFrame(pFly)
426 const SvxProtectItem &rP = m_pFlyFrame->GetFormat()->GetProtect();
427 bMovProt = rP.IsPosProtected();
428 bSizProt = rP.IsSizeProtected();
431 SwVirtFlyDrawObj::~SwVirtFlyDrawObj()
433 if ( getSdrPageFromSdrObject() ) //Withdraw SdrPage the responsibility.
434 getSdrPageFromSdrObject()->RemoveObject( GetOrdNum() );
437 const SwFrameFormat *SwVirtFlyDrawObj::GetFormat() const
439 return GetFlyFrame()->GetFormat();
441 SwFrameFormat *SwVirtFlyDrawObj::GetFormat()
443 return GetFlyFrame()->GetFormat();
446 // --> OD #i102707#
447 namespace
449 class RestoreMapMode
451 public:
452 explicit RestoreMapMode( SwViewShell const * pViewShell )
453 : mbMapModeRestored( false )
454 , mpOutDev( pViewShell->GetOut() )
456 if ( pViewShell->getPrePostMapMode() == mpOutDev->GetMapMode() )
457 return;
459 mpOutDev->Push(PushFlags::MAPMODE);
461 GDIMetaFile* pMetaFile = mpOutDev->GetConnectMetaFile();
462 if ( pMetaFile &&
463 pMetaFile->IsRecord() && !pMetaFile->IsPause() )
465 OSL_FAIL( "MapMode restoration during meta file creation is somehow suspect - using <SetRelativeMapMode(..)>, but not sure, if correct." );
466 mpOutDev->SetRelativeMapMode( pViewShell->getPrePostMapMode() );
468 else
470 mpOutDev->SetMapMode( pViewShell->getPrePostMapMode() );
473 mbMapModeRestored = true;
476 ~RestoreMapMode()
478 if ( mbMapModeRestored )
480 mpOutDev->Pop();
484 private:
485 bool mbMapModeRestored;
486 VclPtr<OutputDevice> mpOutDev;
489 // <--
491 void SwVirtFlyDrawObj::wrap_DoPaintObject(
492 drawinglayer::geometry::ViewInformation2D const& rViewInformation) const
494 SwViewShell* pShell = m_pFlyFrame->getRootFrame()->GetCurrShell();
496 // Only paint when we have a current shell and a DrawingLayer paint is in progress.
497 // This avoids evtl. problems with renderers which do processing stuff,
498 // but no paints. IsPaintInProgress() depends on SW repaint, so, as long
499 // as SW paints self and calls DrawLayer() for Heaven and Hell, this will
500 // be correct
501 if ( !(pShell && pShell->IsDrawingLayerPaintInProgress()) )
502 return;
504 bool bDrawObject(true);
506 if ( !SwFlyFrame::IsPaint( const_cast<SwVirtFlyDrawObj*>(this), pShell ) )
508 bDrawObject = false;
511 if ( !bDrawObject )
512 return;
514 // if there's no viewport set, all fly-frames will be painted,
515 // which is slow, wastes memory, and can cause other trouble.
516 (void) rViewInformation; // suppress "unused parameter" warning
517 assert(comphelper::LibreOfficeKit::isActive() || !rViewInformation.getViewport().isEmpty());
518 if ( m_pFlyFrame->IsFlyInContentFrame() )
519 return;
521 // it is also necessary to restore the VCL MapMode from ViewInformation since e.g.
522 // the VCL PixelRenderer resets it at the used OutputDevice. Unfortunately, this
523 // excludes shears and rotates which are not expressible in MapMode.
524 // OD #i102707#
525 // new helper class to restore MapMode - restoration, only if
526 // needed and consideration of paint for meta file creation .
527 RestoreMapMode aRestoreMapModeIfNeeded( pShell );
529 // paint the FlyFrame (use standard VCL-Paint)
530 m_pFlyFrame->PaintSwFrame( *pShell->GetOut(), m_pFlyFrame->GetPageFrame()->getFrameArea());
533 void SwVirtFlyDrawObj::TakeObjInfo( SdrObjTransformInfoRec& rInfo ) const
535 rInfo.bMoveAllowed =
536 rInfo.bResizeFreeAllowed = rInfo.bResizePropAllowed = true;
538 // RotGrfFlyFrame: Some rotation may be allowed
539 rInfo.bRotateFreeAllowed = rInfo.bRotate90Allowed = HasLimitedRotation();
541 rInfo.bMirrorFreeAllowed = rInfo.bMirror45Allowed =
542 rInfo.bMirror90Allowed = rInfo.bShearAllowed =
543 rInfo.bCanConvToPath = rInfo.bCanConvToPoly =
544 rInfo.bCanConvToPathLineToArea = rInfo.bCanConvToPolyLineToArea = false;
547 // SwVirtFlyDrawObj - Size Determination
549 void SwVirtFlyDrawObj::SetRect() const
551 if ( GetFlyFrame()->getFrameArea().HasArea() )
552 const_cast<SwVirtFlyDrawObj*>(this)->aOutRect = GetFlyFrame()->getFrameArea().SVRect();
553 else
554 const_cast<SwVirtFlyDrawObj*>(this)->aOutRect = tools::Rectangle();
557 const tools::Rectangle& SwVirtFlyDrawObj::GetCurrentBoundRect() const
559 SetRect();
560 return aOutRect;
563 const tools::Rectangle& SwVirtFlyDrawObj::GetLastBoundRect() const
565 return GetCurrentBoundRect();
568 void SwVirtFlyDrawObj::RecalcBoundRect()
570 SetRect();
573 void SwVirtFlyDrawObj::RecalcSnapRect()
575 SetRect();
578 const tools::Rectangle& SwVirtFlyDrawObj::GetSnapRect() const
580 SetRect();
581 return aOutRect;
584 void SwVirtFlyDrawObj::SetSnapRect(const tools::Rectangle& )
586 tools::Rectangle aTmp( GetLastBoundRect() );
587 SetRect();
588 SetChanged();
589 BroadcastObjectChange();
590 if (pUserCall!=nullptr)
591 pUserCall->Changed(*this, SdrUserCallType::Resize, aTmp);
594 void SwVirtFlyDrawObj::NbcSetSnapRect(const tools::Rectangle& )
596 SetRect();
599 const tools::Rectangle& SwVirtFlyDrawObj::GetLogicRect() const
601 SetRect();
602 return aOutRect;
605 void SwVirtFlyDrawObj::SetLogicRect(const tools::Rectangle& )
607 tools::Rectangle aTmp( GetLastBoundRect() );
608 SetRect();
609 SetChanged();
610 BroadcastObjectChange();
611 if (pUserCall!=nullptr)
612 pUserCall->Changed(*this, SdrUserCallType::Resize, aTmp);
615 void SwVirtFlyDrawObj::NbcSetLogicRect(const tools::Rectangle& )
617 SetRect();
620 ::basegfx::B2DPolyPolygon SwVirtFlyDrawObj::TakeXorPoly() const
622 const tools::Rectangle aSourceRectangle(GetFlyFrame()->getFrameArea().SVRect());
623 const ::basegfx::B2DRange aSourceRange = vcl::unotools::b2DRectangleFromRectangle(aSourceRectangle);
624 ::basegfx::B2DPolyPolygon aRetval;
626 aRetval.append(::basegfx::utils::createPolygonFromRect(aSourceRange));
628 return aRetval;
631 // SwVirtFlyDrawObj::Move() and Resize()
632 void SwVirtFlyDrawObj::NbcMove(const Size& rSiz)
634 if(GetFlyFrame()->IsFlyFreeFrame() && static_cast< SwFlyFreeFrame* >(GetFlyFrame())->isTransformableSwFrame())
636 // RotateFlyFrame3: When we have a change and are in transformed state (e.g. rotation used),
637 // we need to fall back to the un-transformed state to keep the old code below
638 // working properly. Restore FrameArea and use aOutRect from old FrameArea.
639 TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
640 pTransformableSwFrame->restoreFrameAreas();
641 aOutRect = GetFlyFrame()->getFrameArea().SVRect();
644 aOutRect.Move( rSiz );
645 const Point aOldPos( GetFlyFrame()->getFrameArea().Pos() );
646 const Point aNewPos( aOutRect.TopLeft() );
647 const SwRect aFlyRect( aOutRect );
649 //If the Fly has an automatic align (right or top),
650 //so preserve the automatic.
651 SwFrameFormat *pFormat = GetFlyFrame()->GetFormat();
652 const sal_Int16 eHori = pFormat->GetHoriOrient().GetHoriOrient();
653 const sal_Int16 eVert = pFormat->GetVertOrient().GetVertOrient();
654 const sal_Int16 eRelHori = pFormat->GetHoriOrient().GetRelationOrient();
655 const sal_Int16 eRelVert = pFormat->GetVertOrient().GetRelationOrient();
656 //On paragraph bound Flys starting from the new position a new
657 //anchor must be set. Anchor and the new RelPos is calculated and
658 //placed by the Fly itself.
659 if( GetFlyFrame()->IsFlyAtContentFrame() )
661 static_cast<SwFlyAtContentFrame*>(GetFlyFrame())->SetAbsPos( aNewPos );
663 else
665 const SwFrameFormat *pTmpFormat = GetFormat();
666 const SwFormatVertOrient &rVert = pTmpFormat->GetVertOrient();
667 const SwFormatHoriOrient &rHori = pTmpFormat->GetHoriOrient();
668 tools::Long lXDiff = aNewPos.X() - aOldPos.X();
669 if( rHori.IsPosToggle() && text::HoriOrientation::NONE == eHori &&
670 !GetFlyFrame()->FindPageFrame()->OnRightPage() )
671 lXDiff = -lXDiff;
673 if( GetFlyFrame()->GetAnchorFrame()->IsRightToLeft() &&
674 text::HoriOrientation::NONE == eHori )
675 lXDiff = -lXDiff;
677 tools::Long lYDiff = aNewPos.Y() - aOldPos.Y();
678 if( GetFlyFrame()->GetAnchorFrame()->IsVertical() )
680 //lXDiff -= rVert.GetPos();
681 //lYDiff += rHori.GetPos();
683 if ( GetFlyFrame()->GetAnchorFrame()->IsVertLR() )
685 lXDiff += rVert.GetPos();
686 lXDiff = -lXDiff;
688 else
690 lXDiff -= rVert.GetPos();
691 lYDiff += rHori.GetPos();
694 else
696 lXDiff += rHori.GetPos();
697 lYDiff += rVert.GetPos();
700 if( GetFlyFrame()->GetAnchorFrame()->IsRightToLeft() &&
701 text::HoriOrientation::NONE != eHori )
702 lXDiff = GetFlyFrame()->GetAnchorFrame()->getFrameArea().Width() -
703 aFlyRect.Width() - lXDiff;
705 const Point aTmp( lXDiff, lYDiff );
706 GetFlyFrame()->ChgRelPos( aTmp );
709 SwAttrSet aSet( pFormat->GetDoc()->GetAttrPool(),
710 RES_VERT_ORIENT, RES_HORI_ORIENT );
711 SwFormatHoriOrient aHori( pFormat->GetHoriOrient() );
712 SwFormatVertOrient aVert( pFormat->GetVertOrient() );
713 bool bPut = false;
715 if( !GetFlyFrame()->IsFlyLayFrame() &&
716 ::GetHtmlMode(pFormat->GetDoc()->GetDocShell()) )
718 //In HTML-Mode only automatic aligns are allowed.
719 //Only we can try a snap to left/right respectively left-/right border
720 const SwFrame* pAnch = GetFlyFrame()->GetAnchorFrame();
721 bool bNextLine = false;
723 if( !GetFlyFrame()->IsAutoPos() || text::RelOrientation::PAGE_FRAME != aHori.GetRelationOrient() )
725 if( text::RelOrientation::CHAR == eRelHori )
727 aHori.SetHoriOrient( text::HoriOrientation::LEFT );
728 aHori.SetRelationOrient( text::RelOrientation::CHAR );
730 else
732 bNextLine = true;
733 //Horizontal Align:
734 const bool bLeftFrame =
735 aFlyRect.Left() < pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Left(),
736 bLeftPrt = aFlyRect.Left() + aFlyRect.Width() <
737 pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Width()/2;
738 if ( bLeftFrame || bLeftPrt )
740 aHori.SetHoriOrient( text::HoriOrientation::LEFT );
741 aHori.SetRelationOrient( bLeftFrame ? text::RelOrientation::FRAME : text::RelOrientation::PRINT_AREA );
743 else
745 const bool bRightFrame = aFlyRect.Left() >
746 pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Width();
747 aHori.SetHoriOrient( text::HoriOrientation::RIGHT );
748 aHori.SetRelationOrient( bRightFrame ? text::RelOrientation::FRAME : text::RelOrientation::PRINT_AREA );
751 aSet.Put( aHori );
753 //Vertical alignment simply is retained principally,
754 //only on manual align will be switched over.
755 bool bRelChar = text::RelOrientation::CHAR == eRelVert;
756 aVert.SetVertOrient( eVert != text::VertOrientation::NONE ? eVert :
757 GetFlyFrame()->IsFlyInContentFrame() ? text::VertOrientation::CHAR_CENTER :
758 bRelChar && bNextLine ? text::VertOrientation::CHAR_TOP : text::VertOrientation::TOP );
759 if( bRelChar )
760 aVert.SetRelationOrient( text::RelOrientation::CHAR );
761 else
762 aVert.SetRelationOrient( text::RelOrientation::PRINT_AREA );
763 aSet.Put( aVert );
764 bPut = true;
767 //We want preferably not to lose the automatic alignments.
768 if ( !bPut && bInResize )
770 if ( text::HoriOrientation::NONE != eHori )
772 aHori.SetHoriOrient( eHori );
773 aHori.SetRelationOrient( eRelHori );
774 aSet.Put( aHori );
775 bPut = true;
777 if ( text::VertOrientation::NONE != eVert )
779 aVert.SetVertOrient( eVert );
780 aVert.SetRelationOrient( eRelVert );
781 aSet.Put( aVert );
782 bPut = true;
785 if ( bPut )
786 pFormat->SetFormatAttr( aSet );
790 void SwVirtFlyDrawObj::NbcCrop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
792 // Get Wrt Shell
793 SwWrtShell *pSh = dynamic_cast<SwWrtShell*>( GetFlyFrame()->getRootFrame()->GetCurrShell() );
795 if (!pSh)
797 return;
800 GraphicObject const *pGraphicObject = pSh->GetGraphicObj();
802 if (!pGraphicObject)
804 return;
807 // Get graphic object size in 100th of mm
808 const MapMode aMapMode100thmm(MapUnit::Map100thMM);
809 Size aGraphicSize(pGraphicObject->GetPrefSize());
811 if( MapUnit::MapPixel == pGraphicObject->GetPrefMapMode().GetMapUnit() )
813 aGraphicSize = Application::GetDefaultDevice()->PixelToLogic( aGraphicSize, aMapMode100thmm );
815 else
817 aGraphicSize = OutputDevice::LogicToLogic( aGraphicSize, pGraphicObject->GetPrefMapMode(), aMapMode100thmm);
820 if( aGraphicSize.IsEmpty() )
822 return ;
825 const bool bIsTransformableSwFrame(
826 GetFlyFrame()->IsFlyFreeFrame() &&
827 static_cast< SwFlyFreeFrame* >(GetFlyFrame())->isTransformableSwFrame());
829 if(bIsTransformableSwFrame)
831 // When we have a change and are in transformed state (e.g. rotation used),
832 // we need to fall back to the un-transformed state to keep the old code below
833 // working properly. Restore FrameArea and use aOutRect from old FrameArea.
834 TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
835 pTransformableSwFrame->restoreFrameAreas();
836 aOutRect = GetFlyFrame()->getFrameArea().SVRect();
839 // Compute old and new rect. This will give us the deformation to apply to
840 // the object to crop. OldRect is the inner frame, see getFullDragClone()
841 // below where getFramePrintAreaTransformation is used as object geometry for Crop
842 const tools::Rectangle aOldRect(
843 GetFlyFrame()->getFrameArea().TopLeft() + GetFlyFrame()->getFramePrintArea().TopLeft(),
844 GetFlyFrame()->getFramePrintArea().SSize());
845 const tools::Long nOldWidth(aOldRect.GetWidth());
846 const tools::Long nOldHeight(aOldRect.GetHeight());
848 if (!nOldWidth || !nOldHeight)
850 return;
853 // rRef is relative to the Crop-Action, si in X/Y-Ranges of [0.0 .. 1.0],
854 // to get the correct absolute position, transform using the old Rect
855 const Point aRef(
856 aOldRect.Left() + basegfx::fround(aOldRect.GetWidth() * rRef.getX()),
857 aOldRect.Top() + basegfx::fround(aOldRect.GetHeight() * rRef.getY()));
859 // apply transformation, use old ResizeRect for now
860 tools::Rectangle aNewRect( aOldRect );
861 ResizeRect(
862 aNewRect,
863 aRef,
864 Fraction(fxFact),
865 Fraction(fyFact));
867 // Get old values for crop in 10th of mm
868 SfxItemSet aSet( pSh->GetAttrPool(), svl::Items<RES_GRFATR_CROPGRF, RES_GRFATR_CROPGRF>{} );
869 pSh->GetCurAttr( aSet );
870 SwCropGrf aCrop( aSet.Get(RES_GRFATR_CROPGRF) );
872 tools::Rectangle aCropRectangle(
873 convertTwipToMm100(aCrop.GetLeft()),
874 convertTwipToMm100(aCrop.GetTop()),
875 convertTwipToMm100(aCrop.GetRight()),
876 convertTwipToMm100(aCrop.GetBottom()) );
878 // Compute delta to apply
879 double fScaleX = ( aGraphicSize.Width() - aCropRectangle.Left() - aCropRectangle.Right() ) / static_cast<double>(nOldWidth);
880 double fScaleY = ( aGraphicSize.Height() - aCropRectangle.Top() - aCropRectangle.Bottom() ) / static_cast<double>(nOldHeight);
882 sal_Int32 nDiffLeft = aNewRect.Left() - aOldRect.Left();
883 sal_Int32 nDiffTop = aNewRect.Top() - aOldRect.Top();
884 sal_Int32 nDiffRight = aNewRect.Right() - aOldRect.Right();
885 sal_Int32 nDiffBottom = aNewRect.Bottom() - aOldRect.Bottom();
887 // Compute new values in 10th of mm
888 sal_Int32 nLeftCrop = static_cast<sal_Int32>( aCropRectangle.Left() + nDiffLeft * fScaleX );
889 sal_Int32 nTopCrop = static_cast<sal_Int32>( aCropRectangle.Top() + nDiffTop * fScaleY );
890 sal_Int32 nRightCrop = static_cast<sal_Int32>( aCropRectangle.Right() - nDiffRight * fScaleX );
891 sal_Int32 nBottomCrop = static_cast<sal_Int32>( aCropRectangle.Bottom() - nDiffBottom * fScaleY );
893 // Apply values
894 pSh->StartAllAction();
895 // pSh->StartUndo(SwUndoId::START);
897 // Set new crop values in twips
898 aCrop.SetLeft (convertMm100ToTwip(nLeftCrop));
899 aCrop.SetTop (convertMm100ToTwip(nTopCrop));
900 aCrop.SetRight (convertMm100ToTwip(nRightCrop));
901 aCrop.SetBottom(convertMm100ToTwip(nBottomCrop));
902 pSh->SetAttrItem(aCrop);
904 // Set new frame size
905 SwFrameFormat *pFormat = GetFormat();
906 SwFormatFrameSize aSz( pFormat->GetFrameSize() );
907 const tools::Long aNewWidth(aNewRect.GetWidth() + (aOutRect.GetWidth() - aOldRect.GetWidth()));
908 const tools::Long aNewHeight(aNewRect.GetHeight() + (aOutRect.GetHeight() - aOldRect.GetHeight()));
909 aSz.SetWidth(aNewWidth);
910 aSz.SetHeight(aNewHeight);
911 pFormat->GetDoc()->SetAttr( aSz, *pFormat );
913 // add move - to make result look better. Fill with defaults
914 // for the untransformed case
915 Point aNewTopLeft(aNewRect.TopLeft());
916 const Point aOldTopLeft(aOldRect.TopLeft());
918 if(bIsTransformableSwFrame)
920 // Need to correct the NewTopLeft position in transformed state to make
921 // the interaction look correct. First, extract rotation
922 basegfx::B2DVector aScale, aTranslate;
923 double fRotate, fShearX;
924 GetFlyFrame()->getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
926 // calc the center of the unchanged object
927 const basegfx::B2DPoint aFormerCenter(
928 GetFlyFrame()->getFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5));
930 // define the existing rotation around that former center
931 const basegfx::B2DHomMatrix aRotFormerCenter(
932 basegfx::utils::createRotateAroundPoint(
933 aFormerCenter.getX(),
934 aFormerCenter.getY(),
935 fRotate));
937 // use the new center of the unrotated object, rotate it around the
938 // former center
939 const Point aNewCenter(aNewRect.Center());
940 const basegfx::B2DPoint aRotNewCenter(
941 aRotFormerCenter * basegfx::B2DPoint(aNewCenter.X(), aNewCenter.Y()));
943 // Create the new TopLeft of the unrotated, cropped object by creating
944 // as if re-creating the unrotated geometry
945 aNewTopLeft = Point(
946 basegfx::fround(aRotNewCenter.getX() - (0.5 * aNewRect.getWidth())),
947 basegfx::fround(aRotNewCenter.getY() - (0.5 * aNewRect.getHeight())));
950 // check if we have movement and execute if yes
951 const Size aDeltaMove(
952 aNewTopLeft.X() - aOldTopLeft.X(),
953 aNewTopLeft.Y() - aOldTopLeft.Y());
955 if(0 != aDeltaMove.Width() || 0 != aDeltaMove.Height())
957 NbcMove(aDeltaMove);
960 // pSh->EndUndo(SwUndoId::END);
961 pSh->EndAllAction();
964 void SwVirtFlyDrawObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
966 const SwFrame* pTmpFrame = GetFlyFrame()->GetAnchorFrame();
968 if( !pTmpFrame )
970 pTmpFrame = GetFlyFrame();
973 const bool bVertX(pTmpFrame->IsVertical());
974 const bool bRTL(pTmpFrame->IsRightToLeft());
975 const bool bVertL2RX(pTmpFrame->IsVertLR());
976 const bool bUseRightEdge((bVertX && !bVertL2RX ) || bRTL);
977 const bool bIsTransformableSwFrame(
978 GetFlyFrame()->IsFlyFreeFrame() &&
979 static_cast< SwFlyFreeFrame* >(GetFlyFrame())->isTransformableSwFrame());
981 if(bIsTransformableSwFrame)
983 // When we have a change in transformed state, we need to fall back to the
984 // state without possible transformations.
985 // In the Resize case to correctly handle the changes, apply to the transformation
986 // and extract the new, untransformed state from that modified transformation
987 basegfx::B2DHomMatrix aNewMat(GetFlyFrame()->getFrameAreaTransformation());
988 const basegfx::B2DPoint aRef(rRef.X(), rRef.Y());
990 // apply state to already valid transformation
991 aNewMat.translate(-aRef.getX(), -aRef.getY());
992 aNewMat.scale(double(xFact), double(yFact));
993 aNewMat.translate(aRef.getX(), aRef.getY());
995 // get center of transformed state
996 const basegfx::B2DPoint aCenter(aNewMat * basegfx::B2DPoint(0.5, 0.5));
998 // decompose to extract scale
999 basegfx::B2DVector aScale, aTranslate;
1000 double fRotate, fShearX;
1001 aNewMat.decompose(aScale, aTranslate, fRotate, fShearX);
1002 const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
1004 // create new modified, but untransformed OutRect
1005 aOutRect = tools::Rectangle(
1006 basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())),
1007 basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())),
1008 basegfx::fround(aCenter.getX() + (0.5 * aAbsScale.getX())),
1009 basegfx::fround(aCenter.getY() + (0.5 * aAbsScale.getY())));
1011 // restore FrameAreas so that actions below not adapted to new
1012 // full transformations take the correct actions
1013 TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
1014 pTransformableSwFrame->restoreFrameAreas();
1016 else
1018 ResizeRect( aOutRect, rRef, xFact, yFact );
1021 // Position may also change, remember old one. This is now already
1022 // the one in the unrotated, old coordinate system
1023 Point aOldPos(bUseRightEdge ? GetFlyFrame()->getFrameArea().TopRight() : GetFlyFrame()->getFrameArea().Pos());
1025 // get target size in old coordinate system
1026 Size aSz( aOutRect.Right() - aOutRect.Left() + 1, aOutRect.Bottom()- aOutRect.Top() + 1 );
1028 // compare with restored FrameArea
1029 if( aSz != GetFlyFrame()->getFrameArea().SSize() )
1031 //The width of the columns should not be too narrow
1032 if ( GetFlyFrame()->Lower() && GetFlyFrame()->Lower()->IsColumnFrame() )
1034 SwBorderAttrAccess aAccess( SwFrame::GetCache(), GetFlyFrame() );
1035 const SwBorderAttrs &rAttrs = *aAccess.Get();
1036 tools::Long nMin = rAttrs.CalcLeftLine()+rAttrs.CalcRightLine();
1037 const SwFormatCol& rCol = rAttrs.GetAttrSet().GetCol();
1038 if ( rCol.GetColumns().size() > 1 )
1040 for ( const auto &rC : rCol.GetColumns() )
1042 nMin += rC.GetLeft() + rC.GetRight() + MINFLY;
1044 nMin -= MINFLY;
1046 aSz.setWidth( std::max( aSz.Width(), nMin ) );
1049 SwFrameFormat *pFormat = GetFormat();
1050 const SwFormatFrameSize aOldFrameSz( pFormat->GetFrameSize() );
1051 GetFlyFrame()->ChgSize( aSz );
1052 SwFormatFrameSize aFrameSz( pFormat->GetFrameSize() );
1054 if ( aFrameSz.GetWidthPercent() || aFrameSz.GetHeightPercent() )
1056 tools::Long nRelWidth, nRelHeight;
1057 const SwFrame *pRel = GetFlyFrame()->IsFlyLayFrame() ?
1058 GetFlyFrame()->GetAnchorFrame() :
1059 GetFlyFrame()->GetAnchorFrame()->GetUpper();
1060 const SwViewShell *pSh = GetFlyFrame()->getRootFrame()->GetCurrShell();
1062 if ( pSh && pRel->IsBodyFrame() &&
1063 pSh->GetViewOptions()->getBrowseMode() &&
1064 pSh->VisArea().HasArea() )
1066 nRelWidth = pSh->GetBrowseWidth();
1067 nRelHeight = pSh->VisArea().Height();
1068 const Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() );
1069 nRelHeight -= 2*aBorder.Height();
1071 else
1073 nRelWidth = pRel->getFramePrintArea().Width();
1074 nRelHeight = pRel->getFramePrintArea().Height();
1077 if ( aFrameSz.GetWidthPercent() && aFrameSz.GetWidthPercent() != SwFormatFrameSize::SYNCED &&
1078 aOldFrameSz.GetWidth() != aFrameSz.GetWidth() )
1080 aFrameSz.SetWidthPercent( sal_uInt8(aSz.Width() * 100.0 / nRelWidth + 0.5) );
1083 if ( aFrameSz.GetHeightPercent() && aFrameSz.GetHeightPercent() != SwFormatFrameSize::SYNCED &&
1084 aOldFrameSz.GetHeight() != aFrameSz.GetHeight() )
1086 aFrameSz.SetHeightPercent( sal_uInt8(aSz.Height() * 100.0 / nRelHeight + 0.5) );
1089 pFormat->GetDoc()->SetAttr( aFrameSz, *pFormat );
1093 //Position can also be changed, get new one
1094 const Point aNewPos(bUseRightEdge ? aOutRect.Right() + 1 : aOutRect.Left(), aOutRect.Top());
1096 if ( aNewPos == aOldPos )
1097 return;
1099 // Former late change in aOutRect by ChgSize
1100 // is now taken into account directly by calculating
1101 // aNewPos *after* calling ChgSize (see old code).
1102 // Still need to adapt aOutRect since the 'Move' is already applied
1103 // here (see ResizeRect) and it's the same SdrObject
1104 const Size aDeltaMove(
1105 aNewPos.X() - aOldPos.X(),
1106 aNewPos.Y() - aOldPos.Y());
1107 aOutRect.Move(-aDeltaMove.Width(), -aDeltaMove.Height());
1109 // Now, move as needed (no empty delta which was a hack anyways)
1110 if(bIsTransformableSwFrame)
1112 // need to save aOutRect to FrameArea, will be restored to aOutRect in
1113 // SwVirtFlyDrawObj::NbcMove currently for TransformableSwFrames
1114 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*GetFlyFrame());
1115 aFrm.setSwRect(aOutRect);
1118 // keep old hack - not clear what happens here
1119 bInResize = true;
1120 NbcMove(aDeltaMove);
1121 bInResize = false;
1124 void SwVirtFlyDrawObj::Move(const Size& rSiz)
1126 NbcMove( rSiz );
1127 SetChanged();
1128 GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
1131 void SwVirtFlyDrawObj::Resize(const Point& rRef,
1132 const Fraction& xFact, const Fraction& yFact, bool /*bUnsetRelative*/)
1134 NbcResize( rRef, xFact, yFact );
1135 SetChanged();
1136 GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
1139 void SwVirtFlyDrawObj::Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
1141 NbcCrop( rRef, fxFact, fyFact );
1142 SetChanged();
1143 GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
1146 // RotGrfFlyFrame: Helper to access possible rotation of Graphic contained in FlyFrame
1147 sal_uInt16 SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame(Size& rSize) const
1149 sal_uInt16 nRetval(0);
1150 const SwNoTextFrame* pNoTx = dynamic_cast< const SwNoTextFrame* >(GetFlyFrame()->Lower());
1152 if(pNoTx)
1154 SwNoTextNode& rNoTNd = const_cast< SwNoTextNode& >(*static_cast<const SwNoTextNode*>(pNoTx->GetNode()));
1155 SwGrfNode* pGrfNd = rNoTNd.GetGrfNode();
1157 if(nullptr != pGrfNd)
1159 const SwAttrSet& rSet = pGrfNd->GetSwAttrSet();
1160 const SwRotationGrf& rRotation = rSet.GetRotationGrf();
1162 rSize = rRotation.GetUnrotatedSize();
1163 nRetval = rRotation.GetValue();
1167 return nRetval;
1170 tools::Long SwVirtFlyDrawObj::GetRotateAngle() const
1172 if(ContainsSwGrfNode())
1174 Size aSize;
1175 return getPossibleRotationFromFraphicFrame(aSize);
1177 else
1179 return SdrVirtObj::GetRotateAngle();
1183 SdrObjectUniquePtr SwVirtFlyDrawObj::getFullDragClone() const
1185 // call parent
1186 SdrObjectUniquePtr pRetval = SdrVirtObj::getFullDragClone();
1188 if(pRetval && GetFlyFrame() && ContainsSwGrfNode())
1190 // RotGrfFlyFrame3: get inner bounds/transformation
1191 const basegfx::B2DHomMatrix aTargetTransform(GetFlyFrame()->getFramePrintAreaTransformation());
1193 pRetval->TRSetBaseGeometry(aTargetTransform, basegfx::B2DPolyPolygon());
1196 return pRetval;
1199 void SwVirtFlyDrawObj::addCropHandles(SdrHdlList& rTarget) const
1201 // RotGrfFlyFrame: Adapt to possible rotated Graphic contained in FlyFrame
1202 if(!GetFlyFrame()->getFrameArea().HasArea())
1203 return;
1205 // Use InnerBound, OuterBound (same as GetFlyFrame()->getFrameArea().SVRect())
1206 // may have a distance to InnerBound which needs to be taken into account.
1207 // The Graphic is mapped to InnerBound, as is the rotated Graphic.
1208 const basegfx::B2DRange aTargetRange(getInnerBound());
1210 if(aTargetRange.isEmpty())
1211 return;
1213 // RotGrfFlyFrame3: get inner bounds/transformation
1214 const basegfx::B2DHomMatrix aTargetTransform(GetFlyFrame()->getFramePrintAreaTransformation());
1216 // break up matrix
1217 basegfx::B2DTuple aScale;
1218 basegfx::B2DTuple aTranslate;
1219 double fRotate(0.0);
1220 double fShearX(0.0);
1221 aTargetTransform.decompose(aScale, aTranslate, fRotate, fShearX);
1222 basegfx::B2DPoint aPos;
1224 aPos = aTargetTransform * basegfx::B2DPoint(0.0, 0.0);
1225 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::UpperLeft, fShearX, fRotate));
1226 aPos = aTargetTransform * basegfx::B2DPoint(0.5, 0.0);
1227 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Upper, fShearX, fRotate));
1228 aPos = aTargetTransform * basegfx::B2DPoint(1.0, 0.0);
1229 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::UpperRight, fShearX, fRotate));
1230 aPos = aTargetTransform * basegfx::B2DPoint(0.0, 0.5);
1231 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Left , fShearX, fRotate));
1232 aPos = aTargetTransform * basegfx::B2DPoint(1.0, 0.5);
1233 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Right, fShearX, fRotate));
1234 aPos = aTargetTransform * basegfx::B2DPoint(0.0, 1.0);
1235 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::LowerLeft, fShearX, fRotate));
1236 aPos = aTargetTransform * basegfx::B2DPoint(0.5, 1.0);
1237 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Lower, fShearX, fRotate));
1238 aPos = aTargetTransform * basegfx::B2DPoint(1.0, 1.0);
1239 rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::LowerRight, fShearX, fRotate));
1242 // Macro
1244 PointerStyle SwVirtFlyDrawObj::GetMacroPointer(
1245 const SdrObjMacroHitRec& ) const
1247 return PointerStyle::RefHand;
1250 bool SwVirtFlyDrawObj::HasMacro() const
1252 const SwFormatURL &rURL = m_pFlyFrame->GetFormat()->GetURL();
1253 return rURL.GetMap() || !rURL.GetURL().isEmpty();
1256 SdrObject* SwVirtFlyDrawObj::CheckMacroHit( const SdrObjMacroHitRec& rRec ) const
1258 const SwFormatURL &rURL = m_pFlyFrame->GetFormat()->GetURL();
1259 if( rURL.GetMap() || !rURL.GetURL().isEmpty() )
1261 SwRect aRect;
1262 if ( m_pFlyFrame->Lower() && m_pFlyFrame->Lower()->IsNoTextFrame() )
1264 aRect = m_pFlyFrame->getFramePrintArea();
1265 aRect += m_pFlyFrame->getFrameArea().Pos();
1267 else
1268 aRect = m_pFlyFrame->getFrameArea();
1270 if( aRect.IsInside( rRec.aPos ) )
1272 aRect.Pos().setX(aRect.Pos().getX() + rRec.nTol);
1273 aRect.Pos().setY(aRect.Pos().getY() + rRec.nTol);
1274 aRect.AddHeight( -(2 * rRec.nTol) );
1275 aRect.AddWidth( -(2 * rRec.nTol) );
1277 if( aRect.IsInside( rRec.aPos ) )
1279 if( !rURL.GetMap() ||
1280 m_pFlyFrame->GetFormat()->GetIMapObject( rRec.aPos, m_pFlyFrame ))
1281 return const_cast<SwVirtFlyDrawObj*>(this);
1283 return nullptr;
1287 return SdrObject::CheckMacroHit( rRec );
1290 bool SwVirtFlyDrawObj::IsTextBox() const
1292 return SwTextBoxHelper::isTextBox(GetFormat(), RES_FLYFRMFMT);
1295 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */