tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / svx / source / svdraw / svdomeas.cxx
blob5647d0331539caf5809e715fa7785ff6143e54d9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <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>
34 #include <math.h>
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
75 OUString aStr;
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));
99 Fraction aFact(1,1);
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());
118 if(!aFact.IsValid())
120 aStr = "?";
122 else
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);
139 nLen2--;
142 if(aStr[nLen2] == cDec || (cDecAlt && aStr[nLen2] == cDecAlt))
144 aStr = aStr.copy(0, nLen2);
145 nLen2--;
148 if(aStr.isEmpty())
149 aStr += "0";
152 break;
154 case SdrMeasureFieldKind::Unit:
156 if(bShowUnit)
158 eModUIUnit = getSdrModelFromSdrObject().GetUIUnit();
160 if(eMeasureUnit == FieldUnit::NONE)
161 eMeasureUnit = eModUIUnit;
163 aStr = SdrModel::GetUnitString(eMeasureUnit);
166 break;
168 case SdrMeasureFieldKind::Rotate90Blanks:
170 if(bTextRota90)
172 aStr = " ";
175 break;
178 return aStr;
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),
200 bTextDirty(false)
202 // #i25616#
203 mbSupportTextIndentingOnLineWidthChange = false;
206 SdrMeasureObj::SdrMeasureObj(SdrModel& rSdrModel, SdrMeasureObj const & rSource)
207 : SdrTextObj(rSdrModel, rSource),
208 bTextDirty(false)
210 // #i25616#
211 mbSupportTextIndentingOnLineWidthChange = false;
213 aPt1 = rSource.aPt1;
214 aPt2 = rSource.aPt2;
215 bTextDirty = rSource.bTextDirty;
218 SdrMeasureObj::SdrMeasureObj(
219 SdrModel& rSdrModel,
220 const Point& rPt1,
221 const Point& rPt2)
222 : SdrTextObj(rSdrModel),
223 aPt1(rPt1),
224 aPt2(rPt2),
225 bTextDirty(false)
227 // #i25616#
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
264 Point aPt1;
265 Point aPt2;
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;
273 bool bBelowRefEdge;
274 bool bTextRota90;
275 bool bTextUpsideDown;
276 bool bTextAutoAngle;
277 Degree100 nTextAutoAngleView;
280 namespace {
282 struct ImpLineRec
284 Point aP1;
285 Point aP2;
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;
297 Size aTextSize;
298 tools::Long nLineLen;
299 Degree100 nLineAngle;
300 Degree100 nTextAngle;
301 Degree100 nHlpAngle;
302 double nLineSin;
303 double nLineCos;
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
314 bool bBreakedLine;
317 void SdrMeasureObj::ImpTakeAttr(ImpMeasureRec& rRec) const
319 rRec.aPt1 = aPt1;
320 rRec.aPt2 = aPt2;
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));
344 if(bCenter)
346 nHeight /= 2;
349 return nHeight;
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);
361 rPol.nLineWdt2=0;
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;
366 rPol.nArrow1Wdt=0;
367 rPol.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();
377 if(nArrow1Wdt < 0)
378 nArrow1Wdt = -nLineWdt * nArrow1Wdt / 100; // <0 = relative
380 nArrow2Wdt = rSet.Get(XATTR_LINEENDWIDTH).GetValue();
381 if(nArrow2Wdt < 0)
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;
401 bool bBrkLine=false;
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
415 if (bBrkLine) {
416 if (nNeedSiz+nArrowNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
417 } else {
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) {
457 nHlpSin=-nHlpSin;
458 nHlpCos=-nHlpCos;
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);
474 // extension line 1
475 rPol.aHelpline1.aP1=Point(aP1.X()+dxh1a,aP1.Y()+dyh1a);
476 rPol.aHelpline1.aP2=Point(aP1.X()+dxh2,aP1.Y()+dyh2);
478 // extension line 2
479 rPol.aHelpline2.aP1=Point(aP2.X()+dxh1b,aP2.Y()+dyh1b);
480 rPol.aHelpline2.aP2=Point(aP2.X()+dxh2,aP2.Y()+dyh2);
482 // dimension line
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;
490 rPol.nMainlineCnt=1;
491 if (bBrkLine) {
492 tools::Long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
493 tools::Long nHalfLen=(rPol.nLineLen-nNeedSiz-nArrow1Wdt/4-nArrow2Wdt/4) /2;
494 rPol.nMainlineCnt=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);
502 } else {
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();
506 if (!bBrkLine) {
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;
516 rPol.nMainlineCnt=3;
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)
531 aPartPolyA.clear();
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)
539 aPartPolyA.clear();
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);
545 aPartPolyA.clear();
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);
550 aPartPolyA.clear();
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);
555 return aRetval;
558 bool SdrMeasureObj::CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_uInt16 nPos,
559 bool bEdit,
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)
568 rpFldColor.reset();
570 return true;
571 } else {
572 return SdrTextObj::CalcFieldValue(rField,nPara,nPos,bEdit,rpTxtColor,rpFldColor,rpFldLineStyle,rRet);
576 void SdrMeasureObj::UndirtyText() const
578 if (!bTextDirty)
579 return;
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));
591 if(GetStyleSheet())
592 rOutliner.SetStyleSheet(0, GetStyleSheet());
594 rOutliner.SetParaAttribs(0, GetObjectItemSet());
596 // cast to nonconst
597 const_cast<SdrMeasureObj*>(this)->NbcSetOutlinerParaObject( rOutliner.CreateParaObject() );
599 else
601 rOutliner.SetText(*pOutlinerParaObject);
604 rOutliner.SetUpdateLayout(true);
605 rOutliner.UpdateFields();
606 Size aSiz(rOutliner.CalcTextSize());
607 rOutliner.Clear();
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();
617 ImpMeasureRec aRec;
618 ImpMeasurePoly aMPol;
619 ImpTakeAttr(aRec);
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
637 // at the arrowhead.
638 nArr1Len=aMPol.nShortLineLen+aMPol.nArrow1Wdt/4;
639 nArr2Len=aMPol.nShortLineLen+aMPol.nArrow2Wdt/4;
642 Point aTextPos;
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;
648 if (!bRota90) {
649 switch (eMH) {
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 );
654 switch (eMV) {
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 );
660 } break;
661 default: {
662 if (!bUpsideDown) aTextPos.setY(aPt1b.Y()-aTextSize2.Height()-nLWdt );
663 else aTextPos.setY(aPt1b.Y()+nLWdt );
666 if (bUpsideDown) {
667 aTextPos.AdjustX(aTextSize2.Width() );
668 aTextPos.AdjustY(aTextSize2.Height() );
670 } else { // also if bTextRota90==TRUE
671 switch (eMH) {
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 );
676 switch (eMV) {
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 );
682 } break;
683 default: {
684 if (!bBelowRefEdge) aTextPos.setY(aPt1b.Y()-nLWdt );
685 else aTextPos.setY(aPt1b.Y()+aTextSize2.Width()+nLWdt );
688 if (bUpsideDown) {
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);
700 rRect.Normalize();
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 + "'";
722 return sName;
725 OUString SdrMeasureObj::TakeObjNamePlural() const
727 return SvxResId(STR_ObjNamePluralMEASURE);
730 basegfx::B2DPolyPolygon SdrMeasureObj::TakeXorPoly() const
732 ImpMeasureRec aRec;
733 ImpMeasurePoly aMPol;
734 ImpTakeAttr(aRec);
735 ImpCalcGeometrics(aRec,aMPol);
736 return ImpCalcXPoly(aMPol);
739 sal_uInt32 SdrMeasureObj::GetHdlCount() const
741 return 6;
744 void SdrMeasureObj::AddToHdlList(SdrHdlList& rHdlList) const
746 ImpMeasureRec aRec;
747 ImpMeasurePoly aMPol;
748 ImpTakeAttr(aRec);
749 aRec.nHelplineDist=0;
750 ImpCalcGeometrics(aRec,aMPol);
752 for (sal_uInt32 nHdlNum=0; nHdlNum<6; ++nHdlNum)
754 Point aPt;
755 switch (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;
762 } // switch
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
773 return true;
776 bool SdrMeasureObj::beginSpecialDrag(SdrDragStat& rDrag) const
778 const SdrHdl* pHdl = rDrag.GetHdl();
780 if(pHdl)
782 const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
784 if(nHdlNum != 2 && nHdlNum != 3)
786 rDrag.SetEndDragChangesAttributes(true);
789 return true;
792 return false;
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);
804 switch (nHdlNum)
806 case 2:
808 aPt1 = aMeasureRec.aPt1;
809 SetTextDirty();
810 break;
812 case 3:
814 aPt2 = aMeasureRec.aPt2;
815 SetTextDirty();
816 break;
818 default:
820 switch(nHdlNum)
822 case 0:
823 case 1:
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));
838 break;
841 case 4:
842 case 5:
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));
859 } // switch
861 SetBoundAndSnapRectsDirty();
862 SetChanged();
864 return true;
867 OUString SdrMeasureObj::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
869 return OUString();
872 void SdrMeasureObj::ImpEvalDrag(ImpMeasureRec& rRec, const SdrDragStat& rDrag) const
874 Degree100 nLineAngle=GetAngle(rRec.aPt2-rRec.aPt1);
875 double a = toRadians(nLineAngle);
876 double nSin=sin(a);
877 double nCos=cos(a);
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());
886 switch (nHdlNum) {
887 case 0: {
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;
892 } break;
893 case 1: {
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;
898 } break;
899 case 2: case 3: {
900 bool bAnf=nHdlNum==2;
901 Point& rMov=bAnf ? rRec.aPt1 : rRec.aPt2;
902 Point aMov(rMov);
903 Point aFix(bAnf ? rRec.aPt2 : rRec.aPt1);
904 if (bOrtho) {
905 tools::Long ndx0=aMov.X()-aFix.X();
906 tools::Long ndy0=aMov.Y()-aFix.Y();
907 bool bHLin=ndy0==0;
908 bool bVLin=ndx0==0;
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);
918 aPt=aFix;
919 aPt.AdjustX(ndx );
920 aPt.AdjustY(ndy );
921 } // else Ortho8
923 rMov=aPt;
924 } break;
925 case 4: case 5: {
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;
936 } break;
937 } // switch
941 bool SdrMeasureObj::BegCreate(SdrDragStat& rStat)
943 rStat.SetOrtho8Possible();
944 aPt1=rStat.GetStart();
945 aPt2=rStat.GetNow();
946 SetTextDirty();
947 return true;
950 bool SdrMeasureObj::MovCreate(SdrDragStat& rStat)
952 SdrView* pView=rStat.GetView();
953 aPt1=rStat.GetStart();
954 aPt2=rStat.GetNow();
955 if (pView!=nullptr && pView->IsCreate1stPointAsCenter()) {
956 aPt1+=aPt1;
957 aPt1-=rStat.GetNow();
959 SetTextDirty();
960 SetBoundRectDirty();
961 m_bSnapRectDirty=true;
962 return true;
965 bool SdrMeasureObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
967 SetTextDirty();
968 SetBoundAndSnapRectsDirty();
969 return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
972 bool SdrMeasureObj::BckCreate(SdrDragStat& /*rStat*/)
974 return false;
977 void SdrMeasureObj::BrkCreate(SdrDragStat& /*rStat*/)
981 basegfx::B2DPolyPolygon SdrMeasureObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
983 ImpMeasureRec aRec;
984 ImpMeasurePoly aMPol;
986 ImpTakeAttr(aRec);
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);
1000 aPt1.Move(rSiz);
1001 aPt2.Move(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);
1009 SetTextDirty();
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);
1024 if (rRef==aPt2) {
1025 aPt1.setX(aPt2.X()-dx );
1026 aPt1.setY(aPt2.Y()-dy );
1027 } else {
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();
1049 SetTextDirty();
1052 Degree100 SdrMeasureObj::GetRotateAngle() const
1054 return GetAngle(aPt2-aPt1);
1057 void SdrMeasureObj::RecalcSnapRect()
1059 ImpMeasureRec aRec;
1060 ImpMeasurePoly aMPol;
1061 XPolyPolygon aXPP;
1063 ImpTakeAttr(aRec);
1064 ImpCalcGeometrics(aRec, aMPol);
1065 aXPP = XPolyPolygon(ImpCalcXPoly(aMPol));
1066 maSnapRect = aXPP.GetBoundRect();
1069 sal_uInt32 SdrMeasureObj::GetSnapPointCount() const
1071 return 2;
1074 Point SdrMeasureObj::GetSnapPoint(sal_uInt32 i) const
1076 if (i==0) return aPt1;
1077 else return aPt2;
1080 bool SdrMeasureObj::IsPolyObj() const
1082 return true;
1085 sal_uInt32 SdrMeasureObj::GetPointCount() const
1087 return 2;
1090 Point SdrMeasureObj::GetPoint(sal_uInt32 i) const
1092 return (0 == i) ? aPt1 : aPt2;
1095 void SdrMeasureObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
1097 if (0 == i)
1098 aPt1=rPnt;
1099 if (1 == i)
1100 aPt2=rPnt;
1101 SetBoundAndSnapRectsDirty();
1102 SetTextDirty();
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);
1114 rMGeo.aPt1=aPt1;
1115 rMGeo.aPt2=aPt2;
1118 void SdrMeasureObj::RestoreGeoData(const SdrObjGeoData& rGeo)
1120 SdrTextObj::RestoreGeoData(rGeo);
1121 const SdrMeasureObjGeoData& rMGeo=static_cast<const SdrMeasureObjGeoData&>(rGeo);
1122 aPt1=rMGeo.aPt1;
1123 aPt2=rMGeo.aPt2;
1124 SetTextDirty();
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();
1136 // prepare group
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);
1145 if(nCount == 3)
1147 // three lines, first one is the middle one
1148 aPolyPoly.clear();
1149 aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1151 pPath = new SdrPathObj(
1152 getSdrModelFromSdrObject(),
1153 SdrObjKind::PathLine,
1154 aPolyPoly);
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));
1161 nLoopStart = 1;
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));
1170 aPolyPoly.clear();
1171 aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1172 pPath = new SdrPathObj(
1173 getSdrModelFromSdrObject(),
1174 SdrObjKind::PathLine,
1175 aPolyPoly);
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));
1185 aPolyPoly.clear();
1186 aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
1187 pPath = new SdrPathObj(
1188 getSdrModelFromSdrObject(),
1189 SdrObjKind::PathLine,
1190 aPolyPoly);
1192 pPath->SetMergedItemSet(aSet);
1193 pPath->SetStyleSheet(pStyleSheet, true);
1195 pGroup->GetSubList()->NbcInsertObject(pPath.get());
1197 aSet.Put(XLineEndWidthItem(0));
1198 nLoopStart = 2;
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));
1207 aPolyPoly.clear();
1208 aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1209 pPath = new SdrPathObj(
1210 getSdrModelFromSdrObject(),
1211 SdrObjKind::PathLine,
1212 aPolyPoly);
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));
1222 aPolyPoly.clear();
1223 aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
1224 pPath = new SdrPathObj(
1225 getSdrModelFromSdrObject(),
1226 SdrObjKind::PathLine,
1227 aPolyPoly);
1229 pPath->SetMergedItemSet(aSet);
1230 pPath->SetStyleSheet(pStyleSheet, true);
1232 pGroup->GetSubList()->NbcInsertObject(pPath.get());
1234 aSet.Put(XLineEndWidthItem(0));
1235 nLoopStart = 2;
1238 for(;nLoopStart<nCount;nLoopStart++)
1240 aPolyPoly.clear();
1241 aPolyPoly.append(aTmpPolyPolygon[nLoopStart].getB2DPolygon());
1242 pPath = new SdrPathObj(
1243 getSdrModelFromSdrObject(),
1244 SdrObjKind::PathLine,
1245 aPolyPoly);
1247 pPath->SetMergedItemSet(aSet);
1248 pPath->SetStyleSheet(pStyleSheet, true);
1250 pGroup->GetSubList()->NbcInsertObject(pPath.get());
1253 if(bAddText)
1255 return ImpConvertAddText(std::move(pGroup), bBezier);
1257 else
1259 return pGroup;
1263 bool SdrMeasureObj::BegTextEdit(SdrOutliner& rOutl)
1265 UndirtyText();
1266 return SdrTextObj::BegTextEdit(rOutl);
1269 const Size& SdrMeasureObj::GetTextSize() const
1271 if (bTextDirty) UndirtyText();
1272 return SdrTextObj::GetTextSize();
1275 OutlinerParaObject* SdrMeasureObj::GetOutlinerParaObject() const
1277 if(bTextDirty)
1278 UndirtyText();
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();
1311 ImpMeasureRec aRec;
1312 ImpMeasurePoly aMPol;
1313 ImpTakeAttr(aRec);
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!
1324 if (!bTextRota90) {
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;
1331 } else {
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;
1338 } else {
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;
1354 } else {
1355 if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopHCenter;
1356 else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomHCenter;
1357 else eRet=EEAnchorMode::VCenterHCenter;
1359 return eRet;
1363 // #i97878#
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);
1388 return true;
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)
1414 return;
1416 // set model values and broadcast
1417 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1419 aPt1 = aNewPt1;
1420 aPt2 = aNewPt2;
1422 SetTextDirty();
1423 ActionChanged();
1424 SetChanged();
1425 BroadcastObjectChange();
1426 SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
1429 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */