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 .
20 #include <svx/dialmgr.hxx>
21 #include <svx/strings.hrc>
23 #include <basegfx/matrix/b2dhommatrix.hxx>
24 #include <basegfx/matrix/b2dhommatrixtools.hxx>
25 #include <basegfx/point/b2dpoint.hxx>
26 #include <basegfx/polygon/b2dpolygon.hxx>
27 #include <basegfx/polygon/b2dpolypolygon.hxx>
28 #include <editeng/editdata.hxx>
29 #include <editeng/editobj.hxx>
30 #include <editeng/eeitem.hxx>
31 #include <editeng/flditem.hxx>
32 #include <editeng/measfld.hxx>
33 #include <editeng/outlobj.hxx>
35 #include <svl/style.hxx>
37 #include <sdr/contact/viewcontactofsdrmeasureobj.hxx>
38 #include <sdr/properties/measureproperties.hxx>
39 #include <svx/svddrag.hxx>
40 #include <svx/svdhdl.hxx>
41 #include <svx/svdmodel.hxx>
42 #include <svx/svdogrp.hxx>
43 #include <svx/svdomeas.hxx>
44 #include <svx/svdopath.hxx>
45 #include <svx/svdoutl.hxx>
46 #include <svx/svdpage.hxx>
47 #include <svx/svdtrans.hxx>
48 #include <svx/svdview.hxx>
49 #include <svx/sxmbritm.hxx>
50 #include <svx/sxmlhitm.hxx>
51 #include <sxmsitm.hxx>
52 #include <sxmtaitm.hxx>
53 #include <svx/sxmtfitm.hxx>
54 #include <svx/sxmtpitm.hxx>
55 #include <svx/sxmtritm.hxx>
56 #include <svx/sxmuitm.hxx>
57 #include <svx/xlnedcit.hxx>
58 #include <svx/xlnedit.hxx>
59 #include <svx/xlnedwit.hxx>
60 #include <svx/xlnstcit.hxx>
61 #include <svx/xlnstit.hxx>
62 #include <svx/xlnstwit.hxx>
63 #include <svx/xlnwtit.hxx>
64 #include <svx/xpoly.hxx>
65 #include <unotools/syslocale.hxx>
66 #include <unotools/localedatawrapper.hxx>
67 #include <vcl/ptrstyle.hxx>
70 SdrMeasureObjGeoData::SdrMeasureObjGeoData() {}
71 SdrMeasureObjGeoData::~SdrMeasureObjGeoData() {}
73 OUString
SdrMeasureObj::TakeRepresentation(SdrMeasureFieldKind eMeasureFieldKind
) const
76 Fraction
aMeasureScale(1, 1);
77 bool bTextRota90(false);
78 bool bShowUnit(false);
79 FieldUnit
eMeasureUnit(FieldUnit::NONE
);
80 FieldUnit
eModUIUnit(FieldUnit::NONE
);
82 const SfxItemSet
& rSet
= GetMergedItemSet();
83 bTextRota90
= rSet
.Get(SDRATTR_MEASURETEXTROTA90
).GetValue();
84 eMeasureUnit
= rSet
.Get(SDRATTR_MEASUREUNIT
).GetValue();
85 aMeasureScale
= rSet
.Get(SDRATTR_MEASURESCALE
).GetValue();
86 bShowUnit
= rSet
.Get(SDRATTR_MEASURESHOWUNIT
).GetValue();
87 sal_Int16 nNumDigits
= rSet
.Get(SDRATTR_MEASUREDECIMALPLACES
).GetValue();
89 switch(eMeasureFieldKind
)
91 case SdrMeasureFieldKind::Value
:
93 eModUIUnit
= getSdrModelFromSdrObject().GetUIUnit();
95 if(eMeasureUnit
== FieldUnit::NONE
)
96 eMeasureUnit
= eModUIUnit
;
98 sal_Int32
nLen(GetLen(aPt2
- aPt1
));
101 if(eMeasureUnit
!= eModUIUnit
)
103 // for the unit conversion
104 aFact
*= GetMapFactor(eModUIUnit
, eMeasureUnit
).X();
107 if(aMeasureScale
.GetNumerator() != aMeasureScale
.GetDenominator())
109 aFact
*= aMeasureScale
;
112 if(aFact
.GetNumerator() != aFact
.GetDenominator())
114 // scale via BigInt, to avoid overruns
115 nLen
= BigMulDiv(nLen
, aFact
.GetNumerator(), aFact
.GetDenominator());
124 aStr
= getSdrModelFromSdrObject().GetMetricString(nLen
, true, nNumDigits
);
127 SvtSysLocale aSysLocale
;
128 const LocaleDataWrapper
& rLocaleDataWrapper
= aSysLocale
.GetLocaleData();
129 sal_Unicode
cDec(rLocaleDataWrapper
.getNumDecimalSep()[0]);
130 sal_Unicode
cDecAlt(rLocaleDataWrapper
.getNumDecimalSepAlt().toChar());
132 if(aStr
.indexOf(cDec
) != -1 || (cDecAlt
&& aStr
.indexOf(cDecAlt
) != -1))
134 sal_Int32
nLen2(aStr
.getLength() - 1);
136 while(aStr
[nLen2
] == '0')
138 aStr
= aStr
.copy(0, nLen2
);
142 if(aStr
[nLen2
] == cDec
|| (cDecAlt
&& aStr
[nLen2
] == cDecAlt
))
144 aStr
= aStr
.copy(0, nLen2
);
154 case SdrMeasureFieldKind::Unit
:
158 eModUIUnit
= getSdrModelFromSdrObject().GetUIUnit();
160 if(eMeasureUnit
== FieldUnit::NONE
)
161 eMeasureUnit
= eModUIUnit
;
163 aStr
= SdrModel::GetUnitString(eMeasureUnit
);
168 case SdrMeasureFieldKind::Rotate90Blanks
:
182 // BaseProperties section
184 std::unique_ptr
<sdr::properties::BaseProperties
> SdrMeasureObj::CreateObjectSpecificProperties()
186 return std::make_unique
<sdr::properties::MeasureProperties
>(*this);
190 // DrawContact section
192 std::unique_ptr
<sdr::contact::ViewContact
> SdrMeasureObj::CreateObjectSpecificViewContact()
194 return std::make_unique
<sdr::contact::ViewContactOfSdrMeasureObj
>(*this);
198 SdrMeasureObj::SdrMeasureObj(SdrModel
& rSdrModel
)
199 : SdrTextObj(rSdrModel
),
203 mbSupportTextIndentingOnLineWidthChange
= false;
206 SdrMeasureObj::SdrMeasureObj(SdrModel
& rSdrModel
, SdrMeasureObj
const & rSource
)
207 : SdrTextObj(rSdrModel
, rSource
),
211 mbSupportTextIndentingOnLineWidthChange
= false;
215 bTextDirty
= rSource
.bTextDirty
;
218 SdrMeasureObj::SdrMeasureObj(
222 : SdrTextObj(rSdrModel
),
228 mbSupportTextIndentingOnLineWidthChange
= false;
231 SdrMeasureObj::~SdrMeasureObj()
235 void SdrMeasureObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
237 rInfo
.bMoveAllowed
=true;
238 rInfo
.bResizeFreeAllowed
=true;
239 rInfo
.bResizePropAllowed
=true;
240 rInfo
.bRotateFreeAllowed
=true;
241 rInfo
.bRotate90Allowed
=true;
242 rInfo
.bMirrorFreeAllowed
=true;
243 rInfo
.bMirror45Allowed
=true;
244 rInfo
.bMirror90Allowed
=true;
245 rInfo
.bTransparenceAllowed
= false;
246 rInfo
.bShearAllowed
=true;
247 rInfo
.bEdgeRadiusAllowed
=false;
248 rInfo
.bNoOrthoDesired
=true;
249 rInfo
.bNoContortion
=false;
250 rInfo
.bCanConvToPath
=false;
251 rInfo
.bCanConvToPoly
=true;
252 rInfo
.bCanConvToPathLineToArea
=false;
253 rInfo
.bCanConvToPolyLineToArea
=false;
254 rInfo
.bCanConvToContour
= LineGeometryUsageIsNecessary();
257 SdrObjKind
SdrMeasureObj::GetObjIdentifier() const
259 return SdrObjKind::Measure
;
262 struct ImpMeasureRec
: public SdrDragStatUserData
266 css::drawing::MeasureTextHorzPos eWantTextHPos
;
267 css::drawing::MeasureTextVertPos eWantTextVPos
;
268 tools::Long nLineDist
;
269 tools::Long nHelplineOverhang
;
270 tools::Long nHelplineDist
;
271 tools::Long nHelpline1Len
;
272 tools::Long nHelpline2Len
;
275 bool bTextUpsideDown
;
277 Degree100 nTextAutoAngleView
;
290 struct ImpMeasurePoly
292 ImpLineRec aMainline1
; // those with the 1st arrowhead
293 ImpLineRec aMainline2
; // those with the 2nd arrowhead
294 ImpLineRec aMainline3
; // those in between
295 ImpLineRec aHelpline1
;
296 ImpLineRec aHelpline2
;
298 tools::Long nLineLen
;
299 Degree100 nLineAngle
;
300 Degree100 nTextAngle
;
304 sal_uInt16 nMainlineCnt
;
305 css::drawing::MeasureTextHorzPos eUsedTextHPos
;
306 css::drawing::MeasureTextVertPos eUsedTextVPos
;
307 tools::Long nLineWdt2
; // half the line width
308 tools::Long nArrow1Len
; // length of 1st arrowhead; for Center, use only half
309 tools::Long nArrow2Len
; // length of 2nd arrowhead; for Center, use only half
310 tools::Long nArrow1Wdt
; // width of 1st arrow
311 tools::Long nArrow2Wdt
; // width of 2nd arrow
312 tools::Long nShortLineLen
; // line length, if PfeileAussen (arrowheads on the outside)
313 bool bAutoUpsideDown
; // UpsideDown via automation
317 void SdrMeasureObj::ImpTakeAttr(ImpMeasureRec
& rRec
) const
322 const SfxItemSet
& rSet
= GetObjectItemSet();
323 rRec
.eWantTextHPos
=rSet
.Get(SDRATTR_MEASURETEXTHPOS
).GetValue();
324 rRec
.eWantTextVPos
=rSet
.Get(SDRATTR_MEASURETEXTVPOS
).GetValue();
325 rRec
.nLineDist
=rSet
.Get(SDRATTR_MEASURELINEDIST
).GetValue();
326 rRec
.nHelplineOverhang
=rSet
.Get(SDRATTR_MEASUREHELPLINEOVERHANG
).GetValue();
327 rRec
.nHelplineDist
=rSet
.Get(SDRATTR_MEASUREHELPLINEDIST
).GetValue();
328 rRec
.nHelpline1Len
=rSet
.Get(SDRATTR_MEASUREHELPLINE1LEN
).GetValue();
329 rRec
.nHelpline2Len
=rSet
.Get(SDRATTR_MEASUREHELPLINE2LEN
).GetValue();
330 rRec
.bBelowRefEdge
=rSet
.Get(SDRATTR_MEASUREBELOWREFEDGE
).GetValue();
331 rRec
.bTextRota90
=rSet
.Get(SDRATTR_MEASURETEXTROTA90
).GetValue();
332 rRec
.bTextUpsideDown
=static_cast<const SdrMeasureTextUpsideDownItem
& >(rSet
.Get(SDRATTR_MEASURETEXTUPSIDEDOWN
)).GetValue();
333 rRec
.bTextAutoAngle
=rSet
.Get(SDRATTR_MEASURETEXTAUTOANGLE
).GetValue();
334 rRec
.nTextAutoAngleView
=static_cast<const SdrMeasureTextAutoAngleViewItem
&>(rSet
.Get(SDRATTR_MEASURETEXTAUTOANGLEVIEW
)).GetValue();
337 static tools::Long
impGetLineStartEndDistance(const basegfx::B2DPolyPolygon
& rPolyPolygon
, tools::Long nNewWidth
, bool bCenter
)
339 const basegfx::B2DRange
aPolygonRange(rPolyPolygon
.getB2DRange());
340 const double fOldWidth(std::max(aPolygonRange
.getWidth(), 1.0));
341 const double fScale(static_cast<double>(nNewWidth
) / fOldWidth
);
342 tools::Long
nHeight(basegfx::fround
<tools::Long
>(aPolygonRange
.getHeight() * fScale
));
352 void SdrMeasureObj::ImpCalcGeometrics(const ImpMeasureRec
& rRec
, ImpMeasurePoly
& rPol
) const
354 Point
aP1(rRec
.aPt1
);
355 Point
aP2(rRec
.aPt2
);
356 Point
aDelt(aP2
); aDelt
-=aP1
;
358 rPol
.aTextSize
=GetTextSize();
359 rPol
.nLineLen
=GetLen(aDelt
);
362 tools::Long nArrow1Len
=0; bool bArrow1Center
=false;
363 tools::Long nArrow2Len
=0; bool bArrow2Center
=false;
364 tools::Long nArrow1Wdt
=0;
365 tools::Long nArrow2Wdt
=0;
368 tools::Long nArrowNeed
=0;
369 tools::Long nShortLen
=0;
370 bool bPfeileAussen
= false;
372 const SfxItemSet
& rSet
= GetObjectItemSet();
373 sal_Int32 nLineWdt
= rSet
.Get(XATTR_LINEWIDTH
).GetValue(); // line width
374 rPol
.nLineWdt2
= (nLineWdt
+ 1) / 2;
376 nArrow1Wdt
= rSet
.Get(XATTR_LINESTARTWIDTH
).GetValue();
378 nArrow1Wdt
= -nLineWdt
* nArrow1Wdt
/ 100; // <0 = relative
380 nArrow2Wdt
= rSet
.Get(XATTR_LINEENDWIDTH
).GetValue();
382 nArrow2Wdt
= -nLineWdt
* nArrow2Wdt
/ 100; // <0 = relative
384 basegfx::B2DPolyPolygon
aPol1(rSet
.Get(XATTR_LINESTART
).GetLineStartValue());
385 basegfx::B2DPolyPolygon
aPol2(rSet
.Get(XATTR_LINEEND
).GetLineEndValue());
386 bArrow1Center
= rSet
.Get(XATTR_LINESTARTCENTER
).GetValue();
387 bArrow2Center
= rSet
.Get(XATTR_LINEENDCENTER
).GetValue();
388 nArrow1Len
= impGetLineStartEndDistance(aPol1
, nArrow1Wdt
, bArrow1Center
) - 1;
389 nArrow2Len
= impGetLineStartEndDistance(aPol2
, nArrow2Wdt
, bArrow2Center
) - 1;
391 // nArrowLen is already halved at bCenter.
392 // In the case of 2 arrowheads each 4mm long, we can't go below 10mm.
393 nArrowNeed
=nArrow1Len
+nArrow2Len
+(nArrow1Wdt
+nArrow2Wdt
)/2;
394 if (rPol
.nLineLen
<nArrowNeed
) bPfeileAussen
= true;
395 nShortLen
=(nArrow1Len
+nArrow1Wdt
+ nArrow2Len
+nArrow2Wdt
) /2;
397 rPol
.eUsedTextHPos
=rRec
.eWantTextHPos
;
398 rPol
.eUsedTextVPos
=rRec
.eWantTextVPos
;
399 if (rPol
.eUsedTextVPos
== css::drawing::MeasureTextVertPos_AUTO
)
400 rPol
.eUsedTextVPos
= css::drawing::MeasureTextVertPos_EAST
;
402 if (rPol
.eUsedTextVPos
== css::drawing::MeasureTextVertPos_CENTERED
)
404 OutlinerParaObject
* pOutlinerParaObject
= SdrTextObj::GetOutlinerParaObject();
405 if (pOutlinerParaObject
!=nullptr && pOutlinerParaObject
->GetTextObject().GetParagraphCount()==1)
407 bBrkLine
=true; // dashed line if there's only on paragraph.
410 rPol
.bBreakedLine
=bBrkLine
;
411 if (rPol
.eUsedTextHPos
==css::drawing::MeasureTextHorzPos_AUTO
) { // if text is too wide, push it outside
412 bool bOutside
= false;
413 tools::Long nNeedSiz
=!rRec
.bTextRota90
? rPol
.aTextSize
.Width() : rPol
.aTextSize
.Height();
414 if (nNeedSiz
>rPol
.nLineLen
) bOutside
= true; // text doesn't fit in between
416 if (nNeedSiz
+nArrowNeed
>rPol
.nLineLen
) bPfeileAussen
= true; // text fits in between, if arrowheads are on the outside
418 tools::Long nSmallNeed
=nArrow1Len
+nArrow2Len
+(nArrow1Wdt
+nArrow2Wdt
)/2/4;
419 if (nNeedSiz
+nSmallNeed
>rPol
.nLineLen
) bPfeileAussen
= true; // text fits in between, if arrowheads are on the outside
421 rPol
.eUsedTextHPos
=bOutside
? css::drawing::MeasureTextHorzPos_LEFTOUTSIDE
: css::drawing::MeasureTextHorzPos_INSIDE
;
423 if (rPol
.eUsedTextHPos
!= css::drawing::MeasureTextHorzPos_INSIDE
) bPfeileAussen
= true;
424 rPol
.nArrow1Wdt
=nArrow1Wdt
;
425 rPol
.nArrow2Wdt
=nArrow2Wdt
;
426 rPol
.nShortLineLen
=nShortLen
;
427 rPol
.nArrow1Len
=nArrow1Len
;
428 rPol
.nArrow2Len
=nArrow2Len
;
430 rPol
.nLineAngle
=GetAngle(aDelt
);
431 double a
= toRadians(rPol
.nLineAngle
);
432 double nLineSin
=sin(a
);
433 double nLineCos
=cos(a
);
434 rPol
.nLineSin
=nLineSin
;
435 rPol
.nLineCos
=nLineCos
;
437 rPol
.nTextAngle
=rPol
.nLineAngle
;
438 if (rRec
.bTextRota90
) rPol
.nTextAngle
+=9000_deg100
;
440 rPol
.bAutoUpsideDown
=false;
441 if (rRec
.bTextAutoAngle
) {
442 Degree100 nTmpAngle
=NormAngle36000(rPol
.nTextAngle
-rRec
.nTextAutoAngleView
);
443 if (nTmpAngle
>=18000_deg100
) {
444 rPol
.nTextAngle
+=18000_deg100
;
445 rPol
.bAutoUpsideDown
=true;
449 if (rRec
.bTextUpsideDown
) rPol
.nTextAngle
+=18000_deg100
;
450 rPol
.nTextAngle
=NormAngle36000(rPol
.nTextAngle
);
451 rPol
.nHlpAngle
=rPol
.nLineAngle
+9000_deg100
;
452 if (rRec
.bBelowRefEdge
) rPol
.nHlpAngle
+=18000_deg100
;
453 rPol
.nHlpAngle
=NormAngle36000(rPol
.nHlpAngle
);
454 double nHlpSin
=nLineCos
;
455 double nHlpCos
=-nLineSin
;
456 if (rRec
.bBelowRefEdge
) {
461 tools::Long nLineDist
=rRec
.nLineDist
;
462 tools::Long nOverhang
=rRec
.nHelplineOverhang
;
463 tools::Long nHelplineDist
=rRec
.nHelplineDist
;
465 tools::Long dx
= basegfx::fround
<tools::Long
>(nLineDist
* nHlpCos
);
466 tools::Long dy
= basegfx::fround
<tools::Long
>(nLineDist
* -nHlpSin
);
467 tools::Long dxh1a
= basegfx::fround
<tools::Long
>((nHelplineDist
- rRec
.nHelpline1Len
) * nHlpCos
);
468 tools::Long dyh1a
= basegfx::fround
<tools::Long
>((nHelplineDist
- rRec
.nHelpline1Len
) * -nHlpSin
);
469 tools::Long dxh1b
= basegfx::fround
<tools::Long
>((nHelplineDist
- rRec
.nHelpline2Len
) * nHlpCos
);
470 tools::Long dyh1b
= basegfx::fround
<tools::Long
>((nHelplineDist
- rRec
.nHelpline2Len
) * -nHlpSin
);
471 tools::Long dxh2
= basegfx::fround
<tools::Long
>((nLineDist
+ nOverhang
) * nHlpCos
);
472 tools::Long dyh2
= basegfx::fround
<tools::Long
>((nLineDist
+ nOverhang
) * -nHlpSin
);
475 rPol
.aHelpline1
.aP1
=Point(aP1
.X()+dxh1a
,aP1
.Y()+dyh1a
);
476 rPol
.aHelpline1
.aP2
=Point(aP1
.X()+dxh2
,aP1
.Y()+dyh2
);
479 rPol
.aHelpline2
.aP1
=Point(aP2
.X()+dxh1b
,aP2
.Y()+dyh1b
);
480 rPol
.aHelpline2
.aP2
=Point(aP2
.X()+dxh2
,aP2
.Y()+dyh2
);
483 Point
aMainlinePt1(aP1
.X()+dx
,aP1
.Y()+dy
);
484 Point
aMainlinePt2(aP2
.X()+dx
,aP2
.Y()+dy
);
485 if (!bPfeileAussen
) {
486 rPol
.aMainline1
.aP1
=aMainlinePt1
;
487 rPol
.aMainline1
.aP2
=aMainlinePt2
;
488 rPol
.aMainline2
=rPol
.aMainline1
;
489 rPol
.aMainline3
=rPol
.aMainline1
;
492 tools::Long nNeedSiz
=!rRec
.bTextRota90
? rPol
.aTextSize
.Width() : rPol
.aTextSize
.Height();
493 tools::Long nHalfLen
=(rPol
.nLineLen
-nNeedSiz
-nArrow1Wdt
/4-nArrow2Wdt
/4) /2;
495 rPol
.aMainline1
.aP2
=aMainlinePt1
;
496 rPol
.aMainline1
.aP2
.AdjustX(nHalfLen
);
497 RotatePoint(rPol
.aMainline1
.aP2
,rPol
.aMainline1
.aP1
,nLineSin
,nLineCos
);
498 rPol
.aMainline2
.aP1
=aMainlinePt2
;
499 rPol
.aMainline2
.aP1
.AdjustX( -nHalfLen
);
500 RotatePoint(rPol
.aMainline2
.aP1
,rPol
.aMainline2
.aP2
,nLineSin
,nLineCos
);
503 tools::Long nLen1
=nShortLen
; // arrowhead's width as line length outside of the arrowhead
504 tools::Long nLen2
=nShortLen
;
505 tools::Long nTextWdt
=rRec
.bTextRota90
? rPol
.aTextSize
.Height() : rPol
.aTextSize
.Width();
507 if (rPol
.eUsedTextHPos
==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE
) nLen1
=nArrow1Len
+nTextWdt
;
508 if (rPol
.eUsedTextHPos
==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE
) nLen2
=nArrow2Len
+nTextWdt
;
510 rPol
.aMainline1
.aP1
=aMainlinePt1
;
511 rPol
.aMainline1
.aP2
=aMainlinePt1
; rPol
.aMainline1
.aP2
.AdjustX( -nLen1
); RotatePoint(rPol
.aMainline1
.aP2
,aMainlinePt1
,nLineSin
,nLineCos
);
512 rPol
.aMainline2
.aP1
=aMainlinePt2
; rPol
.aMainline2
.aP1
.AdjustX(nLen2
); RotatePoint(rPol
.aMainline2
.aP1
,aMainlinePt2
,nLineSin
,nLineCos
);
513 rPol
.aMainline2
.aP2
=aMainlinePt2
;
514 rPol
.aMainline3
.aP1
=aMainlinePt1
;
515 rPol
.aMainline3
.aP2
=aMainlinePt2
;
517 if (bBrkLine
&& rPol
.eUsedTextHPos
==css::drawing::MeasureTextHorzPos_INSIDE
) rPol
.nMainlineCnt
=2;
521 basegfx::B2DPolyPolygon
SdrMeasureObj::ImpCalcXPoly(const ImpMeasurePoly
& rPol
)
523 basegfx::B2DPolyPolygon aRetval
;
524 basegfx::B2DPolygon aPartPolyA
;
525 aPartPolyA
.append(basegfx::B2DPoint(rPol
.aMainline1
.aP1
.X(), rPol
.aMainline1
.aP1
.Y()));
526 aPartPolyA
.append(basegfx::B2DPoint(rPol
.aMainline1
.aP2
.X(), rPol
.aMainline1
.aP2
.Y()));
527 aRetval
.append(aPartPolyA
);
529 if(rPol
.nMainlineCnt
> 1)
532 aPartPolyA
.append(basegfx::B2DPoint(rPol
.aMainline2
.aP1
.X(), rPol
.aMainline2
.aP1
.Y()));
533 aPartPolyA
.append(basegfx::B2DPoint(rPol
.aMainline2
.aP2
.X(), rPol
.aMainline2
.aP2
.Y()));
534 aRetval
.append(aPartPolyA
);
537 if(rPol
.nMainlineCnt
> 2)
540 aPartPolyA
.append(basegfx::B2DPoint(rPol
.aMainline3
.aP1
.X(), rPol
.aMainline3
.aP1
.Y()));
541 aPartPolyA
.append(basegfx::B2DPoint(rPol
.aMainline3
.aP2
.X(), rPol
.aMainline3
.aP2
.Y()));
542 aRetval
.append(aPartPolyA
);
546 aPartPolyA
.append(basegfx::B2DPoint(rPol
.aHelpline1
.aP1
.X(), rPol
.aHelpline1
.aP1
.Y()));
547 aPartPolyA
.append(basegfx::B2DPoint(rPol
.aHelpline1
.aP2
.X(), rPol
.aHelpline1
.aP2
.Y()));
548 aRetval
.append(aPartPolyA
);
551 aPartPolyA
.append(basegfx::B2DPoint(rPol
.aHelpline2
.aP1
.X(), rPol
.aHelpline2
.aP1
.Y()));
552 aPartPolyA
.append(basegfx::B2DPoint(rPol
.aHelpline2
.aP2
.X(), rPol
.aHelpline2
.aP2
.Y()));
553 aRetval
.append(aPartPolyA
);
558 bool SdrMeasureObj::CalcFieldValue(const SvxFieldItem
& rField
, sal_Int32 nPara
, sal_uInt16 nPos
,
560 std::optional
<Color
>& rpTxtColor
, std::optional
<Color
>& rpFldColor
, std::optional
<FontLineStyle
>& rpFldLineStyle
, OUString
& rRet
) const
562 const SvxFieldData
* pField
=rField
.GetField();
563 const SdrMeasureField
* pMeasureField
=dynamic_cast<const SdrMeasureField
*>( pField
);
564 if (pMeasureField
!=nullptr) {
565 rRet
= TakeRepresentation(pMeasureField
->GetMeasureFieldKind());
566 if (rpFldColor
&& !bEdit
)
572 return SdrTextObj::CalcFieldValue(rField
,nPara
,nPos
,bEdit
,rpTxtColor
,rpFldColor
,rpFldLineStyle
,rRet
);
576 void SdrMeasureObj::UndirtyText() const
581 SdrOutliner
& rOutliner
=ImpGetDrawOutliner();
582 OutlinerParaObject
* pOutlinerParaObject
= SdrTextObj::GetOutlinerParaObject();
583 if(pOutlinerParaObject
==nullptr)
585 rOutliner
.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Rotate90Blanks
), EE_FEATURE_FIELD
), ESelection(0,0));
586 rOutliner
.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Value
), EE_FEATURE_FIELD
),ESelection(0,1));
587 rOutliner
.QuickInsertText(u
" "_ustr
, ESelection(0,2));
588 rOutliner
.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Unit
), EE_FEATURE_FIELD
),ESelection(0,3));
589 rOutliner
.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Rotate90Blanks
), EE_FEATURE_FIELD
),ESelection(0,4));
592 rOutliner
.SetStyleSheet(0, GetStyleSheet());
594 rOutliner
.SetParaAttribs(0, GetObjectItemSet());
597 const_cast<SdrMeasureObj
*>(this)->NbcSetOutlinerParaObject( rOutliner
.CreateParaObject() );
601 rOutliner
.SetText(*pOutlinerParaObject
);
604 rOutliner
.SetUpdateLayout(true);
605 rOutliner
.UpdateFields();
606 Size
aSiz(rOutliner
.CalcTextSize());
608 // cast to nonconst three times
609 const_cast<SdrMeasureObj
*>(this)->maTextSize
= aSiz
;
610 const_cast<SdrMeasureObj
*>(this)->mbTextSizeDirty
= false;
611 const_cast<SdrMeasureObj
*>(this)->bTextDirty
= false;
614 void SdrMeasureObj::TakeUnrotatedSnapRect(tools::Rectangle
& rRect
) const
616 if (bTextDirty
) UndirtyText();
618 ImpMeasurePoly aMPol
;
620 ImpCalcGeometrics(aRec
,aMPol
);
622 // determine TextSize including text frame margins
623 Size
aTextSize2(aMPol
.aTextSize
);
624 if (aTextSize2
.Width()<1) aTextSize2
.setWidth(1 );
625 if (aTextSize2
.Height()<1) aTextSize2
.setHeight(1 );
626 aTextSize2
.AdjustWidth(GetTextLeftDistance()+GetTextRightDistance() );
627 aTextSize2
.AdjustHeight(GetTextUpperDistance()+GetTextLowerDistance() );
629 Point
aPt1b(aMPol
.aMainline1
.aP1
);
630 tools::Long nLen
=aMPol
.nLineLen
;
631 tools::Long nLWdt
=aMPol
.nLineWdt2
;
632 tools::Long nArr1Len
=aMPol
.nArrow1Len
;
633 tools::Long nArr2Len
=aMPol
.nArrow2Len
;
634 if (aMPol
.bBreakedLine
) {
635 // In the case of a dashed line and Outside, the text should be
636 // placed next to the line at the arrowhead instead of directly
638 nArr1Len
=aMPol
.nShortLineLen
+aMPol
.nArrow1Wdt
/4;
639 nArr2Len
=aMPol
.nShortLineLen
+aMPol
.nArrow2Wdt
/4;
643 bool bRota90
=aRec
.bTextRota90
;
644 bool bUpsideDown
=aRec
.bTextUpsideDown
!=aMPol
.bAutoUpsideDown
;
645 bool bBelowRefEdge
=aRec
.bBelowRefEdge
;
646 css::drawing::MeasureTextHorzPos eMH
=aMPol
.eUsedTextHPos
;
647 css::drawing::MeasureTextVertPos eMV
=aMPol
.eUsedTextVPos
;
650 case css::drawing::MeasureTextHorzPos_LEFTOUTSIDE
: aTextPos
.setX(aPt1b
.X()-aTextSize2
.Width()-nArr1Len
-nLWdt
); break;
651 case css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE
: aTextPos
.setX(aPt1b
.X()+nLen
+nArr2Len
+nLWdt
); break;
652 default: aTextPos
.setX(aPt1b
.X() ); aTextSize2
.setWidth(nLen
);
655 case css::drawing::MeasureTextVertPos_CENTERED
:
656 aTextPos
.setY(aPt1b
.Y()-aTextSize2
.Height()/2 ); break;
657 case css::drawing::MeasureTextVertPos_WEST
: {
658 if (!bUpsideDown
) aTextPos
.setY(aPt1b
.Y()+nLWdt
);
659 else aTextPos
.setY(aPt1b
.Y()-aTextSize2
.Height()-nLWdt
);
662 if (!bUpsideDown
) aTextPos
.setY(aPt1b
.Y()-aTextSize2
.Height()-nLWdt
);
663 else aTextPos
.setY(aPt1b
.Y()+nLWdt
);
667 aTextPos
.AdjustX(aTextSize2
.Width() );
668 aTextPos
.AdjustY(aTextSize2
.Height() );
670 } else { // also if bTextRota90==TRUE
672 case css::drawing::MeasureTextHorzPos_LEFTOUTSIDE
: aTextPos
.setX(aPt1b
.X()-aTextSize2
.Height()-nArr1Len
); break;
673 case css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE
: aTextPos
.setX(aPt1b
.X()+nLen
+nArr2Len
); break;
674 default: aTextPos
.setX(aPt1b
.X() ); aTextSize2
.setHeight(nLen
);
677 case css::drawing::MeasureTextVertPos_CENTERED
:
678 aTextPos
.setY(aPt1b
.Y()+aTextSize2
.Width()/2 ); break;
679 case css::drawing::MeasureTextVertPos_WEST
: {
680 if (!bBelowRefEdge
) aTextPos
.setY(aPt1b
.Y()+aTextSize2
.Width()+nLWdt
);
681 else aTextPos
.setY(aPt1b
.Y()-nLWdt
);
684 if (!bBelowRefEdge
) aTextPos
.setY(aPt1b
.Y()-nLWdt
);
685 else aTextPos
.setY(aPt1b
.Y()+aTextSize2
.Width()+nLWdt
);
689 aTextPos
.AdjustX(aTextSize2
.Height() );
690 aTextPos
.AdjustY( -(aTextSize2
.Width()) );
693 if (aMPol
.nTextAngle
!= maGeo
.m_nRotationAngle
) {
694 const_cast<SdrMeasureObj
*>(this)->maGeo
.m_nRotationAngle
=aMPol
.nTextAngle
;
695 const_cast<SdrMeasureObj
*>(this)->maGeo
.RecalcSinCos();
697 RotatePoint(aTextPos
,aPt1b
,aMPol
.nLineSin
,aMPol
.nLineCos
);
698 aTextSize2
.AdjustWidth( 1 ); aTextSize2
.AdjustHeight( 1 ); // because of the Rect-Ctor's odd behavior
699 rRect
=tools::Rectangle(aTextPos
,aTextSize2
);
701 const_cast<SdrMeasureObj
*>(this)->setRectangle(rRect
);
703 if (aMPol
.nTextAngle
!= maGeo
.m_nRotationAngle
) {
704 const_cast<SdrMeasureObj
*>(this)->maGeo
.m_nRotationAngle
=aMPol
.nTextAngle
;
705 const_cast<SdrMeasureObj
*>(this)->maGeo
.RecalcSinCos();
709 rtl::Reference
<SdrObject
> SdrMeasureObj::CloneSdrObject(SdrModel
& rTargetModel
) const
711 return new SdrMeasureObj(rTargetModel
, *this);
714 OUString
SdrMeasureObj::TakeObjNameSingul() const
716 OUString
sName(SvxResId(STR_ObjNameSingulMEASURE
));
718 OUString
aName( GetName() );
719 if (!aName
.isEmpty())
720 sName
+= " '" + aName
+ "'";
725 OUString
SdrMeasureObj::TakeObjNamePlural() const
727 return SvxResId(STR_ObjNamePluralMEASURE
);
730 basegfx::B2DPolyPolygon
SdrMeasureObj::TakeXorPoly() const
733 ImpMeasurePoly aMPol
;
735 ImpCalcGeometrics(aRec
,aMPol
);
736 return ImpCalcXPoly(aMPol
);
739 sal_uInt32
SdrMeasureObj::GetHdlCount() const
744 void SdrMeasureObj::AddToHdlList(SdrHdlList
& rHdlList
) const
747 ImpMeasurePoly aMPol
;
749 aRec
.nHelplineDist
=0;
750 ImpCalcGeometrics(aRec
,aMPol
);
752 for (sal_uInt32 nHdlNum
=0; nHdlNum
<6; ++nHdlNum
)
756 case 0: aPt
=aMPol
.aHelpline1
.aP1
; break;
757 case 1: aPt
=aMPol
.aHelpline2
.aP1
; break;
758 case 2: aPt
=aPt1
; break;
759 case 3: aPt
=aPt2
; break;
760 case 4: aPt
=aMPol
.aHelpline1
.aP2
; break;
761 case 5: aPt
=aMPol
.aHelpline2
.aP2
; break;
763 std::unique_ptr
<SdrHdl
> pHdl(new ImpMeasureHdl(aPt
,SdrHdlKind::User
));
764 pHdl
->SetObjHdlNum(nHdlNum
);
765 pHdl
->SetRotationAngle(aMPol
.nLineAngle
);
766 rHdlList
.AddHdl(std::move(pHdl
));
771 bool SdrMeasureObj::hasSpecialDrag() const
776 bool SdrMeasureObj::beginSpecialDrag(SdrDragStat
& rDrag
) const
778 const SdrHdl
* pHdl
= rDrag
.GetHdl();
782 const sal_uInt32
nHdlNum(pHdl
->GetObjHdlNum());
784 if(nHdlNum
!= 2 && nHdlNum
!= 3)
786 rDrag
.SetEndDragChangesAttributes(true);
795 bool SdrMeasureObj::applySpecialDrag(SdrDragStat
& rDrag
)
797 ImpMeasureRec aMeasureRec
;
798 const SdrHdl
* pHdl
= rDrag
.GetHdl();
799 const sal_uInt32
nHdlNum(pHdl
->GetObjHdlNum());
801 ImpTakeAttr(aMeasureRec
);
802 ImpEvalDrag(aMeasureRec
, rDrag
);
808 aPt1
= aMeasureRec
.aPt1
;
814 aPt2
= aMeasureRec
.aPt2
;
825 ImpMeasureRec aOrigMeasureRec
;
826 ImpTakeAttr(aOrigMeasureRec
);
828 if(aMeasureRec
.nHelpline1Len
!= aOrigMeasureRec
.nHelpline1Len
)
830 SetObjectItem(makeSdrMeasureHelpline1LenItem(aMeasureRec
.nHelpline1Len
));
833 if(aMeasureRec
.nHelpline2Len
!= aOrigMeasureRec
.nHelpline2Len
)
835 SetObjectItem(makeSdrMeasureHelpline2LenItem(aMeasureRec
.nHelpline2Len
));
844 ImpMeasureRec aOrigMeasureRec
;
845 ImpTakeAttr(aOrigMeasureRec
);
847 if(aMeasureRec
.nLineDist
!= aOrigMeasureRec
.nLineDist
)
849 SetObjectItem(makeSdrMeasureLineDistItem(aMeasureRec
.nLineDist
));
852 if(aMeasureRec
.bBelowRefEdge
!= aOrigMeasureRec
.bBelowRefEdge
)
854 SetObjectItem(SdrMeasureBelowRefEdgeItem(aMeasureRec
.bBelowRefEdge
));
861 SetBoundAndSnapRectsDirty();
867 OUString
SdrMeasureObj::getSpecialDragComment(const SdrDragStat
& /*rDrag*/) const
872 void SdrMeasureObj::ImpEvalDrag(ImpMeasureRec
& rRec
, const SdrDragStat
& rDrag
) const
874 Degree100 nLineAngle
=GetAngle(rRec
.aPt2
-rRec
.aPt1
);
875 double a
= toRadians(nLineAngle
);
879 const SdrHdl
* pHdl
=rDrag
.GetHdl();
880 sal_uInt32
nHdlNum(pHdl
->GetObjHdlNum());
881 bool bOrtho
=rDrag
.GetView()!=nullptr && rDrag
.GetView()->IsOrtho();
882 bool bBigOrtho
=bOrtho
&& rDrag
.GetView()->IsBigOrtho();
883 bool bBelow
=rRec
.bBelowRefEdge
;
884 Point
aPt(rDrag
.GetNow());
888 RotatePoint(aPt
,aPt1
,nSin
,-nCos
);
889 rRec
.nHelpline1Len
=aPt1
.Y()-aPt
.Y();
890 if (bBelow
) rRec
.nHelpline1Len
=-rRec
.nHelpline1Len
;
891 if (bOrtho
) rRec
.nHelpline2Len
=rRec
.nHelpline1Len
;
894 RotatePoint(aPt
,aPt2
,nSin
,-nCos
);
895 rRec
.nHelpline2Len
=aPt2
.Y()-aPt
.Y();
896 if (bBelow
) rRec
.nHelpline2Len
=-rRec
.nHelpline2Len
;
897 if (bOrtho
) rRec
.nHelpline1Len
=rRec
.nHelpline2Len
;
900 bool bAnf
=nHdlNum
==2;
901 Point
& rMov
=bAnf
? rRec
.aPt1
: rRec
.aPt2
;
903 Point
aFix(bAnf
? rRec
.aPt2
: rRec
.aPt1
);
905 tools::Long ndx0
=aMov
.X()-aFix
.X();
906 tools::Long ndy0
=aMov
.Y()-aFix
.Y();
909 if (!bHLin
|| !bVLin
) { // else aPt1==aPt2
910 tools::Long ndx
=aPt
.X()-aFix
.X();
911 tools::Long ndy
=aPt
.Y()-aFix
.Y();
912 double nXFact
=0; if (!bVLin
) nXFact
=static_cast<double>(ndx
)/static_cast<double>(ndx0
);
913 double nYFact
=0; if (!bHLin
) nYFact
=static_cast<double>(ndy
)/static_cast<double>(ndy0
);
914 bool bHor
=bHLin
|| (!bVLin
&& (nXFact
>nYFact
) ==bBigOrtho
);
915 bool bVer
=bVLin
|| (!bHLin
&& (nXFact
<=nYFact
)==bBigOrtho
);
916 if (bHor
) ndy
=tools::Long(ndy0
*nXFact
);
917 if (bVer
) ndx
=tools::Long(ndx0
*nYFact
);
926 tools::Long nVal0
=rRec
.nLineDist
;
927 RotatePoint(aPt
,(nHdlNum
==4 ? aPt1
: aPt2
),nSin
,-nCos
);
928 rRec
.nLineDist
=aPt
.Y()- (nHdlNum
==4 ? aPt1
.Y() : aPt2
.Y());
929 if (bBelow
) rRec
.nLineDist
=-rRec
.nLineDist
;
930 if (rRec
.nLineDist
<0) {
931 rRec
.nLineDist
=-rRec
.nLineDist
;
932 rRec
.bBelowRefEdge
=!bBelow
;
934 rRec
.nLineDist
-=rRec
.nHelplineOverhang
;
935 if (bOrtho
) rRec
.nLineDist
=nVal0
;
941 bool SdrMeasureObj::BegCreate(SdrDragStat
& rStat
)
943 rStat
.SetOrtho8Possible();
944 aPt1
=rStat
.GetStart();
950 bool SdrMeasureObj::MovCreate(SdrDragStat
& rStat
)
952 SdrView
* pView
=rStat
.GetView();
953 aPt1
=rStat
.GetStart();
955 if (pView
!=nullptr && pView
->IsCreate1stPointAsCenter()) {
957 aPt1
-=rStat
.GetNow();
961 m_bSnapRectDirty
=true;
965 bool SdrMeasureObj::EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
968 SetBoundAndSnapRectsDirty();
969 return (eCmd
==SdrCreateCmd::ForceEnd
|| rStat
.GetPointCount()>=2);
972 bool SdrMeasureObj::BckCreate(SdrDragStat
& /*rStat*/)
977 void SdrMeasureObj::BrkCreate(SdrDragStat
& /*rStat*/)
981 basegfx::B2DPolyPolygon
SdrMeasureObj::TakeCreatePoly(const SdrDragStat
& /*rDrag*/) const
984 ImpMeasurePoly aMPol
;
987 ImpCalcGeometrics(aRec
, aMPol
);
989 return ImpCalcXPoly(aMPol
);
992 PointerStyle
SdrMeasureObj::GetCreatePointer() const
994 return PointerStyle::Cross
;
997 void SdrMeasureObj::NbcMove(const Size
& rSiz
)
999 SdrTextObj::NbcMove(rSiz
);
1004 void SdrMeasureObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
1006 SdrTextObj::NbcResize(rRef
,xFact
,yFact
);
1007 ResizePoint(aPt1
,rRef
,xFact
,yFact
);
1008 ResizePoint(aPt2
,rRef
,xFact
,yFact
);
1012 void SdrMeasureObj::NbcRotate(const Point
& rRef
, Degree100 nAngle
, double sn
, double cs
)
1014 SdrTextObj::NbcRotate(rRef
,nAngle
,sn
,cs
);
1015 tools::Long nLen0
=GetLen(aPt2
-aPt1
);
1016 RotatePoint(aPt1
,rRef
,sn
,cs
);
1017 RotatePoint(aPt2
,rRef
,sn
,cs
);
1018 tools::Long nLen1
=GetLen(aPt2
-aPt1
);
1019 if (nLen1
!=nLen0
) { // rounding error!
1020 tools::Long dx
=aPt2
.X()-aPt1
.X();
1021 tools::Long dy
=aPt2
.Y()-aPt1
.Y();
1022 dx
=BigMulDiv(dx
,nLen0
,nLen1
);
1023 dy
=BigMulDiv(dy
,nLen0
,nLen1
);
1025 aPt1
.setX(aPt2
.X()-dx
);
1026 aPt1
.setY(aPt2
.Y()-dy
);
1028 aPt2
.setX(aPt1
.X()+dx
);
1029 aPt2
.setY(aPt1
.Y()+dy
);
1032 SetBoundAndSnapRectsDirty();
1035 void SdrMeasureObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
1037 SdrTextObj::NbcMirror(rRef1
,rRef2
);
1038 MirrorPoint(aPt1
,rRef1
,rRef2
);
1039 MirrorPoint(aPt2
,rRef1
,rRef2
);
1040 SetBoundAndSnapRectsDirty();
1043 void SdrMeasureObj::NbcShear(const Point
& rRef
, Degree100 nAngle
, double tn
, bool bVShear
)
1045 SdrTextObj::NbcShear(rRef
,nAngle
,tn
,bVShear
);
1046 ShearPoint(aPt1
,rRef
,tn
,bVShear
);
1047 ShearPoint(aPt2
,rRef
,tn
,bVShear
);
1048 SetBoundAndSnapRectsDirty();
1052 Degree100
SdrMeasureObj::GetRotateAngle() const
1054 return GetAngle(aPt2
-aPt1
);
1057 void SdrMeasureObj::RecalcSnapRect()
1060 ImpMeasurePoly aMPol
;
1064 ImpCalcGeometrics(aRec
, aMPol
);
1065 aXPP
= XPolyPolygon(ImpCalcXPoly(aMPol
));
1066 maSnapRect
= aXPP
.GetBoundRect();
1069 sal_uInt32
SdrMeasureObj::GetSnapPointCount() const
1074 Point
SdrMeasureObj::GetSnapPoint(sal_uInt32 i
) const
1076 if (i
==0) return aPt1
;
1080 bool SdrMeasureObj::IsPolyObj() const
1085 sal_uInt32
SdrMeasureObj::GetPointCount() const
1090 Point
SdrMeasureObj::GetPoint(sal_uInt32 i
) const
1092 return (0 == i
) ? aPt1
: aPt2
;
1095 void SdrMeasureObj::NbcSetPoint(const Point
& rPnt
, sal_uInt32 i
)
1101 SetBoundAndSnapRectsDirty();
1105 std::unique_ptr
<SdrObjGeoData
> SdrMeasureObj::NewGeoData() const
1107 return std::make_unique
<SdrMeasureObjGeoData
>();
1110 void SdrMeasureObj::SaveGeoData(SdrObjGeoData
& rGeo
) const
1112 SdrTextObj::SaveGeoData(rGeo
);
1113 SdrMeasureObjGeoData
& rMGeo
=static_cast<SdrMeasureObjGeoData
&>(rGeo
);
1118 void SdrMeasureObj::RestoreGeoData(const SdrObjGeoData
& rGeo
)
1120 SdrTextObj::RestoreGeoData(rGeo
);
1121 const SdrMeasureObjGeoData
& rMGeo
=static_cast<const SdrMeasureObjGeoData
&>(rGeo
);
1127 rtl::Reference
<SdrObject
> SdrMeasureObj::DoConvertToPolyObj(bool bBezier
, bool bAddText
) const
1129 // get XOR Poly as base
1130 XPolyPolygon
aTmpPolyPolygon(TakeXorPoly());
1132 // get local ItemSet and StyleSheet
1133 SfxItemSet
aSet(GetObjectItemSet());
1134 SfxStyleSheet
* pStyleSheet
= GetStyleSheet();
1137 rtl::Reference
<SdrObjGroup
> pGroup(new SdrObjGroup(getSdrModelFromSdrObject()));
1139 // prepare parameters
1140 basegfx::B2DPolyPolygon aPolyPoly
;
1141 rtl::Reference
<SdrPathObj
> pPath
;
1142 sal_uInt16
nCount(aTmpPolyPolygon
.Count());
1143 sal_uInt16
nLoopStart(0);
1147 // three lines, first one is the middle one
1149 aPolyPoly
.append(aTmpPolyPolygon
[0].getB2DPolygon());
1151 pPath
= new SdrPathObj(
1152 getSdrModelFromSdrObject(),
1153 SdrObjKind::PathLine
,
1156 pPath
->SetMergedItemSet(aSet
);
1157 pPath
->SetStyleSheet(pStyleSheet
, true);
1158 pGroup
->GetSubList()->NbcInsertObject(pPath
.get());
1159 aSet
.Put(XLineStartWidthItem(0));
1160 aSet
.Put(XLineEndWidthItem(0));
1163 else if(nCount
== 4)
1165 // four lines, middle line with gap, so there are two lines used
1166 // which have one arrow each
1167 sal_Int32 nEndWidth
= aSet
.Get(XATTR_LINEENDWIDTH
).GetValue();
1168 aSet
.Put(XLineEndWidthItem(0));
1171 aPolyPoly
.append(aTmpPolyPolygon
[0].getB2DPolygon());
1172 pPath
= new SdrPathObj(
1173 getSdrModelFromSdrObject(),
1174 SdrObjKind::PathLine
,
1177 pPath
->SetMergedItemSet(aSet
);
1178 pPath
->SetStyleSheet(pStyleSheet
, true);
1180 pGroup
->GetSubList()->NbcInsertObject(pPath
.get());
1182 aSet
.Put(XLineEndWidthItem(nEndWidth
));
1183 aSet
.Put(XLineStartWidthItem(0));
1186 aPolyPoly
.append(aTmpPolyPolygon
[1].getB2DPolygon());
1187 pPath
= new SdrPathObj(
1188 getSdrModelFromSdrObject(),
1189 SdrObjKind::PathLine
,
1192 pPath
->SetMergedItemSet(aSet
);
1193 pPath
->SetStyleSheet(pStyleSheet
, true);
1195 pGroup
->GetSubList()->NbcInsertObject(pPath
.get());
1197 aSet
.Put(XLineEndWidthItem(0));
1200 else if(nCount
== 5)
1202 // five lines, first two are the outer ones
1203 sal_Int32 nEndWidth
= aSet
.Get(XATTR_LINEENDWIDTH
).GetValue();
1205 aSet
.Put(XLineEndWidthItem(0));
1208 aPolyPoly
.append(aTmpPolyPolygon
[0].getB2DPolygon());
1209 pPath
= new SdrPathObj(
1210 getSdrModelFromSdrObject(),
1211 SdrObjKind::PathLine
,
1214 pPath
->SetMergedItemSet(aSet
);
1215 pPath
->SetStyleSheet(pStyleSheet
, true);
1217 pGroup
->GetSubList()->NbcInsertObject(pPath
.get());
1219 aSet
.Put(XLineEndWidthItem(nEndWidth
));
1220 aSet
.Put(XLineStartWidthItem(0));
1223 aPolyPoly
.append(aTmpPolyPolygon
[1].getB2DPolygon());
1224 pPath
= new SdrPathObj(
1225 getSdrModelFromSdrObject(),
1226 SdrObjKind::PathLine
,
1229 pPath
->SetMergedItemSet(aSet
);
1230 pPath
->SetStyleSheet(pStyleSheet
, true);
1232 pGroup
->GetSubList()->NbcInsertObject(pPath
.get());
1234 aSet
.Put(XLineEndWidthItem(0));
1238 for(;nLoopStart
<nCount
;nLoopStart
++)
1241 aPolyPoly
.append(aTmpPolyPolygon
[nLoopStart
].getB2DPolygon());
1242 pPath
= new SdrPathObj(
1243 getSdrModelFromSdrObject(),
1244 SdrObjKind::PathLine
,
1247 pPath
->SetMergedItemSet(aSet
);
1248 pPath
->SetStyleSheet(pStyleSheet
, true);
1250 pGroup
->GetSubList()->NbcInsertObject(pPath
.get());
1255 return ImpConvertAddText(std::move(pGroup
), bBezier
);
1263 bool SdrMeasureObj::BegTextEdit(SdrOutliner
& rOutl
)
1266 return SdrTextObj::BegTextEdit(rOutl
);
1269 const Size
& SdrMeasureObj::GetTextSize() const
1271 if (bTextDirty
) UndirtyText();
1272 return SdrTextObj::GetTextSize();
1275 OutlinerParaObject
* SdrMeasureObj::GetOutlinerParaObject() const
1279 return SdrTextObj::GetOutlinerParaObject();
1282 void SdrMeasureObj::NbcSetOutlinerParaObject(std::optional
<OutlinerParaObject
> pTextObject
, bool bAdjustTextFrameWidthAndHeight
)
1284 SdrTextObj::NbcSetOutlinerParaObject(std::move(pTextObject
), bAdjustTextFrameWidthAndHeight
);
1285 if(SdrTextObj::GetOutlinerParaObject())
1286 SetTextDirty(); // recalculate text
1289 void SdrMeasureObj::TakeTextRect( SdrOutliner
& rOutliner
, tools::Rectangle
& rTextRect
, bool bNoEditText
,
1290 tools::Rectangle
* pAnchorRect
, bool bLineWidth
) const
1292 if (bTextDirty
) UndirtyText();
1293 SdrTextObj::TakeTextRect( rOutliner
, rTextRect
, bNoEditText
, pAnchorRect
, bLineWidth
);
1296 void SdrMeasureObj::TakeTextAnchorRect(tools::Rectangle
& rAnchorRect
) const
1298 if (bTextDirty
) UndirtyText();
1299 SdrTextObj::TakeTextAnchorRect(rAnchorRect
);
1302 void SdrMeasureObj::TakeTextEditArea(Size
* pPaperMin
, Size
* pPaperMax
, tools::Rectangle
* pViewInit
, tools::Rectangle
* pViewMin
) const
1304 if (bTextDirty
) UndirtyText();
1305 SdrTextObj::TakeTextEditArea(pPaperMin
,pPaperMax
,pViewInit
,pViewMin
);
1308 EEAnchorMode
SdrMeasureObj::GetOutlinerViewAnchorMode() const
1310 if (bTextDirty
) UndirtyText();
1312 ImpMeasurePoly aMPol
;
1314 ImpCalcGeometrics(aRec
,aMPol
);
1316 SdrTextHorzAdjust eTH
=GetTextHorizontalAdjust();
1317 SdrTextVertAdjust eTV
=GetTextVerticalAdjust();
1318 css::drawing::MeasureTextHorzPos eMH
= aMPol
.eUsedTextHPos
;
1319 css::drawing::MeasureTextVertPos eMV
= aMPol
.eUsedTextVPos
;
1320 bool bTextRota90
=aRec
.bTextRota90
;
1321 bool bBelowRefEdge
=aRec
.bBelowRefEdge
;
1323 // TODO: bTextUpsideDown should be interpreted here!
1325 if (eMH
==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE
) eTH
=SDRTEXTHORZADJUST_RIGHT
;
1326 if (eMH
==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE
) eTH
=SDRTEXTHORZADJUST_LEFT
;
1327 // at eMH==css::drawing::MeasureTextHorzPos_INSIDE we can anchor horizontally
1328 if (eMV
==css::drawing::MeasureTextVertPos_EAST
) eTV
=SDRTEXTVERTADJUST_BOTTOM
;
1329 if (eMV
==css::drawing::MeasureTextVertPos_WEST
) eTV
=SDRTEXTVERTADJUST_TOP
;
1330 if (eMV
==css::drawing::MeasureTextVertPos_CENTERED
) eTV
=SDRTEXTVERTADJUST_CENTER
;
1332 if (eMH
==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE
) eTV
=SDRTEXTVERTADJUST_BOTTOM
;
1333 if (eMH
==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE
) eTV
=SDRTEXTVERTADJUST_TOP
;
1334 // at eMH==css::drawing::MeasureTextHorzPos_INSIDE we can anchor vertically
1335 if (!bBelowRefEdge
) {
1336 if (eMV
==css::drawing::MeasureTextVertPos_EAST
) eTH
=SDRTEXTHORZADJUST_LEFT
;
1337 if (eMV
==css::drawing::MeasureTextVertPos_WEST
) eTH
=SDRTEXTHORZADJUST_RIGHT
;
1339 if (eMV
==css::drawing::MeasureTextVertPos_EAST
) eTH
=SDRTEXTHORZADJUST_RIGHT
;
1340 if (eMV
==css::drawing::MeasureTextVertPos_WEST
) eTH
=SDRTEXTHORZADJUST_LEFT
;
1342 if (eMV
==css::drawing::MeasureTextVertPos_CENTERED
) eTH
=SDRTEXTHORZADJUST_CENTER
;
1345 EEAnchorMode eRet
=EEAnchorMode::BottomHCenter
;
1346 if (eTH
==SDRTEXTHORZADJUST_LEFT
) {
1347 if (eTV
==SDRTEXTVERTADJUST_TOP
) eRet
=EEAnchorMode::TopLeft
;
1348 else if (eTV
==SDRTEXTVERTADJUST_BOTTOM
) eRet
=EEAnchorMode::BottomLeft
;
1349 else eRet
=EEAnchorMode::VCenterLeft
;
1350 } else if (eTH
==SDRTEXTHORZADJUST_RIGHT
) {
1351 if (eTV
==SDRTEXTVERTADJUST_TOP
) eRet
=EEAnchorMode::TopRight
;
1352 else if (eTV
==SDRTEXTVERTADJUST_BOTTOM
) eRet
=EEAnchorMode::BottomRight
;
1353 else eRet
=EEAnchorMode::VCenterRight
;
1355 if (eTV
==SDRTEXTVERTADJUST_TOP
) eRet
=EEAnchorMode::TopHCenter
;
1356 else if (eTV
==SDRTEXTVERTADJUST_BOTTOM
) eRet
=EEAnchorMode::BottomHCenter
;
1357 else eRet
=EEAnchorMode::VCenterHCenter
;
1364 // TRGetBaseGeometry/TRSetBaseGeometry needs to be based on two positions,
1365 // same as line geometry in SdrPathObj. Thus needs to be overridden and
1366 // implemented since currently it is derived from SdrTextObj which uses
1367 // a functionality based on SnapRect which is not useful here
1369 bool SdrMeasureObj::TRGetBaseGeometry(basegfx::B2DHomMatrix
& rMatrix
, basegfx::B2DPolyPolygon
& /*rPolyPolygon*/) const
1371 // handle the same as a simple line since the definition is based on two points
1372 const basegfx::B2DRange
aRange(aPt1
.X(), aPt1
.Y(), aPt2
.X(), aPt2
.Y());
1373 basegfx::B2DTuple
aScale(aRange
.getRange());
1374 basegfx::B2DTuple
aTranslate(aRange
.getMinimum());
1376 // position maybe relative to anchor position, convert
1377 if( getSdrModelFromSdrObject().IsWriter() )
1379 if(GetAnchorPos().X() || GetAnchorPos().Y())
1381 aTranslate
-= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
1385 // build return value matrix
1386 rMatrix
= basegfx::utils::createScaleTranslateB2DHomMatrix(aScale
, aTranslate
);
1391 void SdrMeasureObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix
& rMatrix
, const basegfx::B2DPolyPolygon
& /*rPolyPolygon*/)
1393 // use given transformation to derive the two defining points from unit line
1394 basegfx::B2DPoint
aPosA(rMatrix
* basegfx::B2DPoint(0.0, 0.0));
1395 basegfx::B2DPoint
aPosB(rMatrix
* basegfx::B2DPoint(1.0, 0.0));
1397 if( getSdrModelFromSdrObject().IsWriter() )
1399 // if anchor is used, make position relative to it
1400 if(GetAnchorPos().X() || GetAnchorPos().Y())
1402 const basegfx::B2DVector
aAnchorOffset(GetAnchorPos().X(), GetAnchorPos().Y());
1404 aPosA
+= aAnchorOffset
;
1405 aPosB
+= aAnchorOffset
;
1409 // derive new model data
1410 const Point
aNewPt1(basegfx::fround
<tools::Long
>(aPosA
.getX()), basegfx::fround
<tools::Long
>(aPosA
.getY()));
1411 const Point
aNewPt2(basegfx::fround
<tools::Long
>(aPosB
.getX()), basegfx::fround
<tools::Long
>(aPosB
.getY()));
1413 if(aNewPt1
== aPt1
&& aNewPt2
== aPt2
)
1416 // set model values and broadcast
1417 tools::Rectangle aBoundRect0
; if (m_pUserCall
!=nullptr) aBoundRect0
=GetLastBoundRect();
1425 BroadcastObjectChange();
1426 SendUserCall(SdrUserCallType::MoveOnly
,aBoundRect0
);
1429 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */