1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 #include <comphelper/string.hxx>
22 #include <svl/stritem.hxx>
23 #include <svx/svdotext.hxx>
24 #include <svx/svdpage.hxx>
25 #include <svx/svdoutl.hxx>
26 #include <svx/svdmodel.hxx>
27 #include <svx/dialmgr.hxx>
28 #include <svx/strings.hrc>
29 #include <editeng/writingmodeitem.hxx>
30 #include <svx/sdtfchim.hxx>
31 #include <editeng/editdata.hxx>
32 #include <editeng/editstat.hxx>
33 #include <editeng/outlobj.hxx>
34 #include <editeng/editobj.hxx>
35 #include <editeng/outliner.hxx>
36 #include <textchain.hxx>
37 #include <textchainflow.hxx>
38 #include <tools/helpers.hxx>
39 #include <svx/sderitm.hxx>
40 #include <svx/sdooitm.hxx>
41 #include <svx/sdshitm.hxx>
42 #include <svx/sdtagitm.hxx>
43 #include <svx/sdtfsitm.hxx>
44 #include <svx/sdtmfitm.hxx>
45 #include <svx/xtextit0.hxx>
46 #include <svx/compatflags.hxx>
47 #include <sdr/properties/textproperties.hxx>
48 #include <sdr/contact/viewcontactoftextobj.hxx>
49 #include <basegfx/tuple/b2dtuple.hxx>
50 #include <basegfx/matrix/b2dhommatrix.hxx>
51 #include <vcl/gdimtf.hxx>
52 #include <vcl/virdev.hxx>
53 #include <basegfx/matrix/b2dhommatrixtools.hxx>
54 #include <sal/log.hxx>
55 #include <o3tl/unit_conversion.hxx>
56 #include <o3tl/temporary.hxx>
57 #include <unotools/configmgr.hxx>
58 #include <editeng/eeitem.hxx>
59 #include <editeng/fhgtitem.hxx>
61 using namespace com::sun::star
;
63 // BaseProperties section
64 std::unique_ptr
<sdr::properties::BaseProperties
> SdrTextObj::CreateObjectSpecificProperties()
66 return std::make_unique
<sdr::properties::TextProperties
>(*this);
69 // DrawContact section
70 std::unique_ptr
<sdr::contact::ViewContact
> SdrTextObj::CreateObjectSpecificViewContact()
72 return std::make_unique
<sdr::contact::ViewContactOfTextObj
>(*this);
75 SdrTextObj::SdrTextObj(SdrModel
& rSdrModel
)
76 : SdrAttrObj(rSdrModel
)
77 , mpEditingOutliner(nullptr)
78 , meTextKind(SdrObjKind::Text
)
79 , maTextEditOffset(Point(0, 0))
82 , mbTextSizeDirty(false)
84 , mbDisableAutoWidthOnDragging(false)
85 , mbTextAnimationAllowed(true)
86 , mbInDownScale(false)
89 mbSupportTextIndentingOnLineWidthChange
= true;
92 SdrTextObj::SdrTextObj(SdrModel
& rSdrModel
, SdrTextObj
const & rSource
)
93 : SdrAttrObj(rSdrModel
, rSource
)
94 , mpEditingOutliner(nullptr)
95 , meTextKind(rSource
.meTextKind
)
96 , maTextEditOffset(Point(0, 0))
97 , mbTextFrame(rSource
.mbTextFrame
)
98 , mbNoShear(rSource
.mbNoShear
)
99 , mbTextSizeDirty(rSource
.mbTextSizeDirty
)
100 , mbInEditMode(false)
101 , mbDisableAutoWidthOnDragging(rSource
.mbDisableAutoWidthOnDragging
)
102 , mbTextAnimationAllowed(true)
103 , mbInDownScale(false)
106 mbSupportTextIndentingOnLineWidthChange
= true;
108 maRectangle
= rSource
.maRectangle
;
109 maGeo
= rSource
.maGeo
;
110 maTextSize
= rSource
.maTextSize
;
112 // Not all of the necessary parameters were copied yet.
113 SdrText
* pText
= getActiveText();
115 if( pText
&& rSource
.HasText() )
117 // before pNewOutlinerParaObject was created the same, but
118 // set at mpText (outside this scope), but mpText might be
119 // empty (this operator== seems not prepared for MultiText
120 // objects). In the current form it makes only sense to
121 // create locally and use locally on a known existing SdrText
122 const Outliner
* pEO
= rSource
.mpEditingOutliner
;
123 std::optional
<OutlinerParaObject
> pNewOutlinerParaObject
;
127 pNewOutlinerParaObject
= pEO
->CreateParaObject();
129 else if (nullptr != rSource
.getActiveText()->GetOutlinerParaObject())
131 pNewOutlinerParaObject
= *rSource
.getActiveText()->GetOutlinerParaObject();
134 pText
->SetOutlinerParaObject( std::move(pNewOutlinerParaObject
) );
137 ImpSetTextStyleSheetListeners();
140 SdrTextObj::SdrTextObj(SdrModel
& rSdrModel
, const tools::Rectangle
& rNewRect
)
141 : SdrAttrObj(rSdrModel
)
142 , mpEditingOutliner(nullptr)
143 , meTextKind(SdrObjKind::Text
)
144 , maTextEditOffset(Point(0, 0))
147 , mbTextSizeDirty(false)
148 , mbInEditMode(false)
149 , mbDisableAutoWidthOnDragging(false)
150 , mbTextAnimationAllowed(true)
151 , mbInDownScale(false)
153 tools::Rectangle
aRectangle(rNewRect
);
154 ImpJustifyRect(aRectangle
);
155 setRectangle(aRectangle
);
158 mbSupportTextIndentingOnLineWidthChange
= true;
161 SdrTextObj::SdrTextObj(SdrModel
& rSdrModel
, SdrObjKind eNewTextKind
)
162 : SdrAttrObj(rSdrModel
)
163 , mpEditingOutliner(nullptr)
164 , meTextKind(eNewTextKind
)
165 , maTextEditOffset(Point(0, 0))
168 , mbTextSizeDirty(false)
169 , mbInEditMode(false)
170 , mbDisableAutoWidthOnDragging(false)
171 , mbTextAnimationAllowed(true)
172 , mbInDownScale(false)
175 mbSupportTextIndentingOnLineWidthChange
= true;
178 SdrTextObj::SdrTextObj(SdrModel
& rSdrModel
, SdrObjKind eNewTextKind
,
179 const tools::Rectangle
& rNewRect
)
180 : SdrAttrObj(rSdrModel
)
181 , mpEditingOutliner(nullptr)
182 , meTextKind(eNewTextKind
)
183 , maTextEditOffset(Point(0, 0))
186 , mbTextSizeDirty(false)
187 , mbInEditMode(false)
188 , mbDisableAutoWidthOnDragging(false)
189 , mbTextAnimationAllowed(true)
190 , mbInDownScale(false)
192 tools::Rectangle
aRectangle(rNewRect
);
193 ImpJustifyRect(aRectangle
);
194 setRectangle(aRectangle
);
197 mbSupportTextIndentingOnLineWidthChange
= true;
200 SdrTextObj::~SdrTextObj()
206 void SdrTextObj::FitFrameToTextSize()
208 ImpJustifyRect(maRectangle
);
210 SdrText
* pText
= getActiveText();
211 if(pText
==nullptr || !pText
->GetOutlinerParaObject())
214 SdrOutliner
& rOutliner
=ImpGetDrawOutliner();
215 rOutliner
.SetPaperSize(Size(getRectangle().Right() - getRectangle().Left(), getRectangle().Bottom() - getRectangle().Top()));
216 rOutliner
.SetUpdateLayout(true);
217 rOutliner
.SetText(*pText
->GetOutlinerParaObject());
218 Size
aNewSize(rOutliner
.CalcTextSize());
220 aNewSize
.AdjustWidth( 1 ); // because of possible rounding errors
221 aNewSize
.AdjustWidth(GetTextLeftDistance()+GetTextRightDistance() );
222 aNewSize
.AdjustHeight(GetTextUpperDistance()+GetTextLowerDistance() );
223 tools::Rectangle
aNewRect(getRectangle());
224 aNewRect
.SetSize(aNewSize
);
225 ImpJustifyRect(aNewRect
);
227 if (aNewRect
!= getRectangle())
228 SetLogicRect(aNewRect
);
231 void SdrTextObj::NbcSetText(const OUString
& rStr
)
233 SdrOutliner
& rOutliner
=ImpGetDrawOutliner();
234 rOutliner
.SetStyleSheet( 0, GetStyleSheet());
235 rOutliner
.SetText(rStr
,rOutliner
.GetParagraph( 0 ));
236 std::optional
<OutlinerParaObject
> pNewText
=rOutliner
.CreateParaObject();
237 NbcSetOutlinerParaObject(std::move(pNewText
));
238 mbTextSizeDirty
=true;
241 void SdrTextObj::SetText(const OUString
& rStr
)
243 tools::Rectangle aBoundRect0
; if (m_pUserCall
!=nullptr) aBoundRect0
=GetLastBoundRect();
246 BroadcastObjectChange();
247 SendUserCall(SdrUserCallType::Resize
,aBoundRect0
);
250 void SdrTextObj::NbcSetText(SvStream
& rInput
, const OUString
& rBaseURL
, EETextFormat eFormat
)
252 SdrOutliner
& rOutliner
=ImpGetDrawOutliner();
253 rOutliner
.SetStyleSheet( 0, GetStyleSheet());
254 rOutliner
.Read(rInput
,rBaseURL
,eFormat
);
255 std::optional
<OutlinerParaObject
> pNewText
=rOutliner
.CreateParaObject();
256 rOutliner
.SetUpdateLayout(true);
257 Size
aSize(rOutliner
.CalcTextSize());
259 NbcSetOutlinerParaObject(std::move(pNewText
));
261 mbTextSizeDirty
=false;
264 void SdrTextObj::SetText(SvStream
& rInput
, const OUString
& rBaseURL
, EETextFormat eFormat
)
266 tools::Rectangle aBoundRect0
; if (m_pUserCall
!=nullptr) aBoundRect0
=GetLastBoundRect();
267 NbcSetText(rInput
,rBaseURL
,eFormat
);
269 BroadcastObjectChange();
270 SendUserCall(SdrUserCallType::Resize
,aBoundRect0
);
273 const Size
& SdrTextObj::GetTextSize() const
278 SdrText
* pText
= getActiveText();
279 if( pText
&& pText
->GetOutlinerParaObject ())
281 SdrOutliner
& rOutliner
=ImpGetDrawOutliner();
282 rOutliner
.SetText(*pText
->GetOutlinerParaObject());
283 rOutliner
.SetUpdateLayout(true);
284 aSiz
=rOutliner
.CalcTextSize();
287 // casting to nonconst twice
288 const_cast<SdrTextObj
*>(this)->maTextSize
= aSiz
;
289 const_cast<SdrTextObj
*>(this)->mbTextSizeDirty
= false;
294 bool SdrTextObj::IsAutoGrowHeight() const
297 return false; // AutoGrow only together with TextFrames
299 const SfxItemSet
& rSet
= GetObjectItemSet();
300 bool bRet
= rSet
.Get(SDRATTR_TEXT_AUTOGROWHEIGHT
).GetValue();
304 SdrTextAniKind eAniKind
= rSet
.Get(SDRATTR_TEXT_ANIKIND
).GetValue();
306 if(eAniKind
== SdrTextAniKind::Scroll
|| eAniKind
== SdrTextAniKind::Alternate
|| eAniKind
== SdrTextAniKind::Slide
)
308 SdrTextAniDirection eDirection
= rSet
.Get(SDRATTR_TEXT_ANIDIRECTION
).GetValue();
310 if(eDirection
== SdrTextAniDirection::Up
|| eDirection
== SdrTextAniDirection::Down
)
319 bool SdrTextObj::IsAutoGrowWidth() const
322 return false; // AutoGrow only together with TextFrames
324 const SfxItemSet
& rSet
= GetObjectItemSet();
325 bool bRet
= rSet
.Get(SDRATTR_TEXT_AUTOGROWWIDTH
).GetValue();
327 bool bInEditMOde
= IsInEditMode();
329 if(!bInEditMOde
&& bRet
)
331 SdrTextAniKind eAniKind
= rSet
.Get(SDRATTR_TEXT_ANIKIND
).GetValue();
333 if(eAniKind
== SdrTextAniKind::Scroll
|| eAniKind
== SdrTextAniKind::Alternate
|| eAniKind
== SdrTextAniKind::Slide
)
335 SdrTextAniDirection eDirection
= rSet
.Get(SDRATTR_TEXT_ANIDIRECTION
).GetValue();
337 if(eDirection
== SdrTextAniDirection::Left
|| eDirection
== SdrTextAniDirection::Right
)
346 SdrTextHorzAdjust
SdrTextObj::GetTextHorizontalAdjust() const
348 return GetTextHorizontalAdjust(GetObjectItemSet());
351 SdrTextHorzAdjust
SdrTextObj::GetTextHorizontalAdjust(const SfxItemSet
& rSet
) const
353 if(IsContourTextFrame())
354 return SDRTEXTHORZADJUST_BLOCK
;
356 SdrTextHorzAdjust eRet
= rSet
.Get(SDRATTR_TEXT_HORZADJUST
).GetValue();
358 bool bInEditMode
= IsInEditMode();
360 if(!bInEditMode
&& eRet
== SDRTEXTHORZADJUST_BLOCK
)
362 SdrTextAniKind eAniKind
= rSet
.Get(SDRATTR_TEXT_ANIKIND
).GetValue();
364 if(eAniKind
== SdrTextAniKind::Scroll
|| eAniKind
== SdrTextAniKind::Alternate
|| eAniKind
== SdrTextAniKind::Slide
)
366 SdrTextAniDirection eDirection
= rSet
.Get(SDRATTR_TEXT_ANIDIRECTION
).GetValue();
368 if(eDirection
== SdrTextAniDirection::Left
|| eDirection
== SdrTextAniDirection::Right
)
370 eRet
= SDRTEXTHORZADJUST_LEFT
;
376 } // defaults: BLOCK (justify) for text frame, CENTER for captions of drawing objects
378 SdrTextVertAdjust
SdrTextObj::GetTextVerticalAdjust() const
380 return GetTextVerticalAdjust(GetObjectItemSet());
383 SdrTextVertAdjust
SdrTextObj::GetTextVerticalAdjust(const SfxItemSet
& rSet
) const
385 if(IsContourTextFrame())
386 return SDRTEXTVERTADJUST_TOP
;
388 // Take care for vertical text animation here
389 SdrTextVertAdjust eRet
= rSet
.Get(SDRATTR_TEXT_VERTADJUST
).GetValue();
390 bool bInEditMode
= IsInEditMode();
392 // Take care for vertical text animation here
393 if(!bInEditMode
&& eRet
== SDRTEXTVERTADJUST_BLOCK
)
395 SdrTextAniKind eAniKind
= rSet
.Get(SDRATTR_TEXT_ANIKIND
).GetValue();
397 if(eAniKind
== SdrTextAniKind::Scroll
|| eAniKind
== SdrTextAniKind::Alternate
|| eAniKind
== SdrTextAniKind::Slide
)
399 SdrTextAniDirection eDirection
= rSet
.Get(SDRATTR_TEXT_ANIDIRECTION
).GetValue();
401 if(eDirection
== SdrTextAniDirection::Left
|| eDirection
== SdrTextAniDirection::Right
)
403 eRet
= SDRTEXTVERTADJUST_TOP
;
409 } // defaults: TOP for text frame, CENTER for captions of drawing objects
411 void SdrTextObj::ImpJustifyRect(tools::Rectangle
& rRect
)
413 if (!rRect
.IsEmpty()) {
415 if (rRect
.Left()==rRect
.Right()) rRect
.AdjustRight( 1 );
416 if (rRect
.Top()==rRect
.Bottom()) rRect
.AdjustBottom( 1 );
420 void SdrTextObj::ImpCheckShear()
422 if (mbNoShear
&& maGeo
.nShearAngle
)
424 maGeo
.nShearAngle
= 0_deg100
;
425 maGeo
.mfTanShearAngle
= 0;
429 void SdrTextObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
431 bool bNoTextFrame
=!IsTextFrame();
432 rInfo
.bResizeFreeAllowed
=bNoTextFrame
|| ((maGeo
.nRotationAngle
.get() % 9000) == 0);
433 rInfo
.bResizePropAllowed
=true;
434 rInfo
.bRotateFreeAllowed
=true;
435 rInfo
.bRotate90Allowed
=true;
436 rInfo
.bMirrorFreeAllowed
=bNoTextFrame
;
437 rInfo
.bMirror45Allowed
=bNoTextFrame
;
438 rInfo
.bMirror90Allowed
=bNoTextFrame
;
440 // allow transparency
441 rInfo
.bTransparenceAllowed
= true;
443 rInfo
.bShearAllowed
=bNoTextFrame
;
444 rInfo
.bEdgeRadiusAllowed
=true;
445 bool bCanConv
=ImpCanConvTextToCurve();
446 rInfo
.bCanConvToPath
=bCanConv
;
447 rInfo
.bCanConvToPoly
=bCanConv
;
448 rInfo
.bCanConvToPathLineToArea
=bCanConv
;
449 rInfo
.bCanConvToPolyLineToArea
=bCanConv
;
450 rInfo
.bCanConvToContour
= (rInfo
.bCanConvToPoly
|| LineGeometryUsageIsNecessary());
453 SdrObjKind
SdrTextObj::GetObjIdentifier() const
458 bool SdrTextObj::HasTextImpl( SdrOutliner
const * pOutliner
)
463 Paragraph
* p1stPara
=pOutliner
->GetParagraph( 0 );
464 sal_Int32 nParaCount
=pOutliner
->GetParagraphCount();
465 if(p1stPara
==nullptr)
470 // if it is only one paragraph, check if that paragraph is empty
471 if( pOutliner
->GetText(p1stPara
).isEmpty() )
480 void SdrTextObj::handlePageChange(SdrPage
* pOldPage
, SdrPage
* pNewPage
)
482 const bool bRemove(pNewPage
== nullptr && pOldPage
!= nullptr);
483 const bool bInsert(pNewPage
!= nullptr && pOldPage
== nullptr);
484 const bool bLinked(IsLinkedText());
486 if (bLinked
&& bRemove
)
492 SdrAttrObj::handlePageChange(pOldPage
, pNewPage
);
494 if (bLinked
&& bInsert
)
500 void SdrTextObj::NbcSetEckenradius(tools::Long nRad
)
502 SetObjectItem(makeSdrEckenradiusItem(nRad
));
505 // #115391# This implementation is based on the object size (aRect) and the
506 // states of IsAutoGrowWidth/Height to correctly set TextMinFrameWidth/Height
507 void SdrTextObj::AdaptTextMinSize()
510 // Only do this for text frame.
513 if (getSdrModelFromSdrObject().IsPasteResize())
514 // Don't do this during paste resize.
517 const bool bW
= IsAutoGrowWidth();
518 const bool bH
= IsAutoGrowHeight();
521 // No auto grow requested. Bail out.
524 SfxItemSetFixed
<SDRATTR_TEXT_MINFRAMEHEIGHT
, SDRATTR_TEXT_AUTOGROWHEIGHT
,
525 SDRATTR_TEXT_MINFRAMEWIDTH
, SDRATTR_TEXT_AUTOGROWWIDTH
> // contains SDRATTR_TEXT_MAXFRAMEWIDTH
526 aSet(*GetObjectItemSet().GetPool());
530 // Set minimum width.
531 const tools::Long nDist
= GetTextLeftDistance() + GetTextRightDistance();
532 const tools::Long nW
= std::max
<tools::Long
>(0, getRectangle().GetWidth() - 1 - nDist
); // text width without margins
534 aSet
.Put(makeSdrTextMinFrameWidthItem(nW
));
536 if(!IsVerticalWriting() && mbDisableAutoWidthOnDragging
)
538 mbDisableAutoWidthOnDragging
= true;
539 aSet
.Put(makeSdrTextAutoGrowWidthItem(false));
545 // Set Minimum height.
546 const tools::Long nDist
= GetTextUpperDistance() + GetTextLowerDistance();
547 const tools::Long nH
= std::max
<tools::Long
>(0, getRectangle().GetHeight() - 1 - nDist
); // text height without margins
549 aSet
.Put(makeSdrTextMinFrameHeightItem(nH
));
551 if(IsVerticalWriting() && mbDisableAutoWidthOnDragging
)
553 mbDisableAutoWidthOnDragging
= false;
554 aSet
.Put(makeSdrTextAutoGrowHeightItem(false));
558 SetObjectItemSet(aSet
);
561 void SdrTextObj::ImpSetContourPolygon( SdrOutliner
& rOutliner
, tools::Rectangle
const & rAnchorRect
, bool bLineWidth
) const
563 basegfx::B2DPolyPolygon
aXorPolyPolygon(TakeXorPoly());
564 std::optional
<basegfx::B2DPolyPolygon
> pContourPolyPolygon
;
565 basegfx::B2DHomMatrix
aMatrix(basegfx::utils::createTranslateB2DHomMatrix(
566 -rAnchorRect
.Left(), -rAnchorRect
.Top()));
568 if(maGeo
.nRotationAngle
)
571 aMatrix
.rotate(-toRadians(maGeo
.nRotationAngle
));
574 aXorPolyPolygon
.transform(aMatrix
);
578 // Take line width into account.
579 // When doing the hit test, avoid this. (Performance!)
580 pContourPolyPolygon
.emplace();
582 // test if shadow needs to be avoided for TakeContour()
583 const SfxItemSet
& rSet
= GetObjectItemSet();
584 bool bShadowOn
= rSet
.Get(SDRATTR_SHADOW
).GetValue();
587 // Remember TextObject currently set at the DrawOutliner, it WILL be
588 // replaced during calculating the outline since it uses an own paint
589 // and that one uses the DrawOutliner, too.
590 const SdrTextObj
* pLastTextObject
= rOutliner
.GetTextObj();
595 rtl::Reference
<SdrTextObj
> pCopy
= SdrObject::Clone(*this, getSdrModelFromSdrObject());
596 pCopy
->SetMergedItem(makeSdrShadowItem(false));
597 *pContourPolyPolygon
= pCopy
->TakeContour();
601 *pContourPolyPolygon
= TakeContour();
605 // restore remembered text object
606 if(pLastTextObject
!= rOutliner
.GetTextObj())
608 rOutliner
.SetTextObj(pLastTextObject
);
611 pContourPolyPolygon
->transform(aMatrix
);
614 rOutliner
.SetPolygon(aXorPolyPolygon
, pContourPolyPolygon
? &*pContourPolyPolygon
: nullptr);
617 void SdrTextObj::TakeUnrotatedSnapRect(tools::Rectangle
& rRect
) const
619 rRect
= getRectangle();
622 // See also: <unnamed>::getTextAnchorRange in svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
623 void SdrTextObj::AdjustRectToTextDistance(tools::Rectangle
& rAnchorRect
) const
625 const tools::Long nLeftDist
= GetTextLeftDistance();
626 const tools::Long nRightDist
= GetTextRightDistance();
627 const tools::Long nUpperDist
= GetTextUpperDistance();
628 const tools::Long nLowerDist
= GetTextLowerDistance();
629 if (!IsVerticalWriting())
631 rAnchorRect
.AdjustLeft(nLeftDist
);
632 rAnchorRect
.AdjustTop(nUpperDist
);
633 rAnchorRect
.AdjustRight(-nRightDist
);
634 rAnchorRect
.AdjustBottom(-nLowerDist
);
636 else if (IsTopToBottom())
638 rAnchorRect
.AdjustLeft(nLowerDist
);
639 rAnchorRect
.AdjustTop(nLeftDist
);
640 rAnchorRect
.AdjustRight(-nUpperDist
);
641 rAnchorRect
.AdjustBottom(-nRightDist
);
645 rAnchorRect
.AdjustLeft(nUpperDist
);
646 rAnchorRect
.AdjustTop(nRightDist
);
647 rAnchorRect
.AdjustRight(-nLowerDist
);
648 rAnchorRect
.AdjustBottom(-nLeftDist
);
651 // Since sizes may be bigger than the object bounds it is necessary to
652 // justify the rect now.
653 ImpJustifyRect(rAnchorRect
);
656 void SdrTextObj::TakeTextAnchorRect(tools::Rectangle
& rAnchorRect
) const
658 tools::Rectangle
aAnkRect(getRectangle()); // the rectangle in which we anchor
659 bool bFrame
=IsTextFrame();
661 TakeUnrotatedSnapRect(aAnkRect
);
663 Point
aRotateRef(aAnkRect
.TopLeft());
664 AdjustRectToTextDistance(aAnkRect
);
667 // TODO: Optimize this.
668 if (aAnkRect
.GetWidth()<2) aAnkRect
.SetRight(aAnkRect
.Left()+1 ); // minimum size h and v: 2 px
669 if (aAnkRect
.GetHeight()<2) aAnkRect
.SetBottom(aAnkRect
.Top()+1 );
671 if (maGeo
.nRotationAngle
) {
672 Point
aTmpPt(aAnkRect
.TopLeft());
673 RotatePoint(aTmpPt
,aRotateRef
,maGeo
.mfSinRotationAngle
,maGeo
.mfCosRotationAngle
);
674 aTmpPt
-=aAnkRect
.TopLeft();
675 aAnkRect
.Move(aTmpPt
.X(),aTmpPt
.Y());
677 rAnchorRect
=aAnkRect
;
680 void SdrTextObj::TakeTextRect( SdrOutliner
& rOutliner
, tools::Rectangle
& rTextRect
, bool bNoEditText
,
681 tools::Rectangle
* pAnchorRect
, bool bLineWidth
) const
683 tools::Rectangle aAnkRect
; // the rectangle in which we anchor
684 TakeTextAnchorRect(aAnkRect
);
685 SdrTextVertAdjust eVAdj
=GetTextVerticalAdjust();
686 SdrTextHorzAdjust eHAdj
=GetTextHorizontalAdjust();
687 SdrTextAniKind eAniKind
=GetTextAniKind();
688 SdrTextAniDirection eAniDirection
=GetTextAniDirection();
690 bool bFitToSize(IsFitToSize());
691 bool bContourFrame
=IsContourTextFrame();
693 bool bFrame
=IsTextFrame();
694 EEControlBits nStat0
=rOutliner
.GetControlWord();
698 rOutliner
.SetControlWord(nStat0
|EEControlBits::AUTOPAGESIZE
);
699 rOutliner
.SetMinAutoPaperSize(aNullSize
);
700 rOutliner
.SetMaxAutoPaperSize(Size(1000000,1000000));
703 if (!bFitToSize
&& !bContourFrame
)
705 tools::Long nAnkWdt
=aAnkRect
.GetWidth();
706 tools::Long nAnkHgt
=aAnkRect
.GetHeight();
709 tools::Long nWdt
=nAnkWdt
;
710 tools::Long nHgt
=nAnkHgt
;
712 bool bInEditMode
= IsInEditMode();
714 if (!bInEditMode
&& (eAniKind
==SdrTextAniKind::Scroll
|| eAniKind
==SdrTextAniKind::Alternate
|| eAniKind
==SdrTextAniKind::Slide
))
716 // unlimited paper size for ticker text
717 if (eAniDirection
==SdrTextAniDirection::Left
|| eAniDirection
==SdrTextAniDirection::Right
) nWdt
=1000000;
718 if (eAniDirection
==SdrTextAniDirection::Up
|| eAniDirection
==SdrTextAniDirection::Down
) nHgt
=1000000;
721 bool bChainedFrame
= IsChainable();
722 // Might be required for overflow check working: do limit height to frame if box is chainable.
723 if (!bChainedFrame
) {
724 // #i119885# Do not limit/force height to geometrical frame (vice versa for vertical writing)
726 if(IsVerticalWriting())
736 rOutliner
.SetMaxAutoPaperSize(Size(nWdt
,nHgt
));
739 // New try with _BLOCK for hor and ver after completely
740 // supporting full width for vertical text.
741 if(SDRTEXTHORZADJUST_BLOCK
== eHAdj
&& !IsVerticalWriting())
743 rOutliner
.SetMinAutoPaperSize(Size(nAnkWdt
, 0));
744 rOutliner
.SetMinColumnWrapHeight(nAnkHgt
);
747 if(SDRTEXTVERTADJUST_BLOCK
== eVAdj
&& IsVerticalWriting())
749 rOutliner
.SetMinAutoPaperSize(Size(0, nAnkHgt
));
750 rOutliner
.SetMinColumnWrapHeight(nAnkWdt
);
754 rOutliner
.SetPaperSize(aNullSize
);
756 ImpSetContourPolygon( rOutliner
, aAnkRect
, bLineWidth
);
758 // put text into the outliner, if available from the edit outliner
759 SdrText
* pText
= getActiveText();
760 OutlinerParaObject
* pOutlinerParaObject
= pText
? pText
->GetOutlinerParaObject() : nullptr;
761 std::optional
<OutlinerParaObject
> pPara
;
762 if (mpEditingOutliner
&& !bNoEditText
)
763 pPara
= mpEditingOutliner
->CreateParaObject();
764 else if (pOutlinerParaObject
)
765 pPara
= *pOutlinerParaObject
;
769 const bool bHitTest(&getSdrModelFromSdrObject().GetHitTestOutliner() == &rOutliner
);
770 const SdrTextObj
* pTestObj
= rOutliner
.GetTextObj();
772 if( !pTestObj
|| !bHitTest
|| pTestObj
!= this ||
773 pTestObj
->GetOutlinerParaObject() != pOutlinerParaObject
)
775 if( bHitTest
) // #i33696# take back fix #i27510#
777 rOutliner
.SetTextObj( this );
778 rOutliner
.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT
).GetValue());
781 rOutliner
.SetUpdateLayout(true);
782 rOutliner
.SetText(*pPara
);
787 rOutliner
.SetTextObj( nullptr );
790 rOutliner
.SetUpdateLayout(true);
791 rOutliner
.SetControlWord(nStat0
);
794 pText
->CheckPortionInfo(rOutliner
);
796 Point
aTextPos(aAnkRect
.TopLeft());
797 Size
aTextSiz(rOutliner
.GetPaperSize()); // GetPaperSize() adds a little tolerance, right?
799 // For draw objects containing text correct hor/ver alignment if text is bigger
800 // than the object itself. Without that correction, the text would always be
801 // formatted to the left edge (or top edge when vertical) of the draw object.
804 if(aAnkRect
.GetWidth() < aTextSiz
.Width() && !IsVerticalWriting())
806 // Horizontal case here. Correct only if eHAdj == SDRTEXTHORZADJUST_BLOCK,
807 // else the alignment is wanted.
808 if(SDRTEXTHORZADJUST_BLOCK
== eHAdj
)
810 eHAdj
= SDRTEXTHORZADJUST_CENTER
;
814 if(aAnkRect
.GetHeight() < aTextSiz
.Height() && IsVerticalWriting())
816 // Vertical case here. Correct only if eHAdj == SDRTEXTVERTADJUST_BLOCK,
817 // else the alignment is wanted.
818 if(SDRTEXTVERTADJUST_BLOCK
== eVAdj
)
820 eVAdj
= SDRTEXTVERTADJUST_CENTER
;
825 if (eHAdj
==SDRTEXTHORZADJUST_CENTER
|| eHAdj
==SDRTEXTHORZADJUST_RIGHT
)
827 tools::Long nFreeWdt
=aAnkRect
.GetWidth()-aTextSiz
.Width();
828 if (eHAdj
==SDRTEXTHORZADJUST_CENTER
)
829 aTextPos
.AdjustX(nFreeWdt
/2 );
830 if (eHAdj
==SDRTEXTHORZADJUST_RIGHT
)
831 aTextPos
.AdjustX(nFreeWdt
);
833 if (eVAdj
==SDRTEXTVERTADJUST_CENTER
|| eVAdj
==SDRTEXTVERTADJUST_BOTTOM
)
835 tools::Long nFreeHgt
=aAnkRect
.GetHeight()-aTextSiz
.Height();
836 if (eVAdj
==SDRTEXTVERTADJUST_CENTER
)
837 aTextPos
.AdjustY(nFreeHgt
/2 );
838 if (eVAdj
==SDRTEXTVERTADJUST_BOTTOM
)
839 aTextPos
.AdjustY(nFreeHgt
);
841 if (maGeo
.nRotationAngle
)
842 RotatePoint(aTextPos
,aAnkRect
.TopLeft(),maGeo
.mfSinRotationAngle
,maGeo
.mfCosRotationAngle
);
845 *pAnchorRect
=aAnkRect
;
847 // rTextRect might not be correct in some cases at ContourFrame
848 rTextRect
=tools::Rectangle(aTextPos
,aTextSiz
);
853 bool SdrTextObj::CanCreateEditOutlinerParaObject() const
855 if( HasTextImpl( mpEditingOutliner
) )
857 return mpEditingOutliner
->GetParagraphCount() > 0;
862 std::optional
<OutlinerParaObject
> SdrTextObj::CreateEditOutlinerParaObject() const
864 std::optional
<OutlinerParaObject
> pPara
;
865 if( HasTextImpl( mpEditingOutliner
) )
867 sal_Int32 nParaCount
= mpEditingOutliner
->GetParagraphCount();
868 pPara
= mpEditingOutliner
->CreateParaObject(0, nParaCount
);
873 void SdrTextObj::ImpSetCharStretching(SdrOutliner
& rOutliner
, const Size
& rTextSize
, const Size
& rShapeSize
, Fraction
& rFitXCorrection
)
875 OutputDevice
* pOut
= rOutliner
.GetRefDevice();
876 bool bNoStretching(false);
878 if(pOut
&& pOut
->GetOutDevType() == OUTDEV_PRINTER
)
880 // check whether CharStretching is possible at all
881 GDIMetaFile
* pMtf
= pOut
->GetConnectMetaFile();
882 OUString
aTestString(u
'J');
884 if(pMtf
&& (!pMtf
->IsRecord() || pMtf
->IsPause()))
890 vcl::Font
aOriginalFont(pOut
->GetFont());
891 vcl::Font
aTmpFont( OutputDevice::GetDefaultFont( DefaultFontType::SERIF
, LANGUAGE_SYSTEM
, GetDefaultFontFlags::OnlyOne
) );
893 aTmpFont
.SetFontSize(Size(0,100));
894 pOut
->SetFont(aTmpFont
);
895 Size
aSize1(pOut
->GetTextWidth(aTestString
), pOut
->GetTextHeight());
896 aTmpFont
.SetFontSize(Size(800,100));
897 pOut
->SetFont(aTmpFont
);
898 Size
aSize2(pOut
->GetTextWidth(aTestString
), pOut
->GetTextHeight());
899 pOut
->SetFont(aOriginalFont
);
904 bNoStretching
= (aSize1
== aSize2
);
907 // Windows zooms the font proportionally when using Size(100,500),
908 // we don't like that.
909 if(aSize2
.Height() >= aSize1
.Height() * 2)
911 bNoStretching
= true;
916 rOutliner
.setRoundFontSizeToPt(false);
918 unsigned nLoopCount
=0;
919 bool bNoMoreLoop
= false;
920 tools::Long nXDiff0
=0x7FFFFFFF;
921 tools::Long nWantWdt
=rShapeSize
.Width();
922 tools::Long nIsWdt
=rTextSize
.Width();
923 if (nIsWdt
==0) nIsWdt
=1;
925 tools::Long nWantHgt
=rShapeSize
.Height();
926 tools::Long nIsHgt
=rTextSize
.Height();
927 if (nIsHgt
==0) nIsHgt
=1;
929 tools::Long nXTolPl
=nWantWdt
/100; // tolerance: +1%
930 tools::Long nXTolMi
=nWantWdt
/25; // tolerance: -4%
931 tools::Long nXCorr
=nWantWdt
/20; // correction scale: 5%
933 double nX
= (nWantWdt
* 100.0) / double(nIsWdt
); // calculate X stretching
934 double nY
= (nWantHgt
* 100.0) / double(nIsHgt
); // calculate Y stretching
937 { // might only be possible proportionally
949 while (nLoopCount
<5 && !bNoMoreLoop
)
979 // exception, there is no text yet (horizontal case)
986 // exception, there is no text yet (vertical case)
992 rOutliner
.setGlobalScale(nX
, nY
);
994 Size
aSiz(rOutliner
.CalcTextSize());
995 tools::Long nXDiff
= aSiz
.Width() - nWantWdt
;
996 rFitXCorrection
=Fraction(nWantWdt
,aSiz
.Width());
997 if (((nXDiff
>=nXTolMi
|| !bChkX
) && nXDiff
<=nXTolPl
) || nXDiff
==nXDiff0
) {
1000 // correct stretching factors
1001 tools::Long nMul
= nWantWdt
;
1002 tools::Long nDiv
= aSiz
.Width();
1003 if (std::abs(nXDiff
) <= 2 * nXCorr
)
1006 nDiv
+= (nMul
- nDiv
) / 2.0; // but only add half of what we calculated,
1008 nMul
+= (nDiv
- nMul
) / 2.0;// because the EditEngine calculates wrongly later on
1010 nX
= nX
* double(nMul
) / double(nDiv
);
1018 OUString
SdrTextObj::TakeObjNameSingul() const
1024 case SdrObjKind::OutlineText
:
1026 aStr
= SvxResId(STR_ObjNameSingulOUTLINETEXT
);
1030 case SdrObjKind::TitleText
:
1032 aStr
= SvxResId(STR_ObjNameSingulTITLETEXT
);
1039 aStr
= SvxResId(STR_ObjNameSingulTEXTLNK
);
1041 aStr
= SvxResId(STR_ObjNameSingulTEXT
);
1046 OutlinerParaObject
* pOutlinerParaObject
= GetOutlinerParaObject();
1047 if(pOutlinerParaObject
&& meTextKind
!= SdrObjKind::OutlineText
)
1049 // shouldn't currently cause any problems at OUTLINETEXT
1050 OUString
aStr2(comphelper::string::stripStart(pOutlinerParaObject
->GetTextObject().GetText(0), ' '));
1052 // avoid non expanded text portions in object name
1053 // (second condition is new)
1054 if(!aStr2
.isEmpty() && aStr2
.indexOf(u
'\x00FF') == -1)
1056 // space between ResStr and content text
1059 if(aStr2
.getLength() > 10)
1061 aStr2
= OUString::Concat(aStr2
.subView(0, 8)) + "...";
1064 aStr
+= aStr2
+ "\'";
1068 OUString
sName(aStr
);
1070 OUString
aName(GetName());
1071 if (!aName
.isEmpty())
1072 sName
+= " '" + aName
+ "'";
1077 OUString
SdrTextObj::TakeObjNamePlural() const
1082 case SdrObjKind::OutlineText
: sName
=SvxResId(STR_ObjNamePluralOUTLINETEXT
); break;
1083 case SdrObjKind::TitleText
: sName
=SvxResId(STR_ObjNamePluralTITLETEXT
); break;
1085 if (IsLinkedText()) {
1086 sName
=SvxResId(STR_ObjNamePluralTEXTLNK
);
1088 sName
=SvxResId(STR_ObjNamePluralTEXT
);
1095 rtl::Reference
<SdrObject
> SdrTextObj::CloneSdrObject(SdrModel
& rTargetModel
) const
1097 return new SdrTextObj(rTargetModel
, *this);
1100 basegfx::B2DPolyPolygon
SdrTextObj::TakeXorPoly() const
1102 tools::Polygon
aPol(getRectangle());
1103 if (maGeo
.nShearAngle
)
1104 ShearPoly(aPol
, getRectangle().TopLeft(), maGeo
.mfTanShearAngle
);
1105 if (maGeo
.nRotationAngle
)
1106 RotatePoly(aPol
, getRectangle().TopLeft(), maGeo
.mfSinRotationAngle
, maGeo
.mfCosRotationAngle
);
1108 basegfx::B2DPolyPolygon aRetval
;
1109 aRetval
.append(aPol
.getB2DPolygon());
1113 basegfx::B2DPolyPolygon
SdrTextObj::TakeContour() const
1115 basegfx::B2DPolyPolygon
aRetval(SdrAttrObj::TakeContour());
1117 // and now add the BoundRect of the text, if necessary
1118 if ( GetOutlinerParaObject() && !IsFontwork() && !IsContourTextFrame() )
1120 // using Clone()-Paint() strategy inside TakeContour() leaves a destroyed
1121 // SdrObject as pointer in DrawOutliner. Set *this again in fetching the outliner
1123 SdrOutliner
& rOutliner
=ImpGetDrawOutliner();
1125 tools::Rectangle aAnchor2
;
1126 tools::Rectangle aR
;
1127 TakeTextRect(rOutliner
,aR
,false,&aAnchor2
);
1129 bool bFitToSize(IsFitToSize());
1130 if (bFitToSize
) aR
=aAnchor2
;
1131 tools::Polygon
aPol(aR
);
1132 if (maGeo
.nRotationAngle
) RotatePoly(aPol
,aR
.TopLeft(), maGeo
.mfSinRotationAngle
, maGeo
.mfCosRotationAngle
);
1134 aRetval
.append(aPol
.getB2DPolygon());
1140 void SdrTextObj::RecalcSnapRect()
1142 if (maGeo
.nRotationAngle
|| maGeo
.nShearAngle
)
1144 maSnapRect
= Rect2Poly(getRectangle(), maGeo
).GetBoundRect();
1146 maSnapRect
= getRectangle();
1150 sal_uInt32
SdrTextObj::GetSnapPointCount() const
1155 Point
SdrTextObj::GetSnapPoint(sal_uInt32 i
) const
1158 auto aRectangle
= getRectangle();
1160 case 0: aP
= aRectangle
.TopLeft(); break;
1161 case 1: aP
= aRectangle
.TopRight(); break;
1162 case 2: aP
= aRectangle
.BottomLeft(); break;
1163 case 3: aP
= aRectangle
.BottomRight(); break;
1164 default: aP
= aRectangle
.Center(); break;
1166 if (maGeo
.nShearAngle
)
1167 ShearPoint(aP
, aRectangle
.TopLeft(), maGeo
.mfTanShearAngle
);
1168 if (maGeo
.nRotationAngle
)
1169 RotatePoint(aP
, aRectangle
.TopLeft(), maGeo
.mfSinRotationAngle
, maGeo
.mfCosRotationAngle
);
1173 // Extracted from ImpGetDrawOutliner()
1174 void SdrTextObj::ImpInitDrawOutliner( SdrOutliner
& rOutl
) const
1176 rOutl
.SetUpdateLayout(false);
1177 OutlinerMode nOutlinerMode
= OutlinerMode::OutlineObject
;
1178 if ( !IsOutlText() )
1179 nOutlinerMode
= OutlinerMode::TextObject
;
1180 rOutl
.Init( nOutlinerMode
);
1182 rOutl
.setGlobalScale(100.0, 100.0, 100.0, 100.0);
1184 EEControlBits nStat
=rOutl
.GetControlWord();
1185 nStat
&= ~EEControlBits(EEControlBits::STRETCHING
|EEControlBits::AUTOPAGESIZE
);
1186 rOutl
.SetControlWord(nStat
);
1187 Size
aMaxSize(100000,100000);
1188 rOutl
.SetMinAutoPaperSize(Size());
1189 rOutl
.SetMaxAutoPaperSize(aMaxSize
);
1190 rOutl
.SetPaperSize(aMaxSize
);
1191 rOutl
.ClearPolygon();
1194 SdrOutliner
& SdrTextObj::ImpGetDrawOutliner() const
1196 SdrOutliner
& rOutl(getSdrModelFromSdrObject().GetDrawOutliner(this));
1198 // Code extracted to ImpInitDrawOutliner()
1199 ImpInitDrawOutliner( rOutl
);
1204 // Extracted from Paint()
1205 void SdrTextObj::ImpSetupDrawOutlinerForPaint( bool bContourFrame
,
1206 SdrOutliner
& rOutliner
,
1207 tools::Rectangle
& rTextRect
,
1208 tools::Rectangle
& rAnchorRect
,
1209 tools::Rectangle
& rPaintRect
,
1210 Fraction
& rFitXCorrection
) const
1214 // FitToSize can't be used together with ContourFrame for now
1215 if (IsFitToSize() || IsAutoFit())
1217 EEControlBits nStat
=rOutliner
.GetControlWord();
1218 nStat
|=EEControlBits::STRETCHING
|EEControlBits::AUTOPAGESIZE
;
1219 rOutliner
.SetControlWord(nStat
);
1222 rOutliner
.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT
).GetValue());
1223 TakeTextRect(rOutliner
, rTextRect
, false, &rAnchorRect
);
1224 rPaintRect
= rTextRect
;
1229 // FitToSize can't be used together with ContourFrame for now
1232 ImpSetCharStretching(rOutliner
,rTextRect
.GetSize(),rAnchorRect
.GetSize(),rFitXCorrection
);
1233 rPaintRect
=rAnchorRect
;
1235 else if (IsAutoFit())
1237 ImpAutoFitText(rOutliner
);
1241 double SdrTextObj::GetFontScale() const
1243 SdrOutliner
& rOutliner
= ImpGetDrawOutliner();
1244 // This eventually calls ImpAutoFitText
1245 UpdateOutlinerFormatting(rOutliner
, o3tl::temporary(tools::Rectangle()));
1248 rOutliner
.getGlobalScale(o3tl::temporary(double()), fScaleY
, o3tl::temporary(double()), o3tl::temporary(double()));
1252 double SdrTextObj::GetSpacingScale() const
1254 SdrOutliner
& rOutliner
= ImpGetDrawOutliner();
1255 // This eventually calls ImpAutoFitText
1256 UpdateOutlinerFormatting(rOutliner
, o3tl::temporary(tools::Rectangle()));
1258 double fSpacingScaleY
;
1259 rOutliner
.getGlobalScale(o3tl::temporary(double()), o3tl::temporary(double()), o3tl::temporary(double()), fSpacingScaleY
);
1260 return fSpacingScaleY
;
1263 void SdrTextObj::ImpAutoFitText( SdrOutliner
& rOutliner
) const
1265 const Size aShapeSize
=GetSnapRect().GetSize();
1266 ImpAutoFitText( rOutliner
,
1267 Size(aShapeSize
.Width()-GetTextLeftDistance()-GetTextRightDistance(),
1268 aShapeSize
.Height()-GetTextUpperDistance()-GetTextLowerDistance()),
1269 IsVerticalWriting() );
1272 void SdrTextObj::ImpAutoFitText(SdrOutliner
& rOutliner
, const Size
& rTextSize
,
1273 bool bIsVerticalWriting
) const
1275 autoFitTextForCompatibility(rOutliner
, rTextSize
, bIsVerticalWriting
);
1278 void SdrTextObj::autoFitTextForCompatibility(SdrOutliner
& rOutliner
, const Size
& rTextBoxSize
, bool bIsVerticalWriting
) const
1280 rOutliner
.setRoundFontSizeToPt(true);
1282 const SdrTextFitToSizeTypeItem
& rItem
= GetObjectItem(SDRATTR_TEXT_FITTOSIZE
);
1283 double fMaxScale
= rItem
.GetMaxScale();
1284 if (fMaxScale
> 0.0)
1286 rOutliner
.setGlobalScale(fMaxScale
, fMaxScale
, 100.0, 100.0);
1293 Size aCurrentTextBoxSize
= rOutliner
.CalcTextSizeNTP();
1294 if (aCurrentTextBoxSize
.Height() == 0)
1297 tools::Long nExtendTextBoxBy
= -50;
1298 aCurrentTextBoxSize
.extendBy(0, nExtendTextBoxBy
);
1299 double fCurrentFitFactor
= 1.0;
1301 if (bIsVerticalWriting
)
1302 fCurrentFitFactor
= double(rTextBoxSize
.Width()) / aCurrentTextBoxSize
.Width();
1304 fCurrentFitFactor
= double(rTextBoxSize
.Height()) / aCurrentTextBoxSize
.Height();
1306 double fInitialFontScaleY
= 0.0;
1307 double fInitialSpacing
= 0.0;
1308 rOutliner
.getGlobalScale(o3tl::temporary(double()), fInitialFontScaleY
, o3tl::temporary(double()), fInitialSpacing
);
1310 if (fCurrentFitFactor
>= 1.0 && fInitialFontScaleY
>= 100.0 && fInitialSpacing
>= 100.0)
1313 sal_Int32 nFontHeight
= GetObjectItemSet().Get(EE_CHAR_FONTHEIGHT
).GetHeight();
1315 double fFontHeightPt
= o3tl::convert(double(nFontHeight
), o3tl::Length::mm100
, o3tl::Length::pt
);
1317 double fMaxY
= fMaxScale
;
1319 double fBestFontScale
= 0.0;
1320 double fBestSpacing
= 100.0;
1321 double fBestFitFactor
= fCurrentFitFactor
;
1323 if (fCurrentFitFactor
>= 1.0)
1325 fMinY
= fInitialFontScaleY
;
1326 fBestFontScale
= fInitialFontScaleY
;
1327 fBestSpacing
= fInitialSpacing
;
1328 fBestFitFactor
= fCurrentFitFactor
;
1332 fMaxY
= std::min(fInitialFontScaleY
, fMaxScale
);
1335 double fInTheMidle
= 0.5;
1338 double fFitFactorTarget
= 1.00;
1340 while (iteration
< 10)
1343 double fScaleY
= fMinY
+ (fMaxY
- fMinY
) * fInTheMidle
;
1345 double fScaledFontHeight
= fFontHeightPt
* (fScaleY
/ 100.0);
1346 double fRoundedScaledFontHeight
= std::floor(fScaledFontHeight
* 10.0) / 10.0;
1347 double fCurrentFontScale
= (fRoundedScaledFontHeight
/ fFontHeightPt
) * 100.0;
1349 fCurrentFitFactor
= 0.0; // reset fit factor;
1351 for (double fCurrentSpacing
: {100.0, 90.0, 80.0})
1353 if (fCurrentFitFactor
>= fFitFactorTarget
)
1356 rOutliner
.setGlobalScale(fCurrentFontScale
, fCurrentFontScale
, 100.0, fCurrentSpacing
);
1358 aCurrentTextBoxSize
= rOutliner
.CalcTextSizeNTP();
1359 aCurrentTextBoxSize
.extendBy(0, nExtendTextBoxBy
);
1360 if (bIsVerticalWriting
)
1361 fCurrentFitFactor
= double(rTextBoxSize
.Width()) / aCurrentTextBoxSize
.Width();
1363 fCurrentFitFactor
= double(rTextBoxSize
.Height()) / aCurrentTextBoxSize
.Height();
1366 if (fCurrentSpacing
== 100.0)
1368 if (fCurrentFitFactor
> fFitFactorTarget
)
1369 fMinY
= fCurrentFontScale
;
1371 fMaxY
= fCurrentFontScale
;
1374 if ((fBestFitFactor
< fFitFactorTarget
&& fCurrentFitFactor
> fBestFitFactor
)
1375 || (fCurrentFitFactor
>= fFitFactorTarget
&& fCurrentFitFactor
< fBestFitFactor
))
1377 fBestFontScale
= fCurrentFontScale
;
1378 fBestSpacing
= fCurrentSpacing
;
1379 fBestFitFactor
= fCurrentFitFactor
;
1383 rOutliner
.setGlobalScale(fBestFontScale
, fBestFontScale
, 100.0, fBestSpacing
);
1386 void SdrTextObj::SetupOutlinerFormatting( SdrOutliner
& rOutl
, tools::Rectangle
& rPaintRect
) const
1388 ImpInitDrawOutliner( rOutl
);
1389 UpdateOutlinerFormatting( rOutl
, rPaintRect
);
1392 void SdrTextObj::UpdateOutlinerFormatting( SdrOutliner
& rOutl
, tools::Rectangle
& rPaintRect
) const
1394 tools::Rectangle aTextRect
;
1395 tools::Rectangle aAnchorRect
;
1396 Fraction
aFitXCorrection(1,1);
1398 const bool bContourFrame(IsContourTextFrame());
1399 const MapMode
aMapMode(getSdrModelFromSdrObject().GetScaleUnit());
1401 rOutl
.SetRefMapMode(aMapMode
);
1402 ImpSetupDrawOutlinerForPaint(
1412 OutlinerParaObject
* SdrTextObj::GetOutlinerParaObject() const
1414 SdrText
* pText
= getActiveText();
1416 return pText
->GetOutlinerParaObject();
1421 void SdrTextObj::NbcSetOutlinerParaObject(std::optional
<OutlinerParaObject
> pTextObject
)
1423 NbcSetOutlinerParaObjectForText( std::move(pTextObject
), getActiveText() );
1428 bool IsAutoGrow(const SdrTextObj
& rObj
)
1430 bool bAutoGrow
= rObj
.IsAutoGrowHeight() || rObj
.IsAutoGrowWidth();
1431 return bAutoGrow
&& !utl::ConfigManager::IsFuzzing();
1435 void SdrTextObj::NbcSetOutlinerParaObjectForText( std::optional
<OutlinerParaObject
> pTextObject
, SdrText
* pText
)
1438 pText
->SetOutlinerParaObject( std::move(pTextObject
) );
1440 if (pText
&& pText
->GetOutlinerParaObject())
1442 SvxWritingModeItem
aWritingMode(pText
->GetOutlinerParaObject()->IsEffectivelyVertical() && pText
->GetOutlinerParaObject()->IsTopToBottom()
1443 ? css::text::WritingMode_TB_RL
1444 : css::text::WritingMode_LR_TB
,
1445 SDRATTR_TEXTDIRECTION
);
1446 GetProperties().SetObjectItemDirect(aWritingMode
);
1450 if (IsTextFrame() && IsAutoGrow(*this))
1451 { // adapt text frame!
1452 NbcAdjustTextFrameWidthAndHeight();
1456 // the SnapRect keeps its size
1457 SetBoundAndSnapRectsDirty(true);
1460 // always invalidate BoundRect on change
1461 SetBoundRectDirty();
1464 ImpSetTextStyleSheetListeners();
1467 void SdrTextObj::NbcReformatText()
1469 SdrText
* pText
= getActiveText();
1470 if( !(pText
&& pText
->GetOutlinerParaObject()) )
1473 pText
->ReformatText();
1476 NbcAdjustTextFrameWidthAndHeight();
1480 // the SnapRect keeps its size
1481 SetBoundRectDirty();
1482 SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
1487 // Necessary here since we have no compare operator at the outliner
1488 // para object which may detect changes regarding the combination
1489 // of outliner para data and configuration (e.g., change of
1490 // formatting of text numerals)
1491 GetViewContact().flushViewObjectContacts(false);
1494 std::unique_ptr
<SdrObjGeoData
> SdrTextObj::NewGeoData() const
1496 return std::make_unique
<SdrTextObjGeoData
>();
1499 void SdrTextObj::SaveGeoData(SdrObjGeoData
& rGeo
) const
1501 SdrAttrObj::SaveGeoData(rGeo
);
1502 SdrTextObjGeoData
& rTGeo
=static_cast<SdrTextObjGeoData
&>(rGeo
);
1503 rTGeo
.maRect
= getRectangle();
1504 rTGeo
.maGeo
= maGeo
;
1507 void SdrTextObj::RestoreGeoData(const SdrObjGeoData
& rGeo
)
1508 { // RectsDirty is called by SdrObject
1509 SdrAttrObj::RestoreGeoData(rGeo
);
1510 const SdrTextObjGeoData
& rTGeo
=static_cast<const SdrTextObjGeoData
&>(rGeo
);
1511 NbcSetLogicRect(rTGeo
.maRect
);
1512 maGeo
= rTGeo
.maGeo
;
1516 drawing::TextFitToSizeType
SdrTextObj::GetFitToSize() const
1518 drawing::TextFitToSizeType eType
= drawing::TextFitToSizeType_NONE
;
1520 if(!IsAutoGrowWidth())
1521 eType
= GetObjectItem(SDRATTR_TEXT_FITTOSIZE
).GetValue();
1526 const tools::Rectangle
& SdrTextObj::GetGeoRect() const
1528 return getRectangle();
1531 void SdrTextObj::ForceOutlinerParaObject()
1533 SdrText
* pText
= getActiveText();
1534 if( pText
&& (pText
->GetOutlinerParaObject() == nullptr) )
1536 OutlinerMode nOutlMode
= OutlinerMode::TextObject
;
1537 if( IsTextFrame() && meTextKind
== SdrObjKind::OutlineText
)
1538 nOutlMode
= OutlinerMode::OutlineObject
;
1540 pText
->ForceOutlinerParaObject( nOutlMode
);
1544 TextChain
*SdrTextObj::GetTextChain() const
1546 //if (!IsChainable())
1549 return getSdrModelFromSdrObject().GetTextChain();
1552 bool SdrTextObj::IsVerticalWriting() const
1554 if(mpEditingOutliner
)
1556 return mpEditingOutliner
->IsVertical();
1559 OutlinerParaObject
* pOutlinerParaObject
= GetOutlinerParaObject();
1560 if(pOutlinerParaObject
)
1562 return pOutlinerParaObject
->IsEffectivelyVertical();
1568 void SdrTextObj::SetVerticalWriting(bool bVertical
)
1570 OutlinerParaObject
* pOutlinerParaObject
= GetOutlinerParaObject();
1572 if( !pOutlinerParaObject
&& bVertical
)
1574 // we only need to force an outliner para object if the default of
1575 // horizontal text is changed
1576 ForceOutlinerParaObject();
1577 pOutlinerParaObject
= GetOutlinerParaObject();
1580 if (!pOutlinerParaObject
||
1581 (pOutlinerParaObject
->IsEffectivelyVertical() == bVertical
))
1584 // get item settings
1585 const SfxItemSet
& rSet
= GetObjectItemSet();
1586 bool bAutoGrowWidth
= rSet
.Get(SDRATTR_TEXT_AUTOGROWWIDTH
).GetValue();
1587 bool bAutoGrowHeight
= rSet
.Get(SDRATTR_TEXT_AUTOGROWHEIGHT
).GetValue();
1589 // Also exchange hor/ver adjust items
1590 SdrTextHorzAdjust eHorz
= rSet
.Get(SDRATTR_TEXT_HORZADJUST
).GetValue();
1591 SdrTextVertAdjust eVert
= rSet
.Get(SDRATTR_TEXT_VERTADJUST
).GetValue();
1593 // rescue object size
1594 tools::Rectangle aObjectRect
= GetSnapRect();
1596 // prepare ItemSet to set exchanged width and height items
1597 SfxItemSetFixed
<SDRATTR_TEXT_AUTOGROWHEIGHT
, SDRATTR_TEXT_AUTOGROWHEIGHT
,
1598 // Expanded item ranges to also support hor and ver adjust.
1599 SDRATTR_TEXT_VERTADJUST
, SDRATTR_TEXT_VERTADJUST
,
1600 SDRATTR_TEXT_AUTOGROWWIDTH
, SDRATTR_TEXT_HORZADJUST
> aNewSet(*rSet
.GetPool());
1603 aNewSet
.Put(makeSdrTextAutoGrowWidthItem(bAutoGrowHeight
));
1604 aNewSet
.Put(makeSdrTextAutoGrowHeightItem(bAutoGrowWidth
));
1606 // Exchange horz and vert adjusts
1609 case SDRTEXTVERTADJUST_TOP
: aNewSet
.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT
)); break;
1610 case SDRTEXTVERTADJUST_CENTER
: aNewSet
.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_CENTER
)); break;
1611 case SDRTEXTVERTADJUST_BOTTOM
: aNewSet
.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT
)); break;
1612 case SDRTEXTVERTADJUST_BLOCK
: aNewSet
.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_BLOCK
)); break;
1616 case SDRTEXTHORZADJUST_LEFT
: aNewSet
.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BOTTOM
)); break;
1617 case SDRTEXTHORZADJUST_CENTER
: aNewSet
.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER
)); break;
1618 case SDRTEXTHORZADJUST_RIGHT
: aNewSet
.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP
)); break;
1619 case SDRTEXTHORZADJUST_BLOCK
: aNewSet
.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BLOCK
)); break;
1622 SetObjectItemSet(aNewSet
);
1624 pOutlinerParaObject
= GetOutlinerParaObject();
1625 if (pOutlinerParaObject
)
1627 // set ParaObject orientation accordingly
1628 pOutlinerParaObject
->SetVertical(bVertical
);
1631 // restore object size
1632 SetSnapRect(aObjectRect
);
1635 bool SdrTextObj::IsTopToBottom() const
1637 if (mpEditingOutliner
)
1638 return mpEditingOutliner
->IsTopToBottom();
1640 if (OutlinerParaObject
* pOutlinerParaObject
= GetOutlinerParaObject())
1641 return pOutlinerParaObject
->IsTopToBottom();
1646 // transformation interface for StarOfficeAPI. This implements support for
1647 // homogeneous 3x3 matrices containing the transformation of the SdrObject. At the
1648 // moment it contains a shearX, rotation and translation, but for setting all linear
1649 // transforms like Scale, ShearX, ShearY, Rotate and Translate are supported.
1652 // gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon
1653 // with the base geometry and returns TRUE. Otherwise it returns FALSE.
1654 bool SdrTextObj::TRGetBaseGeometry(basegfx::B2DHomMatrix
& rMatrix
, basegfx::B2DPolyPolygon
& /*rPolyPolygon*/) const
1656 // get turn and shear
1657 double fRotate
= toRadians(maGeo
.nRotationAngle
);
1658 double fShearX
= toRadians(maGeo
.nShearAngle
);
1660 // get aRect, this is the unrotated snaprect
1661 tools::Rectangle
aRectangle(getRectangle());
1663 // fill other values
1664 basegfx::B2DTuple
aScale(aRectangle
.GetWidth(), aRectangle
.GetHeight());
1665 basegfx::B2DTuple
aTranslate(aRectangle
.Left(), aRectangle
.Top());
1667 // position maybe relative to anchorpos, convert
1668 if( getSdrModelFromSdrObject().IsWriter() )
1670 if(GetAnchorPos().X() || GetAnchorPos().Y())
1672 aTranslate
-= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
1677 rMatrix
= basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
1679 basegfx::fTools::equalZero(fShearX
) ? 0.0 : tan(fShearX
),
1680 basegfx::fTools::equalZero(fRotate
) ? 0.0 : -fRotate
,
1686 // sets the base geometry of the object using infos contained in the homogeneous 3x3 matrix.
1687 // If it's an SdrPathObj it will use the provided geometry information. The Polygon has
1688 // to use (0,0) as upper left and will be scaled to the given size in the matrix.
1689 void SdrTextObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix
& rMatrix
, const basegfx::B2DPolyPolygon
& /*rPolyPolygon*/)
1692 basegfx::B2DTuple aScale
;
1693 basegfx::B2DTuple aTranslate
;
1694 double fRotate(0.0);
1695 double fShearX(0.0);
1696 rMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
1699 bool bFlipX
= aScale
.getX() < 0.0,
1700 bFlipY
= aScale
.getY() < 0.0;
1703 aScale
.setX(fabs(aScale
.getX()));
1707 aScale
.setY(fabs(aScale
.getY()));
1710 // reset object shear and rotations
1711 maGeo
.nRotationAngle
= 0_deg100
;
1712 maGeo
.RecalcSinCos();
1713 maGeo
.nShearAngle
= 0_deg100
;
1716 // if anchor is used, make position relative to it
1717 if( getSdrModelFromSdrObject().IsWriter() )
1719 if(GetAnchorPos().X() || GetAnchorPos().Y())
1721 aTranslate
+= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
1725 // build and set BaseRect (use scale)
1726 Size
aSize(FRound(aScale
.getX()), FRound(aScale
.getY()));
1727 tools::Rectangle
aBaseRect(Point(), aSize
);
1728 SetSnapRect(aBaseRect
);
1733 Mirror(Point(), Point(0, 1));
1737 Mirror(Point(), Point(1, 0));
1741 if(!basegfx::fTools::equalZero(fShearX
))
1744 aGeoStat
.nShearAngle
= Degree100(FRound(basegfx::rad2deg
<100>(atan(fShearX
))));
1745 aGeoStat
.RecalcTan();
1746 Shear(Point(), aGeoStat
.nShearAngle
, aGeoStat
.mfTanShearAngle
, false);
1750 if(!basegfx::fTools::equalZero(fRotate
))
1755 // fRotate is matematically correct, but aGeoStat.nRotationAngle is
1756 // mirrored -> mirror value here
1757 aGeoStat
.nRotationAngle
= NormAngle36000(Degree100(FRound(-basegfx::rad2deg
<100>(fRotate
))));
1758 aGeoStat
.RecalcSinCos();
1759 Rotate(Point(), aGeoStat
.nRotationAngle
, aGeoStat
.mfSinRotationAngle
, aGeoStat
.mfCosRotationAngle
);
1763 if(!aTranslate
.equalZero())
1765 Move(Size(FRound(aTranslate
.getX()), FRound(aTranslate
.getY())));
1769 bool SdrTextObj::IsReallyEdited() const
1771 return mpEditingOutliner
&& mpEditingOutliner
->IsModified();
1774 // moved inlines here form hxx
1776 tools::Long
SdrTextObj::GetEckenradius() const
1778 return GetObjectItemSet().Get(SDRATTR_CORNER_RADIUS
).GetValue();
1781 tools::Long
SdrTextObj::GetMinTextFrameHeight() const
1783 return GetObjectItemSet().Get(SDRATTR_TEXT_MINFRAMEHEIGHT
).GetValue();
1786 tools::Long
SdrTextObj::GetMaxTextFrameHeight() const
1788 return GetObjectItemSet().Get(SDRATTR_TEXT_MAXFRAMEHEIGHT
).GetValue();
1791 tools::Long
SdrTextObj::GetMinTextFrameWidth() const
1793 return GetObjectItemSet().Get(SDRATTR_TEXT_MINFRAMEWIDTH
).GetValue();
1796 tools::Long
SdrTextObj::GetMaxTextFrameWidth() const
1798 return GetObjectItemSet().Get(SDRATTR_TEXT_MAXFRAMEWIDTH
).GetValue();
1801 bool SdrTextObj::IsFontwork() const
1803 return !mbTextFrame
// Default is FALSE
1804 && GetObjectItemSet().Get(XATTR_FORMTXTSTYLE
).GetValue() != XFormTextStyle::NONE
;
1807 bool SdrTextObj::IsHideContour() const
1809 return !mbTextFrame
// Default is: no, don't HideContour; HideContour not together with TextFrames
1810 && GetObjectItemSet().Get(XATTR_FORMTXTHIDEFORM
).GetValue();
1813 bool SdrTextObj::IsContourTextFrame() const
1815 return !mbTextFrame
// ContourFrame not together with normal TextFrames
1816 && GetObjectItemSet().Get(SDRATTR_TEXT_CONTOURFRAME
).GetValue();
1819 tools::Long
SdrTextObj::GetTextLeftDistance() const
1821 return GetObjectItemSet().Get(SDRATTR_TEXT_LEFTDIST
).GetValue();
1824 tools::Long
SdrTextObj::GetTextRightDistance() const
1826 return GetObjectItemSet().Get(SDRATTR_TEXT_RIGHTDIST
).GetValue();
1829 tools::Long
SdrTextObj::GetTextUpperDistance() const
1831 return GetObjectItemSet().Get(SDRATTR_TEXT_UPPERDIST
).GetValue();
1834 tools::Long
SdrTextObj::GetTextLowerDistance() const
1836 return GetObjectItemSet().Get(SDRATTR_TEXT_LOWERDIST
).GetValue();
1839 SdrTextAniKind
SdrTextObj::GetTextAniKind() const
1841 return GetObjectItemSet().Get(SDRATTR_TEXT_ANIKIND
).GetValue();
1844 SdrTextAniDirection
SdrTextObj::GetTextAniDirection() const
1846 return GetObjectItemSet().Get(SDRATTR_TEXT_ANIDIRECTION
).GetValue();
1849 bool SdrTextObj::HasTextColumnsNumber() const
1851 return GetObjectItemSet().HasItem(SDRATTR_TEXTCOLUMNS_NUMBER
);
1854 sal_Int16
SdrTextObj::GetTextColumnsNumber() const
1856 return GetObjectItemSet().Get(SDRATTR_TEXTCOLUMNS_NUMBER
).GetValue();
1859 void SdrTextObj::SetTextColumnsNumber(sal_Int16 nColumns
)
1861 SetObjectItem(SfxInt16Item(SDRATTR_TEXTCOLUMNS_NUMBER
, nColumns
));
1864 bool SdrTextObj::HasTextColumnsSpacing() const
1866 return GetObjectItemSet().HasItem(SDRATTR_TEXTCOLUMNS_SPACING
);
1869 sal_Int32
SdrTextObj::GetTextColumnsSpacing() const
1871 return GetObjectItemSet().Get(SDRATTR_TEXTCOLUMNS_SPACING
).GetValue();
1874 void SdrTextObj::SetTextColumnsSpacing(sal_Int32 nSpacing
)
1876 SetObjectItem(SdrMetricItem(SDRATTR_TEXTCOLUMNS_SPACING
, nSpacing
));
1879 // Get necessary data for text scroll animation. ATM base it on a Text-Metafile and a
1880 // painting rectangle. Rotation is excluded from the returned values.
1881 GDIMetaFile
* SdrTextObj::GetTextScrollMetaFileAndRectangle(
1882 tools::Rectangle
& rScrollRectangle
, tools::Rectangle
& rPaintRectangle
)
1884 GDIMetaFile
* pRetval
= nullptr;
1885 SdrOutliner
& rOutliner
= ImpGetDrawOutliner();
1886 tools::Rectangle aTextRect
;
1887 tools::Rectangle aAnchorRect
;
1888 tools::Rectangle aPaintRect
;
1889 Fraction
aFitXCorrection(1,1);
1890 bool bContourFrame(IsContourTextFrame());
1892 // get outliner set up. To avoid getting a somehow rotated MetaFile,
1893 // temporarily disable object rotation.
1894 Degree100
nAngle(maGeo
.nRotationAngle
);
1895 maGeo
.nRotationAngle
= 0_deg100
;
1896 ImpSetupDrawOutlinerForPaint( bContourFrame
, rOutliner
, aTextRect
, aAnchorRect
, aPaintRect
, aFitXCorrection
);
1897 maGeo
.nRotationAngle
= nAngle
;
1899 tools::Rectangle
aScrollFrameRect(aPaintRect
);
1900 const SfxItemSet
& rSet
= GetObjectItemSet();
1901 SdrTextAniDirection eDirection
= rSet
.Get(SDRATTR_TEXT_ANIDIRECTION
).GetValue();
1903 if(SdrTextAniDirection::Left
== eDirection
|| SdrTextAniDirection::Right
== eDirection
)
1905 aScrollFrameRect
.SetLeft( aAnchorRect
.Left() );
1906 aScrollFrameRect
.SetRight( aAnchorRect
.Right() );
1909 if(SdrTextAniDirection::Up
== eDirection
|| SdrTextAniDirection::Down
== eDirection
)
1911 aScrollFrameRect
.SetTop( aAnchorRect
.Top() );
1912 aScrollFrameRect
.SetBottom( aAnchorRect
.Bottom() );
1915 // create the MetaFile
1916 pRetval
= new GDIMetaFile
;
1917 ScopedVclPtrInstance
< VirtualDevice
> pBlackHole
;
1918 pBlackHole
->EnableOutput(false);
1919 pRetval
->Record(pBlackHole
);
1920 Point aPaintPos
= aPaintRect
.TopLeft();
1922 rOutliner
.Draw(*pBlackHole
, aPaintPos
);
1925 pRetval
->WindStart();
1927 // return PaintRectanglePixel and pRetval;
1928 rScrollRectangle
= aScrollFrameRect
;
1929 rPaintRectangle
= aPaintRect
;
1934 // Access to TextAnimationAllowed flag
1935 bool SdrTextObj::IsAutoFit() const
1937 return GetFitToSize() == drawing::TextFitToSizeType_AUTOFIT
;
1940 bool SdrTextObj::IsFitToSize() const
1942 const drawing::TextFitToSizeType eFit
= GetFitToSize();
1943 return (eFit
== drawing::TextFitToSizeType_PROPORTIONAL
1944 || eFit
== drawing::TextFitToSizeType_ALLLINES
);
1947 void SdrTextObj::SetTextAnimationAllowed(bool bNew
)
1949 if(mbTextAnimationAllowed
!= bNew
)
1951 mbTextAnimationAllowed
= bNew
;
1956 /** called from the SdrObjEditView during text edit when the status of the edit outliner changes */
1957 void SdrTextObj::onEditOutlinerStatusEvent( EditStatus
* pEditStatus
)
1959 const EditStatusFlags nStat
= pEditStatus
->GetStatusWord();
1960 const bool bGrowX
= bool(nStat
& EditStatusFlags::TEXTWIDTHCHANGED
);
1961 const bool bGrowY
= bool(nStat
& EditStatusFlags::TextHeightChanged
);
1962 if(!(mbTextFrame
&& (bGrowX
|| bGrowY
)))
1965 if ((bGrowX
&& IsAutoGrowWidth()) || (bGrowY
&& IsAutoGrowHeight()))
1967 AdjustTextFrameWidthAndHeight();
1969 else if ( (IsAutoFit() || IsFitToSize()) && !mbInDownScale
)
1971 assert(mpEditingOutliner
);
1972 mbInDownScale
= true;
1974 // sucks that we cannot disable paints via
1975 // mpEditingOutliner->SetUpdateMode(FALSE) - but EditEngine skips
1976 // formatting as well, then.
1977 ImpAutoFitText(*mpEditingOutliner
);
1978 mbInDownScale
= false;
1982 /* Begin chaining code */
1984 // XXX: Make it a method somewhere?
1985 static SdrObject
*ImpGetObjByName(SdrObjList
const *pObjList
, std::u16string_view aObjName
)
1987 // scan the whole list
1988 size_t nObjCount
= pObjList
->GetObjCount();
1989 for (size_t i
= 0; i
< nObjCount
; i
++) {
1990 SdrObject
*pCurObj
= pObjList
->GetObj(i
);
1992 if (pCurObj
->GetName() == aObjName
) {
2000 // XXX: Make it a (private) method of SdrTextObj
2001 static void ImpUpdateChainLinks(SdrTextObj
*pTextObj
, std::u16string_view aNextLinkName
)
2003 // XXX: Current implementation constraints text boxes to be on the same page
2006 if (aNextLinkName
.empty()) {
2007 pTextObj
->SetNextLinkInChain(nullptr);
2011 SdrPage
*pPage(pTextObj
->getSdrPageFromSdrObject());
2013 SdrTextObj
*pNextTextObj
= DynCastSdrTextObj
2014 (ImpGetObjByName(pPage
, aNextLinkName
));
2015 if (!pNextTextObj
) {
2016 SAL_INFO("svx.chaining", "[CHAINING] Can't find object as next link.");
2020 pTextObj
->SetNextLinkInChain(pNextTextObj
);
2023 bool SdrTextObj::IsChainable() const
2026 const SfxItemSet
& rSet
= GetObjectItemSet();
2027 OUString aNextLinkName
= rSet
.Get(SDRATTR_TEXT_CHAINNEXTNAME
).GetValue();
2029 // Update links if any inconsistency is found
2030 bool bNextLinkUnsetYet
= !aNextLinkName
.isEmpty() && !mpNextInChain
;
2031 bool bInconsistentNextLink
= mpNextInChain
&& mpNextInChain
->GetName() != aNextLinkName
;
2032 // if the link is not set despite there should be one OR if it has changed
2033 if (bNextLinkUnsetYet
|| bInconsistentNextLink
) {
2034 ImpUpdateChainLinks(const_cast<SdrTextObj
*>(this), aNextLinkName
);
2037 return !aNextLinkName
.isEmpty(); // XXX: Should we also check for GetNilChainingEvent? (see old code below)
2040 // Check that no overflow is going on
2041 if (!GetTextChain() || GetTextChain()->GetNilChainingEvent(this))
2046 void SdrTextObj::onChainingEvent()
2048 if (!mpEditingOutliner
)
2051 // Outliner for text transfer
2052 SdrOutliner
&aDrawOutliner
= ImpGetDrawOutliner();
2054 EditingTextChainFlow
aTxtChainFlow(this);
2055 aTxtChainFlow
.CheckForFlowEvents(mpEditingOutliner
);
2057 if (aTxtChainFlow
.IsOverflow()) {
2058 SAL_INFO("svx.chaining", "[CHAINING] Overflow going on");
2059 // One outliner is for non-overflowing text, the other for overflowing text
2060 // We remove text directly from the editing outliner
2061 aTxtChainFlow
.ExecuteOverflow(mpEditingOutliner
, &aDrawOutliner
);
2062 } else if (aTxtChainFlow
.IsUnderflow()) {
2063 SAL_INFO("svx.chaining", "[CHAINING] Underflow going on");
2064 // underflow-induced overflow
2065 aTxtChainFlow
.ExecuteUnderflow(&aDrawOutliner
);
2066 bool bIsOverflowFromUnderflow
= aTxtChainFlow
.IsOverflow();
2068 if (bIsOverflowFromUnderflow
) {
2069 SAL_INFO("svx.chaining", "[CHAINING] Overflow going on (underflow induced)");
2070 // prevents infinite loops when setting text for editing outliner
2071 aTxtChainFlow
.ExecuteOverflow(&aDrawOutliner
, &aDrawOutliner
);
2076 SdrTextObj
* SdrTextObj::GetNextLinkInChain() const
2080 return GetTextChain()->GetNextLink(this);
2085 return mpNextInChain
;
2088 void SdrTextObj::SetNextLinkInChain(SdrTextObj
*pNextObj
)
2090 // Basically a doubly linked list implementation
2092 SdrTextObj
*pOldNextObj
= mpNextInChain
;
2094 // Replace next link
2095 mpNextInChain
= pNextObj
;
2096 // Deal with old next link's prev link
2098 pOldNextObj
->mpPrevInChain
= nullptr;
2101 // Deal with new next link's prev link
2102 if (mpNextInChain
) {
2103 // If there is a prev already at all and this is not already the current object
2104 if (mpNextInChain
->mpPrevInChain
&&
2105 mpNextInChain
->mpPrevInChain
!= this)
2106 mpNextInChain
->mpPrevInChain
->mpNextInChain
= nullptr;
2107 mpNextInChain
->mpPrevInChain
= this;
2110 // TODO: Introduce check for circular chains
2114 SdrTextObj
* SdrTextObj::GetPrevLinkInChain() const
2118 return GetTextChain()->GetPrevLink(this);
2123 return mpPrevInChain
;
2126 bool SdrTextObj::GetPreventChainable() const
2128 // Prevent chaining it 1) during dragging && 2) when we are editing next link
2129 return mbIsUnchainableClone
|| (GetNextLinkInChain() && GetNextLinkInChain()->IsInEditMode());
2132 rtl::Reference
<SdrObject
> SdrTextObj::getFullDragClone() const
2134 rtl::Reference
<SdrObject
> pClone
= SdrAttrObj::getFullDragClone();
2135 SdrTextObj
*pTextObjClone
= DynCastSdrTextObj(pClone
.get());
2136 if (pTextObjClone
!= nullptr) {
2137 // Avoid transferring of text for chainable object during dragging
2138 pTextObjClone
->mbIsUnchainableClone
= true;
2144 /* End chaining code */
2146 /** returns the currently active text. */
2147 SdrText
* SdrTextObj::getActiveText() const
2150 return getText( 0 );
2152 return mxText
.get();
2155 /** returns the nth available text. */
2156 SdrText
* SdrTextObj::getText( sal_Int32 nIndex
) const
2161 const_cast< SdrTextObj
* >(this)->mxText
= new SdrText( *const_cast< SdrTextObj
* >(this) );
2162 return mxText
.get();
2170 /** returns the number of texts available for this object. */
2171 sal_Int32
SdrTextObj::getTextCount() const
2176 /** changes the current active text */
2177 void SdrTextObj::setActiveText( sal_Int32
/*nIndex*/ )
2181 /** returns the index of the text that contains the given point or -1 */
2182 sal_Int32
SdrTextObj::CheckTextHit(const Point
& /*rPnt*/) const
2187 void SdrTextObj::SetObjectItemNoBroadcast(const SfxPoolItem
& rItem
)
2189 static_cast< sdr::properties::TextProperties
& >(GetProperties()).SetObjectItemNoBroadcast(rItem
);
2193 // The concept of the text object:
2194 // ~~~~~~~~~~~~~~~~~~~~~~~~
2195 // Attributes/Variations:
2196 // - bool text frame / graphics object with caption
2197 // - bool FontWork (if it is not a text frame and not a ContourTextFrame)
2198 // - bool ContourTextFrame (if it is not a text frame and not Fontwork)
2199 // - long rotation angle (if it is not FontWork)
2200 // - long text frame margins (if it is not FontWork)
2201 // - bool FitToSize (if it is not FontWork)
2202 // - bool AutoGrowingWidth/Height (if it is not FitToSize and not FontWork)
2203 // - long Min/MaxFrameWidth/Height (if AutoGrowingWidth/Height)
2204 // - enum horizontal text anchoring left,center,right,justify/block,Stretch(ni)
2205 // - enum vertical text anchoring top, middle, bottom, block, stretch(ni)
2206 // - enum ticker text (if it is not FontWork)
2208 // Every derived object is either a text frame (mbTextFrame=true)
2209 // or a drawing object with a caption (mbTextFrame=false).
2211 // Default anchoring for text frames:
2212 // SDRTEXTHORZADJUST_BLOCK, SDRTEXTVERTADJUST_TOP
2213 // = static Pool defaults
2214 // Default anchoring for drawing objects with a caption:
2215 // SDRTEXTHORZADJUST_CENTER, SDRTEXTVERTADJUST_CENTER
2216 // via "hard" attribution of SdrAttrObj
2218 // Every object derived from SdrTextObj must return an "UnrotatedSnapRect"
2219 // (->TakeUnrotatedSnapRect()) (the reference point for the rotation is the top
2220 // left of the rectangle (maGeo.nRotationAngle)) which is the basis for anchoring
2221 // text. We then subtract the text frame margins from this rectangle, as a re-
2222 // sult we get the anchoring area (->TakeTextAnchorRect()). Within this area, we
2223 // calculate the anchoring point and the painting area, depending on the hori-
2224 // zontal and vertical adjustment of the text (SdrTextVertAdjust,
2225 // SdrTextHorzAdjust).
2226 // In the case of drawing objects with a caption the painting area might well
2227 // be larger than the anchoring area, for text frames on the other hand, it is
2228 // always of the same or a smaller size (except when there are negative text
2231 // FitToSize takes priority over text anchoring and AutoGrowHeight/Width. When
2232 // FitToSize is turned on, the painting area is always equal to the anchoring
2233 // area. Additionally, FitToSize doesn't allow automatic line breaks.
2235 // ContourTextFrame:
2236 // - long rotation angle
2237 // - long text frame margins (maybe later)
2238 // - bool FitToSize (maybe later)
2239 // - bool AutoGrowingWidth/Height (maybe much later)
2240 // - long Min/MaxFrameWidth/Height (maybe much later)
2241 // - enum horizontal text anchoring (maybe later, for now: left, centered)
2242 // - enum vertical text anchoring (maybe later, for now: top)
2243 // - enum ticker text (maybe later, maybe even with correct clipping)
2245 // When making changes, check these:
2250 // - Printing, Saving, Painting in neighboring View while editing
2251 // - ModelChanged (e. g. through a neighboring View or rulers) while editing
2252 // - FillColorChanged while editing
2253 // - and many more...
2256 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */