Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / svx / source / svdraw / svdomeas.cxx
blob4bbfb61ea289bac9fddbda8bb8109dca3e6c26e9
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 <rtl/ustrbuf.hxx>
66 #include <unotools/syslocale.hxx>
67 #include <unotools/localedatawrapper.hxx>
68 #include <vcl/ptrstyle.hxx>
71 SdrMeasureObjGeoData::SdrMeasureObjGeoData() {}
72 SdrMeasureObjGeoData::~SdrMeasureObjGeoData() {}
74 OUString SdrMeasureObj::TakeRepresentation(SdrMeasureFieldKind eMeasureFieldKind) const
76 OUString aStr;
77 Fraction aMeasureScale(1, 1);
78 bool bTextRota90(false);
79 bool bShowUnit(false);
80 FieldUnit eMeasureUnit(FieldUnit::NONE);
81 FieldUnit eModUIUnit(FieldUnit::NONE);
83 const SfxItemSet& rSet = GetMergedItemSet();
84 bTextRota90 = rSet.Get(SDRATTR_MEASURETEXTROTA90).GetValue();
85 eMeasureUnit = rSet.Get(SDRATTR_MEASUREUNIT).GetValue();
86 aMeasureScale = rSet.Get(SDRATTR_MEASURESCALE).GetValue();
87 bShowUnit = rSet.Get(SDRATTR_MEASURESHOWUNIT).GetValue();
88 sal_Int16 nNumDigits = rSet.Get(SDRATTR_MEASUREDECIMALPLACES).GetValue();
90 switch(eMeasureFieldKind)
92 case SdrMeasureFieldKind::Value:
94 eModUIUnit = getSdrModelFromSdrObject().GetUIUnit();
96 if(eMeasureUnit == FieldUnit::NONE)
97 eMeasureUnit = eModUIUnit;
99 sal_Int32 nLen(GetLen(aPt2 - aPt1));
100 Fraction aFact(1,1);
102 if(eMeasureUnit != eModUIUnit)
104 // for the unit conversion
105 aFact *= GetMapFactor(eModUIUnit, eMeasureUnit).X();
108 if(aMeasureScale.GetNumerator() != aMeasureScale.GetDenominator())
110 aFact *= aMeasureScale;
113 if(aFact.GetNumerator() != aFact.GetDenominator())
115 // scale via BigInt, to avoid overruns
116 nLen = BigMulDiv(nLen, aFact.GetNumerator(), aFact.GetDenominator());
119 if(!aFact.IsValid())
121 aStr = "?";
123 else
125 aStr = getSdrModelFromSdrObject().GetMetricString(nLen, true, nNumDigits);
128 SvtSysLocale aSysLocale;
129 const LocaleDataWrapper& rLocaleDataWrapper = aSysLocale.GetLocaleData();
130 sal_Unicode cDec(rLocaleDataWrapper.getNumDecimalSep()[0]);
131 sal_Unicode cDecAlt(rLocaleDataWrapper.getNumDecimalSepAlt().toChar());
133 if(aStr.indexOf(cDec) != -1 || (cDecAlt && aStr.indexOf(cDecAlt) != -1))
135 sal_Int32 nLen2(aStr.getLength() - 1);
137 while(aStr[nLen2] == '0')
139 aStr = aStr.copy(0, nLen2);
140 nLen2--;
143 if(aStr[nLen2] == cDec || (cDecAlt && aStr[nLen2] == cDecAlt))
145 aStr = aStr.copy(0, nLen2);
146 nLen2--;
149 if(aStr.isEmpty())
150 aStr += "0";
153 break;
155 case SdrMeasureFieldKind::Unit:
157 if(bShowUnit)
159 eModUIUnit = getSdrModelFromSdrObject().GetUIUnit();
161 if(eMeasureUnit == FieldUnit::NONE)
162 eMeasureUnit = eModUIUnit;
164 aStr = SdrModel::GetUnitString(eMeasureUnit);
167 break;
169 case SdrMeasureFieldKind::Rotate90Blanks:
171 if(bTextRota90)
173 aStr = " ";
176 break;
179 return aStr;
183 // BaseProperties section
185 std::unique_ptr<sdr::properties::BaseProperties> SdrMeasureObj::CreateObjectSpecificProperties()
187 return std::make_unique<sdr::properties::MeasureProperties>(*this);
191 // DrawContact section
193 std::unique_ptr<sdr::contact::ViewContact> SdrMeasureObj::CreateObjectSpecificViewContact()
195 return std::make_unique<sdr::contact::ViewContactOfSdrMeasureObj>(*this);
199 SdrMeasureObj::SdrMeasureObj(SdrModel& rSdrModel)
200 : SdrTextObj(rSdrModel),
201 bTextDirty(false)
203 // #i25616#
204 mbSupportTextIndentingOnLineWidthChange = false;
207 SdrMeasureObj::SdrMeasureObj(
208 SdrModel& rSdrModel,
209 const Point& rPt1,
210 const Point& rPt2)
211 : SdrTextObj(rSdrModel),
212 aPt1(rPt1),
213 aPt2(rPt2),
214 bTextDirty(false)
216 // #i25616#
217 mbSupportTextIndentingOnLineWidthChange = false;
220 SdrMeasureObj::~SdrMeasureObj()
224 void SdrMeasureObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
226 rInfo.bMoveAllowed =true;
227 rInfo.bResizeFreeAllowed=true;
228 rInfo.bResizePropAllowed=true;
229 rInfo.bRotateFreeAllowed=true;
230 rInfo.bRotate90Allowed =true;
231 rInfo.bMirrorFreeAllowed=true;
232 rInfo.bMirror45Allowed =true;
233 rInfo.bMirror90Allowed =true;
234 rInfo.bTransparenceAllowed = false;
235 rInfo.bShearAllowed =true;
236 rInfo.bEdgeRadiusAllowed=false;
237 rInfo.bNoOrthoDesired =true;
238 rInfo.bNoContortion =false;
239 rInfo.bCanConvToPath =false;
240 rInfo.bCanConvToPoly =true;
241 rInfo.bCanConvToPathLineToArea=false;
242 rInfo.bCanConvToPolyLineToArea=false;
243 rInfo.bCanConvToContour = LineGeometryUsageIsNecessary();
246 SdrObjKind SdrMeasureObj::GetObjIdentifier() const
248 return OBJ_MEASURE;
251 struct ImpMeasureRec : public SdrDragStatUserData
253 Point aPt1;
254 Point aPt2;
255 css::drawing::MeasureTextHorzPos eWantTextHPos;
256 css::drawing::MeasureTextVertPos eWantTextVPos;
257 tools::Long nLineDist;
258 tools::Long nHelplineOverhang;
259 tools::Long nHelplineDist;
260 tools::Long nHelpline1Len;
261 tools::Long nHelpline2Len;
262 bool bBelowRefEdge;
263 bool bTextRota90;
264 bool bTextUpsideDown;
265 bool bTextAutoAngle;
266 tools::Long nTextAutoAngleView;
269 namespace {
271 struct ImpLineRec
273 Point aP1;
274 Point aP2;
279 struct ImpMeasurePoly
281 ImpLineRec aMainline1; // those with the 1st arrowhead
282 ImpLineRec aMainline2; // those with the 2nd arrowhead
283 ImpLineRec aMainline3; // those in between
284 ImpLineRec aHelpline1;
285 ImpLineRec aHelpline2;
286 Size aTextSize;
287 tools::Long nLineLen;
288 tools::Long nLineAngle;
289 tools::Long nTextAngle;
290 tools::Long nHlpAngle;
291 double nLineSin;
292 double nLineCos;
293 sal_uInt16 nMainlineCnt;
294 css::drawing::MeasureTextHorzPos eUsedTextHPos;
295 css::drawing::MeasureTextVertPos eUsedTextVPos;
296 tools::Long nLineWdt2; // half the line width
297 tools::Long nArrow1Len; // length of 1st arrowhead; for Center, use only half
298 tools::Long nArrow2Len; // length of 2nd arrowhead; for Center, use only half
299 tools::Long nArrow1Wdt; // width of 1st arrow
300 tools::Long nArrow2Wdt; // width of 2nd arrow
301 tools::Long nShortLineLen; // line length, if PfeileAussen (arrowheads on the outside)
302 bool bAutoUpsideDown; // UpsideDown via automation
303 bool bBreakedLine;
306 void SdrMeasureObj::ImpTakeAttr(ImpMeasureRec& rRec) const
308 rRec.aPt1 = aPt1;
309 rRec.aPt2 = aPt2;
311 const SfxItemSet& rSet = GetObjectItemSet();
312 rRec.eWantTextHPos =rSet.Get(SDRATTR_MEASURETEXTHPOS ).GetValue();
313 rRec.eWantTextVPos =rSet.Get(SDRATTR_MEASURETEXTVPOS ).GetValue();
314 rRec.nLineDist =rSet.Get(SDRATTR_MEASURELINEDIST ).GetValue();
315 rRec.nHelplineOverhang =rSet.Get(SDRATTR_MEASUREHELPLINEOVERHANG).GetValue();
316 rRec.nHelplineDist =rSet.Get(SDRATTR_MEASUREHELPLINEDIST ).GetValue();
317 rRec.nHelpline1Len =rSet.Get(SDRATTR_MEASUREHELPLINE1LEN ).GetValue();
318 rRec.nHelpline2Len =rSet.Get(SDRATTR_MEASUREHELPLINE2LEN ).GetValue();
319 rRec.bBelowRefEdge =rSet.Get(SDRATTR_MEASUREBELOWREFEDGE ).GetValue();
320 rRec.bTextRota90 =rSet.Get(SDRATTR_MEASURETEXTROTA90 ).GetValue();
321 rRec.bTextUpsideDown =static_cast<const SdrMeasureTextUpsideDownItem& >(rSet.Get(SDRATTR_MEASURETEXTUPSIDEDOWN )).GetValue();
322 rRec.bTextAutoAngle =rSet.Get(SDRATTR_MEASURETEXTAUTOANGLE ).GetValue();
323 rRec.nTextAutoAngleView=static_cast<const SdrMeasureTextAutoAngleViewItem&>(rSet.Get(SDRATTR_MEASURETEXTAUTOANGLEVIEW)).GetValue();
326 static tools::Long impGetLineStartEndDistance(const basegfx::B2DPolyPolygon& rPolyPolygon, tools::Long nNewWidth, bool bCenter)
328 const basegfx::B2DRange aPolygonRange(rPolyPolygon.getB2DRange());
329 const double fOldWidth(std::max(aPolygonRange.getWidth(), 1.0));
330 const double fScale(static_cast<double>(nNewWidth) / fOldWidth);
331 tools::Long nHeight(basegfx::fround(aPolygonRange.getHeight() * fScale));
333 if(bCenter)
335 nHeight /= 2;
338 return nHeight;
341 void SdrMeasureObj::ImpCalcGeometrics(const ImpMeasureRec& rRec, ImpMeasurePoly& rPol) const
343 Point aP1(rRec.aPt1);
344 Point aP2(rRec.aPt2);
345 Point aDelt(aP2); aDelt-=aP1;
347 rPol.aTextSize=GetTextSize();
348 rPol.nLineLen=GetLen(aDelt);
350 rPol.nLineWdt2=0;
351 tools::Long nArrow1Len=0; bool bArrow1Center=false;
352 tools::Long nArrow2Len=0; bool bArrow2Center=false;
353 tools::Long nArrow1Wdt=0;
354 tools::Long nArrow2Wdt=0;
355 rPol.nArrow1Wdt=0;
356 rPol.nArrow2Wdt=0;
357 tools::Long nArrowNeed=0;
358 tools::Long nShortLen=0;
359 bool bPfeileAussen = false;
361 const SfxItemSet& rSet = GetObjectItemSet();
362 sal_Int32 nLineWdt = rSet.Get(XATTR_LINEWIDTH).GetValue(); // line width
363 rPol.nLineWdt2 = (nLineWdt + 1) / 2;
365 nArrow1Wdt = rSet.Get(XATTR_LINESTARTWIDTH).GetValue();
366 if(nArrow1Wdt < 0)
367 nArrow1Wdt = -nLineWdt * nArrow1Wdt / 100; // <0 = relative
369 nArrow2Wdt = rSet.Get(XATTR_LINEENDWIDTH).GetValue();
370 if(nArrow2Wdt < 0)
371 nArrow2Wdt = -nLineWdt * nArrow2Wdt / 100; // <0 = relative
373 basegfx::B2DPolyPolygon aPol1(rSet.Get(XATTR_LINESTART).GetLineStartValue());
374 basegfx::B2DPolyPolygon aPol2(rSet.Get(XATTR_LINEEND).GetLineEndValue());
375 bArrow1Center = rSet.Get(XATTR_LINESTARTCENTER).GetValue();
376 bArrow2Center = rSet.Get(XATTR_LINEENDCENTER).GetValue();
377 nArrow1Len = impGetLineStartEndDistance(aPol1, nArrow1Wdt, bArrow1Center) - 1;
378 nArrow2Len = impGetLineStartEndDistance(aPol2, nArrow2Wdt, bArrow2Center) - 1;
380 // nArrowLen is already halved at bCenter.
381 // In the case of 2 arrowheads each 4mm long, we can't go below 10mm.
382 nArrowNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2;
383 if (rPol.nLineLen<nArrowNeed) bPfeileAussen = true;
384 nShortLen=(nArrow1Len+nArrow1Wdt + nArrow2Len+nArrow2Wdt) /2;
386 rPol.eUsedTextHPos=rRec.eWantTextHPos;
387 rPol.eUsedTextVPos=rRec.eWantTextVPos;
388 if (rPol.eUsedTextVPos == css::drawing::MeasureTextVertPos_AUTO)
389 rPol.eUsedTextVPos = css::drawing::MeasureTextVertPos_EAST;
390 bool bBrkLine=false;
391 if (rPol.eUsedTextVPos == css::drawing::MeasureTextVertPos_CENTERED)
393 OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
394 if (pOutlinerParaObject!=nullptr && pOutlinerParaObject->GetTextObject().GetParagraphCount()==1)
396 bBrkLine=true; // dashed line if there's only on paragraph.
399 rPol.bBreakedLine=bBrkLine;
400 if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_AUTO) { // if text is too wide, push it outside
401 bool bOutside = false;
402 tools::Long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
403 if (nNeedSiz>rPol.nLineLen) bOutside = true; // text doesn't fit in between
404 if (bBrkLine) {
405 if (nNeedSiz+nArrowNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
406 } else {
407 tools::Long nSmallNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2/4;
408 if (nNeedSiz+nSmallNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
410 rPol.eUsedTextHPos=bOutside ? css::drawing::MeasureTextHorzPos_LEFTOUTSIDE : css::drawing::MeasureTextHorzPos_INSIDE;
412 if (rPol.eUsedTextHPos != css::drawing::MeasureTextHorzPos_INSIDE) bPfeileAussen = true;
413 rPol.nArrow1Wdt=nArrow1Wdt;
414 rPol.nArrow2Wdt=nArrow2Wdt;
415 rPol.nShortLineLen=nShortLen;
416 rPol.nArrow1Len=nArrow1Len;
417 rPol.nArrow2Len=nArrow2Len;
419 rPol.nLineAngle=GetAngle(aDelt);
420 double a = rPol.nLineAngle * F_PI18000;
421 double nLineSin=sin(a);
422 double nLineCos=cos(a);
423 rPol.nLineSin=nLineSin;
424 rPol.nLineCos=nLineCos;
426 rPol.nTextAngle=rPol.nLineAngle;
427 if (rRec.bTextRota90) rPol.nTextAngle+=9000;
429 rPol.bAutoUpsideDown=false;
430 if (rRec.bTextAutoAngle) {
431 tools::Long nTmpAngle=NormAngle36000(rPol.nTextAngle-rRec.nTextAutoAngleView);
432 if (nTmpAngle>=18000) {
433 rPol.nTextAngle+=18000;
434 rPol.bAutoUpsideDown=true;
438 if (rRec.bTextUpsideDown) rPol.nTextAngle+=18000;
439 rPol.nTextAngle=NormAngle36000(rPol.nTextAngle);
440 rPol.nHlpAngle=rPol.nLineAngle+9000;
441 if (rRec.bBelowRefEdge) rPol.nHlpAngle+=18000;
442 rPol.nHlpAngle=NormAngle36000(rPol.nHlpAngle);
443 double nHlpSin=nLineCos;
444 double nHlpCos=-nLineSin;
445 if (rRec.bBelowRefEdge) {
446 nHlpSin=-nHlpSin;
447 nHlpCos=-nHlpCos;
450 tools::Long nLineDist=rRec.nLineDist;
451 tools::Long nOverhang=rRec.nHelplineOverhang;
452 tools::Long nHelplineDist=rRec.nHelplineDist;
454 tools::Long dx= FRound(nLineDist*nHlpCos);
455 tools::Long dy=-FRound(nLineDist*nHlpSin);
456 tools::Long dxh1a= FRound((nHelplineDist-rRec.nHelpline1Len)*nHlpCos);
457 tools::Long dyh1a=-FRound((nHelplineDist-rRec.nHelpline1Len)*nHlpSin);
458 tools::Long dxh1b= FRound((nHelplineDist-rRec.nHelpline2Len)*nHlpCos);
459 tools::Long dyh1b=-FRound((nHelplineDist-rRec.nHelpline2Len)*nHlpSin);
460 tools::Long dxh2= FRound((nLineDist+nOverhang)*nHlpCos);
461 tools::Long dyh2=-FRound((nLineDist+nOverhang)*nHlpSin);
463 // extension line 1
464 rPol.aHelpline1.aP1=Point(aP1.X()+dxh1a,aP1.Y()+dyh1a);
465 rPol.aHelpline1.aP2=Point(aP1.X()+dxh2,aP1.Y()+dyh2);
467 // extension line 2
468 rPol.aHelpline2.aP1=Point(aP2.X()+dxh1b,aP2.Y()+dyh1b);
469 rPol.aHelpline2.aP2=Point(aP2.X()+dxh2,aP2.Y()+dyh2);
471 // dimension line
472 Point aMainlinePt1(aP1.X()+dx,aP1.Y()+dy);
473 Point aMainlinePt2(aP2.X()+dx,aP2.Y()+dy);
474 if (!bPfeileAussen) {
475 rPol.aMainline1.aP1=aMainlinePt1;
476 rPol.aMainline1.aP2=aMainlinePt2;
477 rPol.aMainline2=rPol.aMainline1;
478 rPol.aMainline3=rPol.aMainline1;
479 rPol.nMainlineCnt=1;
480 if (bBrkLine) {
481 tools::Long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
482 tools::Long nHalfLen=(rPol.nLineLen-nNeedSiz-nArrow1Wdt/4-nArrow2Wdt/4) /2;
483 rPol.nMainlineCnt=2;
484 rPol.aMainline1.aP2=aMainlinePt1;
485 rPol.aMainline1.aP2.AdjustX(nHalfLen );
486 RotatePoint(rPol.aMainline1.aP2,rPol.aMainline1.aP1,nLineSin,nLineCos);
487 rPol.aMainline2.aP1=aMainlinePt2;
488 rPol.aMainline2.aP1.AdjustX( -nHalfLen );
489 RotatePoint(rPol.aMainline2.aP1,rPol.aMainline2.aP2,nLineSin,nLineCos);
491 } else {
492 tools::Long nLen1=nShortLen; // arrowhead's width as line length outside of the arrowhead
493 tools::Long nLen2=nShortLen;
494 tools::Long nTextWdt=rRec.bTextRota90 ? rPol.aTextSize.Height() : rPol.aTextSize.Width();
495 if (!bBrkLine) {
496 if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) nLen1=nArrow1Len+nTextWdt;
497 if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) nLen2=nArrow2Len+nTextWdt;
499 rPol.aMainline1.aP1=aMainlinePt1;
500 rPol.aMainline1.aP2=aMainlinePt1; rPol.aMainline1.aP2.AdjustX( -nLen1 ); RotatePoint(rPol.aMainline1.aP2,aMainlinePt1,nLineSin,nLineCos);
501 rPol.aMainline2.aP1=aMainlinePt2; rPol.aMainline2.aP1.AdjustX(nLen2 ); RotatePoint(rPol.aMainline2.aP1,aMainlinePt2,nLineSin,nLineCos);
502 rPol.aMainline2.aP2=aMainlinePt2;
503 rPol.aMainline3.aP1=aMainlinePt1;
504 rPol.aMainline3.aP2=aMainlinePt2;
505 rPol.nMainlineCnt=3;
506 if (bBrkLine && rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_INSIDE) rPol.nMainlineCnt=2;
510 basegfx::B2DPolyPolygon SdrMeasureObj::ImpCalcXPoly(const ImpMeasurePoly& rPol)
512 basegfx::B2DPolyPolygon aRetval;
513 basegfx::B2DPolygon aPartPolyA;
514 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP1.X(), rPol.aMainline1.aP1.Y()));
515 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP2.X(), rPol.aMainline1.aP2.Y()));
516 aRetval.append(aPartPolyA);
518 if(rPol.nMainlineCnt > 1)
520 aPartPolyA.clear();
521 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP1.X(), rPol.aMainline2.aP1.Y()));
522 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP2.X(), rPol.aMainline2.aP2.Y()));
523 aRetval.append(aPartPolyA);
526 if(rPol.nMainlineCnt > 2)
528 aPartPolyA.clear();
529 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP1.X(), rPol.aMainline3.aP1.Y()));
530 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP2.X(), rPol.aMainline3.aP2.Y()));
531 aRetval.append(aPartPolyA);
534 aPartPolyA.clear();
535 aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP1.X(), rPol.aHelpline1.aP1.Y()));
536 aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP2.X(), rPol.aHelpline1.aP2.Y()));
537 aRetval.append(aPartPolyA);
539 aPartPolyA.clear();
540 aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP1.X(), rPol.aHelpline2.aP1.Y()));
541 aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP2.X(), rPol.aHelpline2.aP2.Y()));
542 aRetval.append(aPartPolyA);
544 return aRetval;
547 bool SdrMeasureObj::CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_uInt16 nPos,
548 bool bEdit,
549 std::optional<Color>& rpTxtColor, std::optional<Color>& rpFldColor, OUString& rRet) const
551 const SvxFieldData* pField=rField.GetField();
552 const SdrMeasureField* pMeasureField=dynamic_cast<const SdrMeasureField*>( pField );
553 if (pMeasureField!=nullptr) {
554 rRet = TakeRepresentation(pMeasureField->GetMeasureFieldKind());
555 if (rpFldColor && !bEdit)
557 rpFldColor.reset();
559 return true;
560 } else {
561 return SdrTextObj::CalcFieldValue(rField,nPara,nPos,bEdit,rpTxtColor,rpFldColor,rRet);
565 void SdrMeasureObj::UndirtyText() const
567 if (!bTextDirty)
568 return;
570 SdrOutliner& rOutliner=ImpGetDrawOutliner();
571 OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
572 if(pOutlinerParaObject==nullptr)
574 rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Rotate90Blanks), EE_FEATURE_FIELD), ESelection(0,0));
575 rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Value), EE_FEATURE_FIELD),ESelection(0,1));
576 rOutliner.QuickInsertText(" ", ESelection(0,2));
577 rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Unit), EE_FEATURE_FIELD),ESelection(0,3));
578 rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Rotate90Blanks), EE_FEATURE_FIELD),ESelection(0,4));
580 if(GetStyleSheet())
581 rOutliner.SetStyleSheet(0, GetStyleSheet());
583 rOutliner.SetParaAttribs(0, GetObjectItemSet());
585 // cast to nonconst
586 const_cast<SdrMeasureObj*>(this)->NbcSetOutlinerParaObject( rOutliner.CreateParaObject() );
588 else
590 rOutliner.SetText(*pOutlinerParaObject);
593 rOutliner.SetUpdateMode(true);
594 rOutliner.UpdateFields();
595 Size aSiz(rOutliner.CalcTextSize());
596 rOutliner.Clear();
597 // cast to nonconst three times
598 const_cast<SdrMeasureObj*>(this)->aTextSize=aSiz;
599 const_cast<SdrMeasureObj*>(this)->bTextSizeDirty=false;
600 const_cast<SdrMeasureObj*>(this)->bTextDirty=false;
603 void SdrMeasureObj::TakeUnrotatedSnapRect(tools::Rectangle& rRect) const
605 if (bTextDirty) UndirtyText();
606 ImpMeasureRec aRec;
607 ImpMeasurePoly aMPol;
608 ImpTakeAttr(aRec);
609 ImpCalcGeometrics(aRec,aMPol);
611 // determine TextSize including text frame margins
612 Size aTextSize2(aMPol.aTextSize);
613 if (aTextSize2.Width()<1) aTextSize2.setWidth(1 );
614 if (aTextSize2.Height()<1) aTextSize2.setHeight(1 );
615 aTextSize2.AdjustWidth(GetTextLeftDistance()+GetTextRightDistance() );
616 aTextSize2.AdjustHeight(GetTextUpperDistance()+GetTextLowerDistance() );
618 Point aPt1b(aMPol.aMainline1.aP1);
619 tools::Long nLen=aMPol.nLineLen;
620 tools::Long nLWdt=aMPol.nLineWdt2;
621 tools::Long nArr1Len=aMPol.nArrow1Len;
622 tools::Long nArr2Len=aMPol.nArrow2Len;
623 if (aMPol.bBreakedLine) {
624 // In the case of a dashed line and Outside, the text should be
625 // placed next to the line at the arrowhead instead of directly
626 // at the arrowhead.
627 nArr1Len=aMPol.nShortLineLen+aMPol.nArrow1Wdt/4;
628 nArr2Len=aMPol.nShortLineLen+aMPol.nArrow2Wdt/4;
631 Point aTextPos;
632 bool bRota90=aRec.bTextRota90;
633 bool bUpsideDown=aRec.bTextUpsideDown!=aMPol.bAutoUpsideDown;
634 bool bBelowRefEdge=aRec.bBelowRefEdge;
635 css::drawing::MeasureTextHorzPos eMH=aMPol.eUsedTextHPos;
636 css::drawing::MeasureTextVertPos eMV=aMPol.eUsedTextVPos;
637 if (!bRota90) {
638 switch (eMH) {
639 case css::drawing::MeasureTextHorzPos_LEFTOUTSIDE: aTextPos.setX(aPt1b.X()-aTextSize2.Width()-nArr1Len-nLWdt ); break;
640 case css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE: aTextPos.setX(aPt1b.X()+nLen+nArr2Len+nLWdt ); break;
641 default: aTextPos.setX(aPt1b.X() ); aTextSize2.setWidth(nLen );
643 switch (eMV) {
644 case css::drawing::MeasureTextVertPos_CENTERED:
645 aTextPos.setY(aPt1b.Y()-aTextSize2.Height()/2 ); break;
646 case css::drawing::MeasureTextVertPos_WEST: {
647 if (!bUpsideDown) aTextPos.setY(aPt1b.Y()+nLWdt );
648 else aTextPos.setY(aPt1b.Y()-aTextSize2.Height()-nLWdt );
649 } break;
650 default: {
651 if (!bUpsideDown) aTextPos.setY(aPt1b.Y()-aTextSize2.Height()-nLWdt );
652 else aTextPos.setY(aPt1b.Y()+nLWdt );
655 if (bUpsideDown) {
656 aTextPos.AdjustX(aTextSize2.Width() );
657 aTextPos.AdjustY(aTextSize2.Height() );
659 } else { // also if bTextRota90==TRUE
660 switch (eMH) {
661 case css::drawing::MeasureTextHorzPos_LEFTOUTSIDE: aTextPos.setX(aPt1b.X()-aTextSize2.Height()-nArr1Len ); break;
662 case css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE: aTextPos.setX(aPt1b.X()+nLen+nArr2Len ); break;
663 default: aTextPos.setX(aPt1b.X() ); aTextSize2.setHeight(nLen );
665 switch (eMV) {
666 case css::drawing::MeasureTextVertPos_CENTERED:
667 aTextPos.setY(aPt1b.Y()+aTextSize2.Width()/2 ); break;
668 case css::drawing::MeasureTextVertPos_WEST: {
669 if (!bBelowRefEdge) aTextPos.setY(aPt1b.Y()+aTextSize2.Width()+nLWdt );
670 else aTextPos.setY(aPt1b.Y()-nLWdt );
671 } break;
672 default: {
673 if (!bBelowRefEdge) aTextPos.setY(aPt1b.Y()-nLWdt );
674 else aTextPos.setY(aPt1b.Y()+aTextSize2.Width()+nLWdt );
677 if (bUpsideDown) {
678 aTextPos.AdjustX(aTextSize2.Height() );
679 aTextPos.AdjustY( -(aTextSize2.Width()) );
682 if (aMPol.nTextAngle!=aGeo.nRotationAngle) {
683 const_cast<SdrMeasureObj*>(this)->aGeo.nRotationAngle=aMPol.nTextAngle;
684 const_cast<SdrMeasureObj*>(this)->aGeo.RecalcSinCos();
686 RotatePoint(aTextPos,aPt1b,aMPol.nLineSin,aMPol.nLineCos);
687 aTextSize2.AdjustWidth( 1 ); aTextSize2.AdjustHeight( 1 ); // because of the Rect-Ctor's odd behavior
688 rRect=tools::Rectangle(aTextPos,aTextSize2);
689 rRect.Justify();
690 const_cast<SdrMeasureObj*>(this)->maRect=rRect;
692 if (aMPol.nTextAngle!=aGeo.nRotationAngle) {
693 const_cast<SdrMeasureObj*>(this)->aGeo.nRotationAngle=aMPol.nTextAngle;
694 const_cast<SdrMeasureObj*>(this)->aGeo.RecalcSinCos();
698 SdrMeasureObj* SdrMeasureObj::CloneSdrObject(SdrModel& rTargetModel) const
700 return CloneHelper< SdrMeasureObj >(rTargetModel);
703 SdrMeasureObj& SdrMeasureObj::operator=(const SdrMeasureObj& rObj)
705 if( this == &rObj )
706 return *this;
707 SdrTextObj::operator=(rObj);
709 aPt1 = rObj.aPt1;
710 aPt2 = rObj.aPt2;
711 bTextDirty = rObj.bTextDirty;
713 return *this;
716 OUString SdrMeasureObj::TakeObjNameSingul() const
718 OUStringBuffer sName(SvxResId(STR_ObjNameSingulMEASURE));
720 OUString aName( GetName() );
721 if (!aName.isEmpty())
723 sName.append(' ');
724 sName.append('\'');
725 sName.append(aName);
726 sName.append('\'');
729 return sName.makeStringAndClear();
732 OUString SdrMeasureObj::TakeObjNamePlural() const
734 return SvxResId(STR_ObjNamePluralMEASURE);
737 basegfx::B2DPolyPolygon SdrMeasureObj::TakeXorPoly() const
739 ImpMeasureRec aRec;
740 ImpMeasurePoly aMPol;
741 ImpTakeAttr(aRec);
742 ImpCalcGeometrics(aRec,aMPol);
743 return ImpCalcXPoly(aMPol);
746 sal_uInt32 SdrMeasureObj::GetHdlCount() const
748 return 6;
751 void SdrMeasureObj::AddToHdlList(SdrHdlList& rHdlList) const
753 ImpMeasureRec aRec;
754 ImpMeasurePoly aMPol;
755 ImpTakeAttr(aRec);
756 aRec.nHelplineDist=0;
757 ImpCalcGeometrics(aRec,aMPol);
759 for (sal_uInt32 nHdlNum=0; nHdlNum<6; ++nHdlNum)
761 Point aPt;
762 switch (nHdlNum) {
763 case 0: aPt=aMPol.aHelpline1.aP1; break;
764 case 1: aPt=aMPol.aHelpline2.aP1; break;
765 case 2: aPt=aPt1; break;
766 case 3: aPt=aPt2; break;
767 case 4: aPt=aMPol.aHelpline1.aP2; break;
768 case 5: aPt=aMPol.aHelpline2.aP2; break;
769 } // switch
770 std::unique_ptr<SdrHdl> pHdl(new ImpMeasureHdl(aPt,SdrHdlKind::User));
771 pHdl->SetObjHdlNum(nHdlNum);
772 pHdl->SetRotationAngle(aMPol.nLineAngle);
773 rHdlList.AddHdl(std::move(pHdl));
778 bool SdrMeasureObj::hasSpecialDrag() const
780 return true;
783 bool SdrMeasureObj::beginSpecialDrag(SdrDragStat& rDrag) const
785 const SdrHdl* pHdl = rDrag.GetHdl();
787 if(pHdl)
789 const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
791 if(nHdlNum != 2 && nHdlNum != 3)
793 rDrag.SetEndDragChangesAttributes(true);
796 return true;
799 return false;
802 bool SdrMeasureObj::applySpecialDrag(SdrDragStat& rDrag)
804 ImpMeasureRec aMeasureRec;
805 const SdrHdl* pHdl = rDrag.GetHdl();
806 const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
808 ImpTakeAttr(aMeasureRec);
809 ImpEvalDrag(aMeasureRec, rDrag);
811 switch (nHdlNum)
813 case 2:
815 aPt1 = aMeasureRec.aPt1;
816 SetTextDirty();
817 break;
819 case 3:
821 aPt2 = aMeasureRec.aPt2;
822 SetTextDirty();
823 break;
825 default:
827 switch(nHdlNum)
829 case 0:
830 case 1:
832 ImpMeasureRec aOrigMeasureRec;
833 ImpTakeAttr(aOrigMeasureRec);
835 if(aMeasureRec.nHelpline1Len != aOrigMeasureRec.nHelpline1Len)
837 SetObjectItem(makeSdrMeasureHelpline1LenItem(aMeasureRec.nHelpline1Len));
840 if(aMeasureRec.nHelpline2Len != aOrigMeasureRec.nHelpline2Len)
842 SetObjectItem(makeSdrMeasureHelpline2LenItem(aMeasureRec.nHelpline2Len));
845 break;
848 case 4:
849 case 5:
851 ImpMeasureRec aOrigMeasureRec;
852 ImpTakeAttr(aOrigMeasureRec);
854 if(aMeasureRec.nLineDist != aOrigMeasureRec.nLineDist)
856 SetObjectItem(makeSdrMeasureLineDistItem(aMeasureRec.nLineDist));
859 if(aMeasureRec.bBelowRefEdge != aOrigMeasureRec.bBelowRefEdge)
861 SetObjectItem(SdrMeasureBelowRefEdgeItem(aMeasureRec.bBelowRefEdge));
866 } // switch
868 SetRectsDirty();
869 SetChanged();
871 return true;
874 OUString SdrMeasureObj::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
876 return OUString();
879 void SdrMeasureObj::ImpEvalDrag(ImpMeasureRec& rRec, const SdrDragStat& rDrag) const
881 tools::Long nLineAngle=GetAngle(rRec.aPt2-rRec.aPt1);
882 double a = nLineAngle * F_PI18000;
883 double nSin=sin(a);
884 double nCos=cos(a);
886 const SdrHdl* pHdl=rDrag.GetHdl();
887 sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
888 bool bOrtho=rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho();
889 bool bBigOrtho=bOrtho && rDrag.GetView()->IsBigOrtho();
890 bool bBelow=rRec.bBelowRefEdge;
891 Point aPt(rDrag.GetNow());
893 switch (nHdlNum) {
894 case 0: {
895 RotatePoint(aPt,aPt1,nSin,-nCos);
896 rRec.nHelpline1Len=aPt1.Y()-aPt.Y();
897 if (bBelow) rRec.nHelpline1Len=-rRec.nHelpline1Len;
898 if (bOrtho) rRec.nHelpline2Len=rRec.nHelpline1Len;
899 } break;
900 case 1: {
901 RotatePoint(aPt,aPt2,nSin,-nCos);
902 rRec.nHelpline2Len=aPt2.Y()-aPt.Y();
903 if (bBelow) rRec.nHelpline2Len=-rRec.nHelpline2Len;
904 if (bOrtho) rRec.nHelpline1Len=rRec.nHelpline2Len;
905 } break;
906 case 2: case 3: {
907 bool bAnf=nHdlNum==2;
908 Point& rMov=bAnf ? rRec.aPt1 : rRec.aPt2;
909 Point aMov(rMov);
910 Point aFix(bAnf ? rRec.aPt2 : rRec.aPt1);
911 if (bOrtho) {
912 tools::Long ndx0=aMov.X()-aFix.X();
913 tools::Long ndy0=aMov.Y()-aFix.Y();
914 bool bHLin=ndy0==0;
915 bool bVLin=ndx0==0;
916 if (!bHLin || !bVLin) { // else aPt1==aPt2
917 tools::Long ndx=aPt.X()-aFix.X();
918 tools::Long ndy=aPt.Y()-aFix.Y();
919 double nXFact=0; if (!bVLin) nXFact=static_cast<double>(ndx)/static_cast<double>(ndx0);
920 double nYFact=0; if (!bHLin) nYFact=static_cast<double>(ndy)/static_cast<double>(ndy0);
921 bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
922 bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
923 if (bHor) ndy=tools::Long(ndy0*nXFact);
924 if (bVer) ndx=tools::Long(ndx0*nYFact);
925 aPt=aFix;
926 aPt.AdjustX(ndx );
927 aPt.AdjustY(ndy );
928 } // else Ortho8
930 rMov=aPt;
931 } break;
932 case 4: case 5: {
933 tools::Long nVal0=rRec.nLineDist;
934 RotatePoint(aPt,(nHdlNum==4 ? aPt1 : aPt2),nSin,-nCos);
935 rRec.nLineDist=aPt.Y()- (nHdlNum==4 ? aPt1.Y() : aPt2.Y());
936 if (bBelow) rRec.nLineDist=-rRec.nLineDist;
937 if (rRec.nLineDist<0) {
938 rRec.nLineDist=-rRec.nLineDist;
939 rRec.bBelowRefEdge=!bBelow;
941 rRec.nLineDist-=rRec.nHelplineOverhang;
942 if (bOrtho) rRec.nLineDist=nVal0;
943 } break;
944 } // switch
948 bool SdrMeasureObj::BegCreate(SdrDragStat& rStat)
950 rStat.SetOrtho8Possible();
951 aPt1=rStat.GetStart();
952 aPt2=rStat.GetNow();
953 SetTextDirty();
954 return true;
957 bool SdrMeasureObj::MovCreate(SdrDragStat& rStat)
959 SdrView* pView=rStat.GetView();
960 aPt1=rStat.GetStart();
961 aPt2=rStat.GetNow();
962 if (pView!=nullptr && pView->IsCreate1stPointAsCenter()) {
963 aPt1+=aPt1;
964 aPt1-=rStat.GetNow();
966 SetTextDirty();
967 SetBoundRectDirty();
968 bSnapRectDirty=true;
969 return true;
972 bool SdrMeasureObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
974 SetTextDirty();
975 SetRectsDirty();
976 return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
979 bool SdrMeasureObj::BckCreate(SdrDragStat& /*rStat*/)
981 return false;
984 void SdrMeasureObj::BrkCreate(SdrDragStat& /*rStat*/)
988 basegfx::B2DPolyPolygon SdrMeasureObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
990 ImpMeasureRec aRec;
991 ImpMeasurePoly aMPol;
993 ImpTakeAttr(aRec);
994 ImpCalcGeometrics(aRec, aMPol);
996 return ImpCalcXPoly(aMPol);
999 PointerStyle SdrMeasureObj::GetCreatePointer() const
1001 return PointerStyle::Cross;
1004 void SdrMeasureObj::NbcMove(const Size& rSiz)
1006 SdrTextObj::NbcMove(rSiz);
1007 aPt1.Move(rSiz);
1008 aPt2.Move(rSiz);
1011 void SdrMeasureObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
1013 SdrTextObj::NbcResize(rRef,xFact,yFact);
1014 ResizePoint(aPt1,rRef,xFact,yFact);
1015 ResizePoint(aPt2,rRef,xFact,yFact);
1016 SetTextDirty();
1019 void SdrMeasureObj::NbcRotate(const Point& rRef, tools::Long nAngle, double sn, double cs)
1021 SdrTextObj::NbcRotate(rRef,nAngle,sn,cs);
1022 tools::Long nLen0=GetLen(aPt2-aPt1);
1023 RotatePoint(aPt1,rRef,sn,cs);
1024 RotatePoint(aPt2,rRef,sn,cs);
1025 tools::Long nLen1=GetLen(aPt2-aPt1);
1026 if (nLen1!=nLen0) { // rounding error!
1027 tools::Long dx=aPt2.X()-aPt1.X();
1028 tools::Long dy=aPt2.Y()-aPt1.Y();
1029 dx=BigMulDiv(dx,nLen0,nLen1);
1030 dy=BigMulDiv(dy,nLen0,nLen1);
1031 if (rRef==aPt2) {
1032 aPt1.setX(aPt2.X()-dx );
1033 aPt1.setY(aPt2.Y()-dy );
1034 } else {
1035 aPt2.setX(aPt1.X()+dx );
1036 aPt2.setY(aPt1.Y()+dy );
1039 SetRectsDirty();
1042 void SdrMeasureObj::NbcMirror(const Point& rRef1, const Point& rRef2)
1044 SdrTextObj::NbcMirror(rRef1,rRef2);
1045 MirrorPoint(aPt1,rRef1,rRef2);
1046 MirrorPoint(aPt2,rRef1,rRef2);
1047 SetRectsDirty();
1050 void SdrMeasureObj::NbcShear(const Point& rRef, tools::Long nAngle, double tn, bool bVShear)
1052 SdrTextObj::NbcShear(rRef,nAngle,tn,bVShear);
1053 ShearPoint(aPt1,rRef,tn,bVShear);
1054 ShearPoint(aPt2,rRef,tn,bVShear);
1055 SetRectsDirty();
1056 SetTextDirty();
1059 tools::Long SdrMeasureObj::GetRotateAngle() const
1061 return GetAngle(aPt2-aPt1);
1064 void SdrMeasureObj::RecalcSnapRect()
1066 ImpMeasureRec aRec;
1067 ImpMeasurePoly aMPol;
1068 XPolyPolygon aXPP;
1070 ImpTakeAttr(aRec);
1071 ImpCalcGeometrics(aRec, aMPol);
1072 aXPP = XPolyPolygon(ImpCalcXPoly(aMPol));
1073 maSnapRect = aXPP.GetBoundRect();
1076 sal_uInt32 SdrMeasureObj::GetSnapPointCount() const
1078 return 2;
1081 Point SdrMeasureObj::GetSnapPoint(sal_uInt32 i) const
1083 if (i==0) return aPt1;
1084 else return aPt2;
1087 bool SdrMeasureObj::IsPolyObj() const
1089 return true;
1092 sal_uInt32 SdrMeasureObj::GetPointCount() const
1094 return 2;
1097 Point SdrMeasureObj::GetPoint(sal_uInt32 i) const
1099 return (0 == i) ? aPt1 : aPt2;
1102 void SdrMeasureObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
1104 if (0 == i)
1105 aPt1=rPnt;
1106 if (1 == i)
1107 aPt2=rPnt;
1108 SetRectsDirty();
1109 SetTextDirty();
1112 SdrObjGeoData* SdrMeasureObj::NewGeoData() const
1114 return new SdrMeasureObjGeoData;
1117 void SdrMeasureObj::SaveGeoData(SdrObjGeoData& rGeo) const
1119 SdrTextObj::SaveGeoData(rGeo);
1120 SdrMeasureObjGeoData& rMGeo=static_cast<SdrMeasureObjGeoData&>(rGeo);
1121 rMGeo.aPt1=aPt1;
1122 rMGeo.aPt2=aPt2;
1125 void SdrMeasureObj::RestGeoData(const SdrObjGeoData& rGeo)
1127 SdrTextObj::RestGeoData(rGeo);
1128 const SdrMeasureObjGeoData& rMGeo=static_cast<const SdrMeasureObjGeoData&>(rGeo);
1129 aPt1=rMGeo.aPt1;
1130 aPt2=rMGeo.aPt2;
1131 SetTextDirty();
1134 SdrObjectUniquePtr SdrMeasureObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
1136 // get XOR Poly as base
1137 XPolyPolygon aTmpPolyPolygon(TakeXorPoly());
1139 // get local ItemSet and StyleSheet
1140 SfxItemSet aSet(GetObjectItemSet());
1141 SfxStyleSheet* pStyleSheet = GetStyleSheet();
1143 // prepare group
1144 std::unique_ptr<SdrObjGroup,SdrObjectFreeOp> pGroup(new SdrObjGroup(getSdrModelFromSdrObject()));
1146 // prepare parameters
1147 basegfx::B2DPolyPolygon aPolyPoly;
1148 SdrPathObj* pPath;
1149 sal_uInt16 nCount(aTmpPolyPolygon.Count());
1150 sal_uInt16 nLoopStart(0);
1152 if(nCount == 3)
1154 // three lines, first one is the middle one
1155 aPolyPoly.clear();
1156 aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1158 pPath = new SdrPathObj(
1159 getSdrModelFromSdrObject(),
1160 OBJ_PATHLINE,
1161 aPolyPoly);
1163 pPath->SetMergedItemSet(aSet);
1164 pPath->SetStyleSheet(pStyleSheet, true);
1165 pGroup->GetSubList()->NbcInsertObject(pPath);
1166 aSet.Put(XLineStartWidthItem(0));
1167 aSet.Put(XLineEndWidthItem(0));
1168 nLoopStart = 1;
1170 else if(nCount == 4)
1172 // four lines, middle line with gap, so there are two lines used
1173 // which have one arrow each
1174 sal_Int32 nEndWidth = aSet.Get(XATTR_LINEENDWIDTH).GetValue();
1175 aSet.Put(XLineEndWidthItem(0));
1177 aPolyPoly.clear();
1178 aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1179 pPath = new SdrPathObj(
1180 getSdrModelFromSdrObject(),
1181 OBJ_PATHLINE,
1182 aPolyPoly);
1184 pPath->SetMergedItemSet(aSet);
1185 pPath->SetStyleSheet(pStyleSheet, true);
1187 pGroup->GetSubList()->NbcInsertObject(pPath);
1189 aSet.Put(XLineEndWidthItem(nEndWidth));
1190 aSet.Put(XLineStartWidthItem(0));
1192 aPolyPoly.clear();
1193 aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
1194 pPath = new SdrPathObj(
1195 getSdrModelFromSdrObject(),
1196 OBJ_PATHLINE,
1197 aPolyPoly);
1199 pPath->SetMergedItemSet(aSet);
1200 pPath->SetStyleSheet(pStyleSheet, true);
1202 pGroup->GetSubList()->NbcInsertObject(pPath);
1204 aSet.Put(XLineEndWidthItem(0));
1205 nLoopStart = 2;
1207 else if(nCount == 5)
1209 // five lines, first two are the outer ones
1210 sal_Int32 nEndWidth = aSet.Get(XATTR_LINEENDWIDTH).GetValue();
1212 aSet.Put(XLineEndWidthItem(0));
1214 aPolyPoly.clear();
1215 aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1216 pPath = new SdrPathObj(
1217 getSdrModelFromSdrObject(),
1218 OBJ_PATHLINE,
1219 aPolyPoly);
1221 pPath->SetMergedItemSet(aSet);
1222 pPath->SetStyleSheet(pStyleSheet, true);
1224 pGroup->GetSubList()->NbcInsertObject(pPath);
1226 aSet.Put(XLineEndWidthItem(nEndWidth));
1227 aSet.Put(XLineStartWidthItem(0));
1229 aPolyPoly.clear();
1230 aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
1231 pPath = new SdrPathObj(
1232 getSdrModelFromSdrObject(),
1233 OBJ_PATHLINE,
1234 aPolyPoly);
1236 pPath->SetMergedItemSet(aSet);
1237 pPath->SetStyleSheet(pStyleSheet, true);
1239 pGroup->GetSubList()->NbcInsertObject(pPath);
1241 aSet.Put(XLineEndWidthItem(0));
1242 nLoopStart = 2;
1245 for(;nLoopStart<nCount;nLoopStart++)
1247 aPolyPoly.clear();
1248 aPolyPoly.append(aTmpPolyPolygon[nLoopStart].getB2DPolygon());
1249 pPath = new SdrPathObj(
1250 getSdrModelFromSdrObject(),
1251 OBJ_PATHLINE,
1252 aPolyPoly);
1254 pPath->SetMergedItemSet(aSet);
1255 pPath->SetStyleSheet(pStyleSheet, true);
1257 pGroup->GetSubList()->NbcInsertObject(pPath);
1260 if(bAddText)
1262 return ImpConvertAddText(std::move(pGroup), bBezier);
1264 else
1266 return pGroup;
1270 bool SdrMeasureObj::BegTextEdit(SdrOutliner& rOutl)
1272 UndirtyText();
1273 return SdrTextObj::BegTextEdit(rOutl);
1276 const Size& SdrMeasureObj::GetTextSize() const
1278 if (bTextDirty) UndirtyText();
1279 return SdrTextObj::GetTextSize();
1282 OutlinerParaObject* SdrMeasureObj::GetOutlinerParaObject() const
1284 if(bTextDirty)
1285 UndirtyText();
1286 return SdrTextObj::GetOutlinerParaObject();
1289 void SdrMeasureObj::NbcSetOutlinerParaObject(std::unique_ptr<OutlinerParaObject> pTextObject)
1291 SdrTextObj::NbcSetOutlinerParaObject(std::move(pTextObject));
1292 if(SdrTextObj::GetOutlinerParaObject())
1293 SetTextDirty(); // recalculate text
1296 void SdrMeasureObj::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText,
1297 tools::Rectangle* pAnchorRect, bool bLineWidth ) const
1299 if (bTextDirty) UndirtyText();
1300 SdrTextObj::TakeTextRect( rOutliner, rTextRect, bNoEditText, pAnchorRect, bLineWidth );
1303 void SdrMeasureObj::TakeTextAnchorRect(tools::Rectangle& rAnchorRect) const
1305 if (bTextDirty) UndirtyText();
1306 SdrTextObj::TakeTextAnchorRect(rAnchorRect);
1309 void SdrMeasureObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin) const
1311 if (bTextDirty) UndirtyText();
1312 SdrTextObj::TakeTextEditArea(pPaperMin,pPaperMax,pViewInit,pViewMin);
1315 EEAnchorMode SdrMeasureObj::GetOutlinerViewAnchorMode() const
1317 if (bTextDirty) UndirtyText();
1318 ImpMeasureRec aRec;
1319 ImpMeasurePoly aMPol;
1320 ImpTakeAttr(aRec);
1321 ImpCalcGeometrics(aRec,aMPol);
1323 SdrTextHorzAdjust eTH=GetTextHorizontalAdjust();
1324 SdrTextVertAdjust eTV=GetTextVerticalAdjust();
1325 css::drawing::MeasureTextHorzPos eMH = aMPol.eUsedTextHPos;
1326 css::drawing::MeasureTextVertPos eMV = aMPol.eUsedTextVPos;
1327 bool bTextRota90=aRec.bTextRota90;
1328 bool bBelowRefEdge=aRec.bBelowRefEdge;
1330 // TODO: bTextUpsideDown should be interpreted here!
1331 if (!bTextRota90) {
1332 if (eMH==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) eTH=SDRTEXTHORZADJUST_RIGHT;
1333 if (eMH==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) eTH=SDRTEXTHORZADJUST_LEFT;
1334 // at eMH==css::drawing::MeasureTextHorzPos_INSIDE we can anchor horizontally
1335 if (eMV==css::drawing::MeasureTextVertPos_EAST) eTV=SDRTEXTVERTADJUST_BOTTOM;
1336 if (eMV==css::drawing::MeasureTextVertPos_WEST) eTV=SDRTEXTVERTADJUST_TOP;
1337 if (eMV==css::drawing::MeasureTextVertPos_CENTERED) eTV=SDRTEXTVERTADJUST_CENTER;
1338 } else {
1339 if (eMH==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) eTV=SDRTEXTVERTADJUST_BOTTOM;
1340 if (eMH==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) eTV=SDRTEXTVERTADJUST_TOP;
1341 // at eMH==css::drawing::MeasureTextHorzPos_INSIDE we can anchor vertically
1342 if (!bBelowRefEdge) {
1343 if (eMV==css::drawing::MeasureTextVertPos_EAST) eTH=SDRTEXTHORZADJUST_LEFT;
1344 if (eMV==css::drawing::MeasureTextVertPos_WEST) eTH=SDRTEXTHORZADJUST_RIGHT;
1345 } else {
1346 if (eMV==css::drawing::MeasureTextVertPos_EAST) eTH=SDRTEXTHORZADJUST_RIGHT;
1347 if (eMV==css::drawing::MeasureTextVertPos_WEST) eTH=SDRTEXTHORZADJUST_LEFT;
1349 if (eMV==css::drawing::MeasureTextVertPos_CENTERED) eTH=SDRTEXTHORZADJUST_CENTER;
1352 EEAnchorMode eRet=EEAnchorMode::BottomHCenter;
1353 if (eTH==SDRTEXTHORZADJUST_LEFT) {
1354 if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopLeft;
1355 else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomLeft;
1356 else eRet=EEAnchorMode::VCenterLeft;
1357 } else if (eTH==SDRTEXTHORZADJUST_RIGHT) {
1358 if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopRight;
1359 else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomRight;
1360 else eRet=EEAnchorMode::VCenterRight;
1361 } else {
1362 if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopHCenter;
1363 else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomHCenter;
1364 else eRet=EEAnchorMode::VCenterHCenter;
1366 return eRet;
1370 // #i97878#
1371 // TRGetBaseGeometry/TRSetBaseGeometry needs to be based on two positions,
1372 // same as line geometry in SdrPathObj. Thus needs to be overridden and
1373 // implemented since currently it is derived from SdrTextObj which uses
1374 // a functionality based on SnapRect which is not useful here
1376 bool SdrMeasureObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
1378 // handle the same as a simple line since the definition is based on two points
1379 const basegfx::B2DRange aRange(aPt1.X(), aPt1.Y(), aPt2.X(), aPt2.Y());
1380 basegfx::B2DTuple aScale(aRange.getRange());
1381 basegfx::B2DTuple aTranslate(aRange.getMinimum());
1383 // position maybe relative to anchor position, convert
1384 if( getSdrModelFromSdrObject().IsWriter() )
1386 if(GetAnchorPos().X() || GetAnchorPos().Y())
1388 aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
1392 // build return value matrix
1393 rMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(aScale, aTranslate);
1395 return true;
1398 void SdrMeasureObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
1400 // use given transformation to derive the two defining points from unit line
1401 basegfx::B2DPoint aPosA(rMatrix * basegfx::B2DPoint(0.0, 0.0));
1402 basegfx::B2DPoint aPosB(rMatrix * basegfx::B2DPoint(1.0, 0.0));
1404 if( getSdrModelFromSdrObject().IsWriter() )
1406 // if anchor is used, make position relative to it
1407 if(GetAnchorPos().X() || GetAnchorPos().Y())
1409 const basegfx::B2DVector aAnchorOffset(GetAnchorPos().X(), GetAnchorPos().Y());
1411 aPosA += aAnchorOffset;
1412 aPosB += aAnchorOffset;
1416 // derive new model data
1417 const Point aNewPt1(basegfx::fround(aPosA.getX()), basegfx::fround(aPosA.getY()));
1418 const Point aNewPt2(basegfx::fround(aPosB.getX()), basegfx::fround(aPosB.getY()));
1420 if(aNewPt1 == aPt1 && aNewPt2 == aPt2)
1421 return;
1423 // set model values and broadcast
1424 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1426 aPt1 = aNewPt1;
1427 aPt2 = aNewPt2;
1429 SetTextDirty();
1430 ActionChanged();
1431 SetChanged();
1432 BroadcastObjectChange();
1433 SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
1436 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */