summaryrefslogtreecommitdiffstats
path: root/svx/source/svdraw/svdomeas.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /svx/source/svdraw/svdomeas.cxx
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'svx/source/svdraw/svdomeas.cxx')
-rw-r--r--svx/source/svdraw/svdomeas.cxx1429
1 files changed, 1429 insertions, 0 deletions
diff --git a/svx/source/svdraw/svdomeas.cxx b/svx/source/svdraw/svdomeas.cxx
new file mode 100644
index 000000000..da9959c84
--- /dev/null
+++ b/svx/source/svdraw/svdomeas.cxx
@@ -0,0 +1,1429 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <editeng/editdata.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/measfld.hxx>
+#include <editeng/outlobj.hxx>
+#include <math.h>
+#include <svl/style.hxx>
+
+#include <sdr/contact/viewcontactofsdrmeasureobj.hxx>
+#include <sdr/properties/measureproperties.hxx>
+#include <svx/svddrag.hxx>
+#include <svx/svdhdl.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdomeas.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sxmbritm.hxx>
+#include <svx/sxmlhitm.hxx>
+#include <sxmsitm.hxx>
+#include <sxmtaitm.hxx>
+#include <svx/sxmtfitm.hxx>
+#include <svx/sxmtpitm.hxx>
+#include <svx/sxmtritm.hxx>
+#include <svx/sxmuitm.hxx>
+#include <svx/xlnedcit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstcit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xpoly.hxx>
+#include <unotools/syslocale.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/ptrstyle.hxx>
+
+
+SdrMeasureObjGeoData::SdrMeasureObjGeoData() {}
+SdrMeasureObjGeoData::~SdrMeasureObjGeoData() {}
+
+OUString SdrMeasureObj::TakeRepresentation(SdrMeasureFieldKind eMeasureFieldKind) const
+{
+ OUString aStr;
+ Fraction aMeasureScale(1, 1);
+ bool bTextRota90(false);
+ bool bShowUnit(false);
+ FieldUnit eMeasureUnit(FieldUnit::NONE);
+ FieldUnit eModUIUnit(FieldUnit::NONE);
+
+ const SfxItemSet& rSet = GetMergedItemSet();
+ bTextRota90 = rSet.Get(SDRATTR_MEASURETEXTROTA90).GetValue();
+ eMeasureUnit = rSet.Get(SDRATTR_MEASUREUNIT).GetValue();
+ aMeasureScale = rSet.Get(SDRATTR_MEASURESCALE).GetValue();
+ bShowUnit = rSet.Get(SDRATTR_MEASURESHOWUNIT).GetValue();
+ sal_Int16 nNumDigits = rSet.Get(SDRATTR_MEASUREDECIMALPLACES).GetValue();
+
+ switch(eMeasureFieldKind)
+ {
+ case SdrMeasureFieldKind::Value:
+ {
+ eModUIUnit = getSdrModelFromSdrObject().GetUIUnit();
+
+ if(eMeasureUnit == FieldUnit::NONE)
+ eMeasureUnit = eModUIUnit;
+
+ sal_Int32 nLen(GetLen(aPt2 - aPt1));
+ Fraction aFact(1,1);
+
+ if(eMeasureUnit != eModUIUnit)
+ {
+ // for the unit conversion
+ aFact *= GetMapFactor(eModUIUnit, eMeasureUnit).X();
+ }
+
+ if(aMeasureScale.GetNumerator() != aMeasureScale.GetDenominator())
+ {
+ aFact *= aMeasureScale;
+ }
+
+ if(aFact.GetNumerator() != aFact.GetDenominator())
+ {
+ // scale via BigInt, to avoid overruns
+ nLen = BigMulDiv(nLen, aFact.GetNumerator(), aFact.GetDenominator());
+ }
+
+ if(!aFact.IsValid())
+ {
+ aStr = "?";
+ }
+ else
+ {
+ aStr = getSdrModelFromSdrObject().GetMetricString(nLen, true, nNumDigits);
+ }
+
+ SvtSysLocale aSysLocale;
+ const LocaleDataWrapper& rLocaleDataWrapper = aSysLocale.GetLocaleData();
+ sal_Unicode cDec(rLocaleDataWrapper.getNumDecimalSep()[0]);
+ sal_Unicode cDecAlt(rLocaleDataWrapper.getNumDecimalSepAlt().toChar());
+
+ if(aStr.indexOf(cDec) != -1 || (cDecAlt && aStr.indexOf(cDecAlt) != -1))
+ {
+ sal_Int32 nLen2(aStr.getLength() - 1);
+
+ while(aStr[nLen2] == '0')
+ {
+ aStr = aStr.copy(0, nLen2);
+ nLen2--;
+ }
+
+ if(aStr[nLen2] == cDec || (cDecAlt && aStr[nLen2] == cDecAlt))
+ {
+ aStr = aStr.copy(0, nLen2);
+ nLen2--;
+ }
+
+ if(aStr.isEmpty())
+ aStr += "0";
+ }
+
+ break;
+ }
+ case SdrMeasureFieldKind::Unit:
+ {
+ if(bShowUnit)
+ {
+ eModUIUnit = getSdrModelFromSdrObject().GetUIUnit();
+
+ if(eMeasureUnit == FieldUnit::NONE)
+ eMeasureUnit = eModUIUnit;
+
+ aStr = SdrModel::GetUnitString(eMeasureUnit);
+ }
+
+ break;
+ }
+ case SdrMeasureFieldKind::Rotate90Blanks:
+ {
+ if(bTextRota90)
+ {
+ aStr = " ";
+ }
+
+ break;
+ }
+ }
+ return aStr;
+}
+
+
+// BaseProperties section
+
+std::unique_ptr<sdr::properties::BaseProperties> SdrMeasureObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::MeasureProperties>(*this);
+}
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> SdrMeasureObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfSdrMeasureObj>(*this);
+}
+
+
+SdrMeasureObj::SdrMeasureObj(SdrModel& rSdrModel)
+: SdrTextObj(rSdrModel),
+ bTextDirty(false)
+{
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+}
+
+SdrMeasureObj::SdrMeasureObj(SdrModel& rSdrModel, SdrMeasureObj const & rSource)
+: SdrTextObj(rSdrModel, rSource),
+ bTextDirty(false)
+{
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+
+ aPt1 = rSource.aPt1;
+ aPt2 = rSource.aPt2;
+ bTextDirty = rSource.bTextDirty;
+}
+
+SdrMeasureObj::SdrMeasureObj(
+ SdrModel& rSdrModel,
+ const Point& rPt1,
+ const Point& rPt2)
+: SdrTextObj(rSdrModel),
+ aPt1(rPt1),
+ aPt2(rPt2),
+ bTextDirty(false)
+{
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+}
+
+SdrMeasureObj::~SdrMeasureObj()
+{
+}
+
+void SdrMeasureObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ rInfo.bMoveAllowed =true;
+ rInfo.bResizeFreeAllowed=true;
+ rInfo.bResizePropAllowed=true;
+ rInfo.bRotateFreeAllowed=true;
+ rInfo.bRotate90Allowed =true;
+ rInfo.bMirrorFreeAllowed=true;
+ rInfo.bMirror45Allowed =true;
+ rInfo.bMirror90Allowed =true;
+ rInfo.bTransparenceAllowed = false;
+ rInfo.bShearAllowed =true;
+ rInfo.bEdgeRadiusAllowed=false;
+ rInfo.bNoOrthoDesired =true;
+ rInfo.bNoContortion =false;
+ rInfo.bCanConvToPath =false;
+ rInfo.bCanConvToPoly =true;
+ rInfo.bCanConvToPathLineToArea=false;
+ rInfo.bCanConvToPolyLineToArea=false;
+ rInfo.bCanConvToContour = LineGeometryUsageIsNecessary();
+}
+
+SdrObjKind SdrMeasureObj::GetObjIdentifier() const
+{
+ return SdrObjKind::Measure;
+}
+
+struct ImpMeasureRec : public SdrDragStatUserData
+{
+ Point aPt1;
+ Point aPt2;
+ css::drawing::MeasureTextHorzPos eWantTextHPos;
+ css::drawing::MeasureTextVertPos eWantTextVPos;
+ tools::Long nLineDist;
+ tools::Long nHelplineOverhang;
+ tools::Long nHelplineDist;
+ tools::Long nHelpline1Len;
+ tools::Long nHelpline2Len;
+ bool bBelowRefEdge;
+ bool bTextRota90;
+ bool bTextUpsideDown;
+ bool bTextAutoAngle;
+ Degree100 nTextAutoAngleView;
+};
+
+namespace {
+
+struct ImpLineRec
+{
+ Point aP1;
+ Point aP2;
+};
+
+}
+
+struct ImpMeasurePoly
+{
+ ImpLineRec aMainline1; // those with the 1st arrowhead
+ ImpLineRec aMainline2; // those with the 2nd arrowhead
+ ImpLineRec aMainline3; // those in between
+ ImpLineRec aHelpline1;
+ ImpLineRec aHelpline2;
+ Size aTextSize;
+ tools::Long nLineLen;
+ Degree100 nLineAngle;
+ Degree100 nTextAngle;
+ Degree100 nHlpAngle;
+ double nLineSin;
+ double nLineCos;
+ sal_uInt16 nMainlineCnt;
+ css::drawing::MeasureTextHorzPos eUsedTextHPos;
+ css::drawing::MeasureTextVertPos eUsedTextVPos;
+ tools::Long nLineWdt2; // half the line width
+ tools::Long nArrow1Len; // length of 1st arrowhead; for Center, use only half
+ tools::Long nArrow2Len; // length of 2nd arrowhead; for Center, use only half
+ tools::Long nArrow1Wdt; // width of 1st arrow
+ tools::Long nArrow2Wdt; // width of 2nd arrow
+ tools::Long nShortLineLen; // line length, if PfeileAussen (arrowheads on the outside)
+ bool bAutoUpsideDown; // UpsideDown via automation
+ bool bBreakedLine;
+};
+
+void SdrMeasureObj::ImpTakeAttr(ImpMeasureRec& rRec) const
+{
+ rRec.aPt1 = aPt1;
+ rRec.aPt2 = aPt2;
+
+ const SfxItemSet& rSet = GetObjectItemSet();
+ rRec.eWantTextHPos =rSet.Get(SDRATTR_MEASURETEXTHPOS ).GetValue();
+ rRec.eWantTextVPos =rSet.Get(SDRATTR_MEASURETEXTVPOS ).GetValue();
+ rRec.nLineDist =rSet.Get(SDRATTR_MEASURELINEDIST ).GetValue();
+ rRec.nHelplineOverhang =rSet.Get(SDRATTR_MEASUREHELPLINEOVERHANG).GetValue();
+ rRec.nHelplineDist =rSet.Get(SDRATTR_MEASUREHELPLINEDIST ).GetValue();
+ rRec.nHelpline1Len =rSet.Get(SDRATTR_MEASUREHELPLINE1LEN ).GetValue();
+ rRec.nHelpline2Len =rSet.Get(SDRATTR_MEASUREHELPLINE2LEN ).GetValue();
+ rRec.bBelowRefEdge =rSet.Get(SDRATTR_MEASUREBELOWREFEDGE ).GetValue();
+ rRec.bTextRota90 =rSet.Get(SDRATTR_MEASURETEXTROTA90 ).GetValue();
+ rRec.bTextUpsideDown =static_cast<const SdrMeasureTextUpsideDownItem& >(rSet.Get(SDRATTR_MEASURETEXTUPSIDEDOWN )).GetValue();
+ rRec.bTextAutoAngle =rSet.Get(SDRATTR_MEASURETEXTAUTOANGLE ).GetValue();
+ rRec.nTextAutoAngleView=static_cast<const SdrMeasureTextAutoAngleViewItem&>(rSet.Get(SDRATTR_MEASURETEXTAUTOANGLEVIEW)).GetValue();
+}
+
+static tools::Long impGetLineStartEndDistance(const basegfx::B2DPolyPolygon& rPolyPolygon, tools::Long nNewWidth, bool bCenter)
+{
+ const basegfx::B2DRange aPolygonRange(rPolyPolygon.getB2DRange());
+ const double fOldWidth(std::max(aPolygonRange.getWidth(), 1.0));
+ const double fScale(static_cast<double>(nNewWidth) / fOldWidth);
+ tools::Long nHeight(basegfx::fround(aPolygonRange.getHeight() * fScale));
+
+ if(bCenter)
+ {
+ nHeight /= 2;
+ }
+
+ return nHeight;
+}
+
+void SdrMeasureObj::ImpCalcGeometrics(const ImpMeasureRec& rRec, ImpMeasurePoly& rPol) const
+{
+ Point aP1(rRec.aPt1);
+ Point aP2(rRec.aPt2);
+ Point aDelt(aP2); aDelt-=aP1;
+
+ rPol.aTextSize=GetTextSize();
+ rPol.nLineLen=GetLen(aDelt);
+
+ rPol.nLineWdt2=0;
+ tools::Long nArrow1Len=0; bool bArrow1Center=false;
+ tools::Long nArrow2Len=0; bool bArrow2Center=false;
+ tools::Long nArrow1Wdt=0;
+ tools::Long nArrow2Wdt=0;
+ rPol.nArrow1Wdt=0;
+ rPol.nArrow2Wdt=0;
+ tools::Long nArrowNeed=0;
+ tools::Long nShortLen=0;
+ bool bPfeileAussen = false;
+
+ const SfxItemSet& rSet = GetObjectItemSet();
+ sal_Int32 nLineWdt = rSet.Get(XATTR_LINEWIDTH).GetValue(); // line width
+ rPol.nLineWdt2 = (nLineWdt + 1) / 2;
+
+ nArrow1Wdt = rSet.Get(XATTR_LINESTARTWIDTH).GetValue();
+ if(nArrow1Wdt < 0)
+ nArrow1Wdt = -nLineWdt * nArrow1Wdt / 100; // <0 = relative
+
+ nArrow2Wdt = rSet.Get(XATTR_LINEENDWIDTH).GetValue();
+ if(nArrow2Wdt < 0)
+ nArrow2Wdt = -nLineWdt * nArrow2Wdt / 100; // <0 = relative
+
+ basegfx::B2DPolyPolygon aPol1(rSet.Get(XATTR_LINESTART).GetLineStartValue());
+ basegfx::B2DPolyPolygon aPol2(rSet.Get(XATTR_LINEEND).GetLineEndValue());
+ bArrow1Center = rSet.Get(XATTR_LINESTARTCENTER).GetValue();
+ bArrow2Center = rSet.Get(XATTR_LINEENDCENTER).GetValue();
+ nArrow1Len = impGetLineStartEndDistance(aPol1, nArrow1Wdt, bArrow1Center) - 1;
+ nArrow2Len = impGetLineStartEndDistance(aPol2, nArrow2Wdt, bArrow2Center) - 1;
+
+ // nArrowLen is already halved at bCenter.
+ // In the case of 2 arrowheads each 4mm long, we can't go below 10mm.
+ nArrowNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2;
+ if (rPol.nLineLen<nArrowNeed) bPfeileAussen = true;
+ nShortLen=(nArrow1Len+nArrow1Wdt + nArrow2Len+nArrow2Wdt) /2;
+
+ rPol.eUsedTextHPos=rRec.eWantTextHPos;
+ rPol.eUsedTextVPos=rRec.eWantTextVPos;
+ if (rPol.eUsedTextVPos == css::drawing::MeasureTextVertPos_AUTO)
+ rPol.eUsedTextVPos = css::drawing::MeasureTextVertPos_EAST;
+ bool bBrkLine=false;
+ if (rPol.eUsedTextVPos == css::drawing::MeasureTextVertPos_CENTERED)
+ {
+ OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
+ if (pOutlinerParaObject!=nullptr && pOutlinerParaObject->GetTextObject().GetParagraphCount()==1)
+ {
+ bBrkLine=true; // dashed line if there's only on paragraph.
+ }
+ }
+ rPol.bBreakedLine=bBrkLine;
+ if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_AUTO) { // if text is too wide, push it outside
+ bool bOutside = false;
+ tools::Long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
+ if (nNeedSiz>rPol.nLineLen) bOutside = true; // text doesn't fit in between
+ if (bBrkLine) {
+ if (nNeedSiz+nArrowNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
+ } else {
+ tools::Long nSmallNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2/4;
+ if (nNeedSiz+nSmallNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
+ }
+ rPol.eUsedTextHPos=bOutside ? css::drawing::MeasureTextHorzPos_LEFTOUTSIDE : css::drawing::MeasureTextHorzPos_INSIDE;
+ }
+ if (rPol.eUsedTextHPos != css::drawing::MeasureTextHorzPos_INSIDE) bPfeileAussen = true;
+ rPol.nArrow1Wdt=nArrow1Wdt;
+ rPol.nArrow2Wdt=nArrow2Wdt;
+ rPol.nShortLineLen=nShortLen;
+ rPol.nArrow1Len=nArrow1Len;
+ rPol.nArrow2Len=nArrow2Len;
+
+ rPol.nLineAngle=GetAngle(aDelt);
+ double a = toRadians(rPol.nLineAngle);
+ double nLineSin=sin(a);
+ double nLineCos=cos(a);
+ rPol.nLineSin=nLineSin;
+ rPol.nLineCos=nLineCos;
+
+ rPol.nTextAngle=rPol.nLineAngle;
+ if (rRec.bTextRota90) rPol.nTextAngle+=9000_deg100;
+
+ rPol.bAutoUpsideDown=false;
+ if (rRec.bTextAutoAngle) {
+ Degree100 nTmpAngle=NormAngle36000(rPol.nTextAngle-rRec.nTextAutoAngleView);
+ if (nTmpAngle>=18000_deg100) {
+ rPol.nTextAngle+=18000_deg100;
+ rPol.bAutoUpsideDown=true;
+ }
+ }
+
+ if (rRec.bTextUpsideDown) rPol.nTextAngle+=18000_deg100;
+ rPol.nTextAngle=NormAngle36000(rPol.nTextAngle);
+ rPol.nHlpAngle=rPol.nLineAngle+9000_deg100;
+ if (rRec.bBelowRefEdge) rPol.nHlpAngle+=18000_deg100;
+ rPol.nHlpAngle=NormAngle36000(rPol.nHlpAngle);
+ double nHlpSin=nLineCos;
+ double nHlpCos=-nLineSin;
+ if (rRec.bBelowRefEdge) {
+ nHlpSin=-nHlpSin;
+ nHlpCos=-nHlpCos;
+ }
+
+ tools::Long nLineDist=rRec.nLineDist;
+ tools::Long nOverhang=rRec.nHelplineOverhang;
+ tools::Long nHelplineDist=rRec.nHelplineDist;
+
+ tools::Long dx= FRound(nLineDist*nHlpCos);
+ tools::Long dy=-FRound(nLineDist*nHlpSin);
+ tools::Long dxh1a= FRound((nHelplineDist-rRec.nHelpline1Len)*nHlpCos);
+ tools::Long dyh1a=-FRound((nHelplineDist-rRec.nHelpline1Len)*nHlpSin);
+ tools::Long dxh1b= FRound((nHelplineDist-rRec.nHelpline2Len)*nHlpCos);
+ tools::Long dyh1b=-FRound((nHelplineDist-rRec.nHelpline2Len)*nHlpSin);
+ tools::Long dxh2= FRound((nLineDist+nOverhang)*nHlpCos);
+ tools::Long dyh2=-FRound((nLineDist+nOverhang)*nHlpSin);
+
+ // extension line 1
+ rPol.aHelpline1.aP1=Point(aP1.X()+dxh1a,aP1.Y()+dyh1a);
+ rPol.aHelpline1.aP2=Point(aP1.X()+dxh2,aP1.Y()+dyh2);
+
+ // extension line 2
+ rPol.aHelpline2.aP1=Point(aP2.X()+dxh1b,aP2.Y()+dyh1b);
+ rPol.aHelpline2.aP2=Point(aP2.X()+dxh2,aP2.Y()+dyh2);
+
+ // dimension line
+ Point aMainlinePt1(aP1.X()+dx,aP1.Y()+dy);
+ Point aMainlinePt2(aP2.X()+dx,aP2.Y()+dy);
+ if (!bPfeileAussen) {
+ rPol.aMainline1.aP1=aMainlinePt1;
+ rPol.aMainline1.aP2=aMainlinePt2;
+ rPol.aMainline2=rPol.aMainline1;
+ rPol.aMainline3=rPol.aMainline1;
+ rPol.nMainlineCnt=1;
+ if (bBrkLine) {
+ tools::Long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
+ tools::Long nHalfLen=(rPol.nLineLen-nNeedSiz-nArrow1Wdt/4-nArrow2Wdt/4) /2;
+ rPol.nMainlineCnt=2;
+ rPol.aMainline1.aP2=aMainlinePt1;
+ rPol.aMainline1.aP2.AdjustX(nHalfLen );
+ RotatePoint(rPol.aMainline1.aP2,rPol.aMainline1.aP1,nLineSin,nLineCos);
+ rPol.aMainline2.aP1=aMainlinePt2;
+ rPol.aMainline2.aP1.AdjustX( -nHalfLen );
+ RotatePoint(rPol.aMainline2.aP1,rPol.aMainline2.aP2,nLineSin,nLineCos);
+ }
+ } else {
+ tools::Long nLen1=nShortLen; // arrowhead's width as line length outside of the arrowhead
+ tools::Long nLen2=nShortLen;
+ tools::Long nTextWdt=rRec.bTextRota90 ? rPol.aTextSize.Height() : rPol.aTextSize.Width();
+ if (!bBrkLine) {
+ if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) nLen1=nArrow1Len+nTextWdt;
+ if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) nLen2=nArrow2Len+nTextWdt;
+ }
+ rPol.aMainline1.aP1=aMainlinePt1;
+ rPol.aMainline1.aP2=aMainlinePt1; rPol.aMainline1.aP2.AdjustX( -nLen1 ); RotatePoint(rPol.aMainline1.aP2,aMainlinePt1,nLineSin,nLineCos);
+ rPol.aMainline2.aP1=aMainlinePt2; rPol.aMainline2.aP1.AdjustX(nLen2 ); RotatePoint(rPol.aMainline2.aP1,aMainlinePt2,nLineSin,nLineCos);
+ rPol.aMainline2.aP2=aMainlinePt2;
+ rPol.aMainline3.aP1=aMainlinePt1;
+ rPol.aMainline3.aP2=aMainlinePt2;
+ rPol.nMainlineCnt=3;
+ if (bBrkLine && rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_INSIDE) rPol.nMainlineCnt=2;
+ }
+}
+
+basegfx::B2DPolyPolygon SdrMeasureObj::ImpCalcXPoly(const ImpMeasurePoly& rPol)
+{
+ basegfx::B2DPolyPolygon aRetval;
+ basegfx::B2DPolygon aPartPolyA;
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP1.X(), rPol.aMainline1.aP1.Y()));
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP2.X(), rPol.aMainline1.aP2.Y()));
+ aRetval.append(aPartPolyA);
+
+ if(rPol.nMainlineCnt > 1)
+ {
+ aPartPolyA.clear();
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP1.X(), rPol.aMainline2.aP1.Y()));
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP2.X(), rPol.aMainline2.aP2.Y()));
+ aRetval.append(aPartPolyA);
+ }
+
+ if(rPol.nMainlineCnt > 2)
+ {
+ aPartPolyA.clear();
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP1.X(), rPol.aMainline3.aP1.Y()));
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP2.X(), rPol.aMainline3.aP2.Y()));
+ aRetval.append(aPartPolyA);
+ }
+
+ aPartPolyA.clear();
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP1.X(), rPol.aHelpline1.aP1.Y()));
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP2.X(), rPol.aHelpline1.aP2.Y()));
+ aRetval.append(aPartPolyA);
+
+ aPartPolyA.clear();
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP1.X(), rPol.aHelpline2.aP1.Y()));
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP2.X(), rPol.aHelpline2.aP2.Y()));
+ aRetval.append(aPartPolyA);
+
+ return aRetval;
+}
+
+bool SdrMeasureObj::CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_uInt16 nPos,
+ bool bEdit,
+ std::optional<Color>& rpTxtColor, std::optional<Color>& rpFldColor, OUString& rRet) const
+{
+ const SvxFieldData* pField=rField.GetField();
+ const SdrMeasureField* pMeasureField=dynamic_cast<const SdrMeasureField*>( pField );
+ if (pMeasureField!=nullptr) {
+ rRet = TakeRepresentation(pMeasureField->GetMeasureFieldKind());
+ if (rpFldColor && !bEdit)
+ {
+ rpFldColor.reset();
+ }
+ return true;
+ } else {
+ return SdrTextObj::CalcFieldValue(rField,nPara,nPos,bEdit,rpTxtColor,rpFldColor,rRet);
+ }
+}
+
+void SdrMeasureObj::UndirtyText() const
+{
+ if (!bTextDirty)
+ return;
+
+ SdrOutliner& rOutliner=ImpGetDrawOutliner();
+ OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
+ if(pOutlinerParaObject==nullptr)
+ {
+ rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Rotate90Blanks), EE_FEATURE_FIELD), ESelection(0,0));
+ rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Value), EE_FEATURE_FIELD),ESelection(0,1));
+ rOutliner.QuickInsertText(" ", ESelection(0,2));
+ rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Unit), EE_FEATURE_FIELD),ESelection(0,3));
+ rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Rotate90Blanks), EE_FEATURE_FIELD),ESelection(0,4));
+
+ if(GetStyleSheet())
+ rOutliner.SetStyleSheet(0, GetStyleSheet());
+
+ rOutliner.SetParaAttribs(0, GetObjectItemSet());
+
+ // cast to nonconst
+ const_cast<SdrMeasureObj*>(this)->NbcSetOutlinerParaObject( rOutliner.CreateParaObject() );
+ }
+ else
+ {
+ rOutliner.SetText(*pOutlinerParaObject);
+ }
+
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.UpdateFields();
+ Size aSiz(rOutliner.CalcTextSize());
+ rOutliner.Clear();
+ // cast to nonconst three times
+ const_cast<SdrMeasureObj*>(this)->maTextSize = aSiz;
+ const_cast<SdrMeasureObj*>(this)->mbTextSizeDirty = false;
+ const_cast<SdrMeasureObj*>(this)->bTextDirty = false;
+}
+
+void SdrMeasureObj::TakeUnrotatedSnapRect(tools::Rectangle& rRect) const
+{
+ if (bTextDirty) UndirtyText();
+ ImpMeasureRec aRec;
+ ImpMeasurePoly aMPol;
+ ImpTakeAttr(aRec);
+ ImpCalcGeometrics(aRec,aMPol);
+
+ // determine TextSize including text frame margins
+ Size aTextSize2(aMPol.aTextSize);
+ if (aTextSize2.Width()<1) aTextSize2.setWidth(1 );
+ if (aTextSize2.Height()<1) aTextSize2.setHeight(1 );
+ aTextSize2.AdjustWidth(GetTextLeftDistance()+GetTextRightDistance() );
+ aTextSize2.AdjustHeight(GetTextUpperDistance()+GetTextLowerDistance() );
+
+ Point aPt1b(aMPol.aMainline1.aP1);
+ tools::Long nLen=aMPol.nLineLen;
+ tools::Long nLWdt=aMPol.nLineWdt2;
+ tools::Long nArr1Len=aMPol.nArrow1Len;
+ tools::Long nArr2Len=aMPol.nArrow2Len;
+ if (aMPol.bBreakedLine) {
+ // In the case of a dashed line and Outside, the text should be
+ // placed next to the line at the arrowhead instead of directly
+ // at the arrowhead.
+ nArr1Len=aMPol.nShortLineLen+aMPol.nArrow1Wdt/4;
+ nArr2Len=aMPol.nShortLineLen+aMPol.nArrow2Wdt/4;
+ }
+
+ Point aTextPos;
+ bool bRota90=aRec.bTextRota90;
+ bool bUpsideDown=aRec.bTextUpsideDown!=aMPol.bAutoUpsideDown;
+ bool bBelowRefEdge=aRec.bBelowRefEdge;
+ css::drawing::MeasureTextHorzPos eMH=aMPol.eUsedTextHPos;
+ css::drawing::MeasureTextVertPos eMV=aMPol.eUsedTextVPos;
+ if (!bRota90) {
+ switch (eMH) {
+ case css::drawing::MeasureTextHorzPos_LEFTOUTSIDE: aTextPos.setX(aPt1b.X()-aTextSize2.Width()-nArr1Len-nLWdt ); break;
+ case css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE: aTextPos.setX(aPt1b.X()+nLen+nArr2Len+nLWdt ); break;
+ default: aTextPos.setX(aPt1b.X() ); aTextSize2.setWidth(nLen );
+ }
+ switch (eMV) {
+ case css::drawing::MeasureTextVertPos_CENTERED:
+ aTextPos.setY(aPt1b.Y()-aTextSize2.Height()/2 ); break;
+ case css::drawing::MeasureTextVertPos_WEST: {
+ if (!bUpsideDown) aTextPos.setY(aPt1b.Y()+nLWdt );
+ else aTextPos.setY(aPt1b.Y()-aTextSize2.Height()-nLWdt );
+ } break;
+ default: {
+ if (!bUpsideDown) aTextPos.setY(aPt1b.Y()-aTextSize2.Height()-nLWdt );
+ else aTextPos.setY(aPt1b.Y()+nLWdt );
+ }
+ }
+ if (bUpsideDown) {
+ aTextPos.AdjustX(aTextSize2.Width() );
+ aTextPos.AdjustY(aTextSize2.Height() );
+ }
+ } else { // also if bTextRota90==TRUE
+ switch (eMH) {
+ case css::drawing::MeasureTextHorzPos_LEFTOUTSIDE: aTextPos.setX(aPt1b.X()-aTextSize2.Height()-nArr1Len ); break;
+ case css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE: aTextPos.setX(aPt1b.X()+nLen+nArr2Len ); break;
+ default: aTextPos.setX(aPt1b.X() ); aTextSize2.setHeight(nLen );
+ }
+ switch (eMV) {
+ case css::drawing::MeasureTextVertPos_CENTERED:
+ aTextPos.setY(aPt1b.Y()+aTextSize2.Width()/2 ); break;
+ case css::drawing::MeasureTextVertPos_WEST: {
+ if (!bBelowRefEdge) aTextPos.setY(aPt1b.Y()+aTextSize2.Width()+nLWdt );
+ else aTextPos.setY(aPt1b.Y()-nLWdt );
+ } break;
+ default: {
+ if (!bBelowRefEdge) aTextPos.setY(aPt1b.Y()-nLWdt );
+ else aTextPos.setY(aPt1b.Y()+aTextSize2.Width()+nLWdt );
+ }
+ }
+ if (bUpsideDown) {
+ aTextPos.AdjustX(aTextSize2.Height() );
+ aTextPos.AdjustY( -(aTextSize2.Width()) );
+ }
+ }
+ if (aMPol.nTextAngle != maGeo.nRotationAngle) {
+ const_cast<SdrMeasureObj*>(this)->maGeo.nRotationAngle=aMPol.nTextAngle;
+ const_cast<SdrMeasureObj*>(this)->maGeo.RecalcSinCos();
+ }
+ RotatePoint(aTextPos,aPt1b,aMPol.nLineSin,aMPol.nLineCos);
+ aTextSize2.AdjustWidth( 1 ); aTextSize2.AdjustHeight( 1 ); // because of the Rect-Ctor's odd behavior
+ rRect=tools::Rectangle(aTextPos,aTextSize2);
+ rRect.Justify();
+ const_cast<SdrMeasureObj*>(this)->maRect=rRect;
+
+ if (aMPol.nTextAngle != maGeo.nRotationAngle) {
+ const_cast<SdrMeasureObj*>(this)->maGeo.nRotationAngle=aMPol.nTextAngle;
+ const_cast<SdrMeasureObj*>(this)->maGeo.RecalcSinCos();
+ }
+}
+
+SdrMeasureObj* SdrMeasureObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrMeasureObj(rTargetModel, *this);
+}
+
+OUString SdrMeasureObj::TakeObjNameSingul() const
+{
+ OUString sName(SvxResId(STR_ObjNameSingulMEASURE));
+
+ OUString aName( GetName() );
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+
+ return sName;
+}
+
+OUString SdrMeasureObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralMEASURE);
+}
+
+basegfx::B2DPolyPolygon SdrMeasureObj::TakeXorPoly() const
+{
+ ImpMeasureRec aRec;
+ ImpMeasurePoly aMPol;
+ ImpTakeAttr(aRec);
+ ImpCalcGeometrics(aRec,aMPol);
+ return ImpCalcXPoly(aMPol);
+}
+
+sal_uInt32 SdrMeasureObj::GetHdlCount() const
+{
+ return 6;
+}
+
+void SdrMeasureObj::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ ImpMeasureRec aRec;
+ ImpMeasurePoly aMPol;
+ ImpTakeAttr(aRec);
+ aRec.nHelplineDist=0;
+ ImpCalcGeometrics(aRec,aMPol);
+
+ for (sal_uInt32 nHdlNum=0; nHdlNum<6; ++nHdlNum)
+ {
+ Point aPt;
+ switch (nHdlNum) {
+ case 0: aPt=aMPol.aHelpline1.aP1; break;
+ case 1: aPt=aMPol.aHelpline2.aP1; break;
+ case 2: aPt=aPt1; break;
+ case 3: aPt=aPt2; break;
+ case 4: aPt=aMPol.aHelpline1.aP2; break;
+ case 5: aPt=aMPol.aHelpline2.aP2; break;
+ } // switch
+ std::unique_ptr<SdrHdl> pHdl(new ImpMeasureHdl(aPt,SdrHdlKind::User));
+ pHdl->SetObjHdlNum(nHdlNum);
+ pHdl->SetRotationAngle(aMPol.nLineAngle);
+ rHdlList.AddHdl(std::move(pHdl));
+ }
+}
+
+
+bool SdrMeasureObj::hasSpecialDrag() const
+{
+ return true;
+}
+
+bool SdrMeasureObj::beginSpecialDrag(SdrDragStat& rDrag) const
+{
+ const SdrHdl* pHdl = rDrag.GetHdl();
+
+ if(pHdl)
+ {
+ const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
+
+ if(nHdlNum != 2 && nHdlNum != 3)
+ {
+ rDrag.SetEndDragChangesAttributes(true);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool SdrMeasureObj::applySpecialDrag(SdrDragStat& rDrag)
+{
+ ImpMeasureRec aMeasureRec;
+ const SdrHdl* pHdl = rDrag.GetHdl();
+ const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
+
+ ImpTakeAttr(aMeasureRec);
+ ImpEvalDrag(aMeasureRec, rDrag);
+
+ switch (nHdlNum)
+ {
+ case 2:
+ {
+ aPt1 = aMeasureRec.aPt1;
+ SetTextDirty();
+ break;
+ }
+ case 3:
+ {
+ aPt2 = aMeasureRec.aPt2;
+ SetTextDirty();
+ break;
+ }
+ default:
+ {
+ switch(nHdlNum)
+ {
+ case 0:
+ case 1:
+ {
+ ImpMeasureRec aOrigMeasureRec;
+ ImpTakeAttr(aOrigMeasureRec);
+
+ if(aMeasureRec.nHelpline1Len != aOrigMeasureRec.nHelpline1Len)
+ {
+ SetObjectItem(makeSdrMeasureHelpline1LenItem(aMeasureRec.nHelpline1Len));
+ }
+
+ if(aMeasureRec.nHelpline2Len != aOrigMeasureRec.nHelpline2Len)
+ {
+ SetObjectItem(makeSdrMeasureHelpline2LenItem(aMeasureRec.nHelpline2Len));
+ }
+
+ break;
+ }
+
+ case 4:
+ case 5:
+ {
+ ImpMeasureRec aOrigMeasureRec;
+ ImpTakeAttr(aOrigMeasureRec);
+
+ if(aMeasureRec.nLineDist != aOrigMeasureRec.nLineDist)
+ {
+ SetObjectItem(makeSdrMeasureLineDistItem(aMeasureRec.nLineDist));
+ }
+
+ if(aMeasureRec.bBelowRefEdge != aOrigMeasureRec.bBelowRefEdge)
+ {
+ SetObjectItem(SdrMeasureBelowRefEdgeItem(aMeasureRec.bBelowRefEdge));
+ }
+ }
+ }
+ }
+ } // switch
+
+ SetBoundAndSnapRectsDirty();
+ SetChanged();
+
+ return true;
+}
+
+OUString SdrMeasureObj::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
+{
+ return OUString();
+}
+
+void SdrMeasureObj::ImpEvalDrag(ImpMeasureRec& rRec, const SdrDragStat& rDrag) const
+{
+ Degree100 nLineAngle=GetAngle(rRec.aPt2-rRec.aPt1);
+ double a = toRadians(nLineAngle);
+ double nSin=sin(a);
+ double nCos=cos(a);
+
+ const SdrHdl* pHdl=rDrag.GetHdl();
+ sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
+ bool bOrtho=rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho();
+ bool bBigOrtho=bOrtho && rDrag.GetView()->IsBigOrtho();
+ bool bBelow=rRec.bBelowRefEdge;
+ Point aPt(rDrag.GetNow());
+
+ switch (nHdlNum) {
+ case 0: {
+ RotatePoint(aPt,aPt1,nSin,-nCos);
+ rRec.nHelpline1Len=aPt1.Y()-aPt.Y();
+ if (bBelow) rRec.nHelpline1Len=-rRec.nHelpline1Len;
+ if (bOrtho) rRec.nHelpline2Len=rRec.nHelpline1Len;
+ } break;
+ case 1: {
+ RotatePoint(aPt,aPt2,nSin,-nCos);
+ rRec.nHelpline2Len=aPt2.Y()-aPt.Y();
+ if (bBelow) rRec.nHelpline2Len=-rRec.nHelpline2Len;
+ if (bOrtho) rRec.nHelpline1Len=rRec.nHelpline2Len;
+ } break;
+ case 2: case 3: {
+ bool bAnf=nHdlNum==2;
+ Point& rMov=bAnf ? rRec.aPt1 : rRec.aPt2;
+ Point aMov(rMov);
+ Point aFix(bAnf ? rRec.aPt2 : rRec.aPt1);
+ if (bOrtho) {
+ tools::Long ndx0=aMov.X()-aFix.X();
+ tools::Long ndy0=aMov.Y()-aFix.Y();
+ bool bHLin=ndy0==0;
+ bool bVLin=ndx0==0;
+ if (!bHLin || !bVLin) { // else aPt1==aPt2
+ tools::Long ndx=aPt.X()-aFix.X();
+ tools::Long ndy=aPt.Y()-aFix.Y();
+ double nXFact=0; if (!bVLin) nXFact=static_cast<double>(ndx)/static_cast<double>(ndx0);
+ double nYFact=0; if (!bHLin) nYFact=static_cast<double>(ndy)/static_cast<double>(ndy0);
+ bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
+ bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
+ if (bHor) ndy=tools::Long(ndy0*nXFact);
+ if (bVer) ndx=tools::Long(ndx0*nYFact);
+ aPt=aFix;
+ aPt.AdjustX(ndx );
+ aPt.AdjustY(ndy );
+ } // else Ortho8
+ }
+ rMov=aPt;
+ } break;
+ case 4: case 5: {
+ tools::Long nVal0=rRec.nLineDist;
+ RotatePoint(aPt,(nHdlNum==4 ? aPt1 : aPt2),nSin,-nCos);
+ rRec.nLineDist=aPt.Y()- (nHdlNum==4 ? aPt1.Y() : aPt2.Y());
+ if (bBelow) rRec.nLineDist=-rRec.nLineDist;
+ if (rRec.nLineDist<0) {
+ rRec.nLineDist=-rRec.nLineDist;
+ rRec.bBelowRefEdge=!bBelow;
+ }
+ rRec.nLineDist-=rRec.nHelplineOverhang;
+ if (bOrtho) rRec.nLineDist=nVal0;
+ } break;
+ } // switch
+}
+
+
+bool SdrMeasureObj::BegCreate(SdrDragStat& rStat)
+{
+ rStat.SetOrtho8Possible();
+ aPt1=rStat.GetStart();
+ aPt2=rStat.GetNow();
+ SetTextDirty();
+ return true;
+}
+
+bool SdrMeasureObj::MovCreate(SdrDragStat& rStat)
+{
+ SdrView* pView=rStat.GetView();
+ aPt1=rStat.GetStart();
+ aPt2=rStat.GetNow();
+ if (pView!=nullptr && pView->IsCreate1stPointAsCenter()) {
+ aPt1+=aPt1;
+ aPt1-=rStat.GetNow();
+ }
+ SetTextDirty();
+ SetBoundRectDirty();
+ m_bSnapRectDirty=true;
+ return true;
+}
+
+bool SdrMeasureObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ SetTextDirty();
+ SetBoundAndSnapRectsDirty();
+ return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
+}
+
+bool SdrMeasureObj::BckCreate(SdrDragStat& /*rStat*/)
+{
+ return false;
+}
+
+void SdrMeasureObj::BrkCreate(SdrDragStat& /*rStat*/)
+{
+}
+
+basegfx::B2DPolyPolygon SdrMeasureObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
+{
+ ImpMeasureRec aRec;
+ ImpMeasurePoly aMPol;
+
+ ImpTakeAttr(aRec);
+ ImpCalcGeometrics(aRec, aMPol);
+
+ return ImpCalcXPoly(aMPol);
+}
+
+PointerStyle SdrMeasureObj::GetCreatePointer() const
+{
+ return PointerStyle::Cross;
+}
+
+void SdrMeasureObj::NbcMove(const Size& rSiz)
+{
+ SdrTextObj::NbcMove(rSiz);
+ aPt1.Move(rSiz);
+ aPt2.Move(rSiz);
+}
+
+void SdrMeasureObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ SdrTextObj::NbcResize(rRef,xFact,yFact);
+ ResizePoint(aPt1,rRef,xFact,yFact);
+ ResizePoint(aPt2,rRef,xFact,yFact);
+ SetTextDirty();
+}
+
+void SdrMeasureObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ SdrTextObj::NbcRotate(rRef,nAngle,sn,cs);
+ tools::Long nLen0=GetLen(aPt2-aPt1);
+ RotatePoint(aPt1,rRef,sn,cs);
+ RotatePoint(aPt2,rRef,sn,cs);
+ tools::Long nLen1=GetLen(aPt2-aPt1);
+ if (nLen1!=nLen0) { // rounding error!
+ tools::Long dx=aPt2.X()-aPt1.X();
+ tools::Long dy=aPt2.Y()-aPt1.Y();
+ dx=BigMulDiv(dx,nLen0,nLen1);
+ dy=BigMulDiv(dy,nLen0,nLen1);
+ if (rRef==aPt2) {
+ aPt1.setX(aPt2.X()-dx );
+ aPt1.setY(aPt2.Y()-dy );
+ } else {
+ aPt2.setX(aPt1.X()+dx );
+ aPt2.setY(aPt1.Y()+dy );
+ }
+ }
+ SetBoundAndSnapRectsDirty();
+}
+
+void SdrMeasureObj::NbcMirror(const Point& rRef1, const Point& rRef2)
+{
+ SdrTextObj::NbcMirror(rRef1,rRef2);
+ MirrorPoint(aPt1,rRef1,rRef2);
+ MirrorPoint(aPt2,rRef1,rRef2);
+ SetBoundAndSnapRectsDirty();
+}
+
+void SdrMeasureObj::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
+{
+ SdrTextObj::NbcShear(rRef,nAngle,tn,bVShear);
+ ShearPoint(aPt1,rRef,tn,bVShear);
+ ShearPoint(aPt2,rRef,tn,bVShear);
+ SetBoundAndSnapRectsDirty();
+ SetTextDirty();
+}
+
+Degree100 SdrMeasureObj::GetRotateAngle() const
+{
+ return GetAngle(aPt2-aPt1);
+}
+
+void SdrMeasureObj::RecalcSnapRect()
+{
+ ImpMeasureRec aRec;
+ ImpMeasurePoly aMPol;
+ XPolyPolygon aXPP;
+
+ ImpTakeAttr(aRec);
+ ImpCalcGeometrics(aRec, aMPol);
+ aXPP = XPolyPolygon(ImpCalcXPoly(aMPol));
+ maSnapRect = aXPP.GetBoundRect();
+}
+
+sal_uInt32 SdrMeasureObj::GetSnapPointCount() const
+{
+ return 2;
+}
+
+Point SdrMeasureObj::GetSnapPoint(sal_uInt32 i) const
+{
+ if (i==0) return aPt1;
+ else return aPt2;
+}
+
+bool SdrMeasureObj::IsPolyObj() const
+{
+ return true;
+}
+
+sal_uInt32 SdrMeasureObj::GetPointCount() const
+{
+ return 2;
+}
+
+Point SdrMeasureObj::GetPoint(sal_uInt32 i) const
+{
+ return (0 == i) ? aPt1 : aPt2;
+}
+
+void SdrMeasureObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
+{
+ if (0 == i)
+ aPt1=rPnt;
+ if (1 == i)
+ aPt2=rPnt;
+ SetBoundAndSnapRectsDirty();
+ SetTextDirty();
+}
+
+std::unique_ptr<SdrObjGeoData> SdrMeasureObj::NewGeoData() const
+{
+ return std::make_unique<SdrMeasureObjGeoData>();
+}
+
+void SdrMeasureObj::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ SdrTextObj::SaveGeoData(rGeo);
+ SdrMeasureObjGeoData& rMGeo=static_cast<SdrMeasureObjGeoData&>(rGeo);
+ rMGeo.aPt1=aPt1;
+ rMGeo.aPt2=aPt2;
+}
+
+void SdrMeasureObj::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ SdrTextObj::RestoreGeoData(rGeo);
+ const SdrMeasureObjGeoData& rMGeo=static_cast<const SdrMeasureObjGeoData&>(rGeo);
+ aPt1=rMGeo.aPt1;
+ aPt2=rMGeo.aPt2;
+ SetTextDirty();
+}
+
+SdrObjectUniquePtr SdrMeasureObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
+{
+ // get XOR Poly as base
+ XPolyPolygon aTmpPolyPolygon(TakeXorPoly());
+
+ // get local ItemSet and StyleSheet
+ SfxItemSet aSet(GetObjectItemSet());
+ SfxStyleSheet* pStyleSheet = GetStyleSheet();
+
+ // prepare group
+ std::unique_ptr<SdrObjGroup,SdrObjectFreeOp> pGroup(new SdrObjGroup(getSdrModelFromSdrObject()));
+
+ // prepare parameters
+ basegfx::B2DPolyPolygon aPolyPoly;
+ SdrPathObj* pPath;
+ sal_uInt16 nCount(aTmpPolyPolygon.Count());
+ sal_uInt16 nLoopStart(0);
+
+ if(nCount == 3)
+ {
+ // three lines, first one is the middle one
+ aPolyPoly.clear();
+ aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
+
+ pPath = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathLine,
+ aPolyPoly);
+
+ pPath->SetMergedItemSet(aSet);
+ pPath->SetStyleSheet(pStyleSheet, true);
+ pGroup->GetSubList()->NbcInsertObject(pPath);
+ aSet.Put(XLineStartWidthItem(0));
+ aSet.Put(XLineEndWidthItem(0));
+ nLoopStart = 1;
+ }
+ else if(nCount == 4)
+ {
+ // four lines, middle line with gap, so there are two lines used
+ // which have one arrow each
+ sal_Int32 nEndWidth = aSet.Get(XATTR_LINEENDWIDTH).GetValue();
+ aSet.Put(XLineEndWidthItem(0));
+
+ aPolyPoly.clear();
+ aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
+ pPath = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathLine,
+ aPolyPoly);
+
+ pPath->SetMergedItemSet(aSet);
+ pPath->SetStyleSheet(pStyleSheet, true);
+
+ pGroup->GetSubList()->NbcInsertObject(pPath);
+
+ aSet.Put(XLineEndWidthItem(nEndWidth));
+ aSet.Put(XLineStartWidthItem(0));
+
+ aPolyPoly.clear();
+ aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
+ pPath = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathLine,
+ aPolyPoly);
+
+ pPath->SetMergedItemSet(aSet);
+ pPath->SetStyleSheet(pStyleSheet, true);
+
+ pGroup->GetSubList()->NbcInsertObject(pPath);
+
+ aSet.Put(XLineEndWidthItem(0));
+ nLoopStart = 2;
+ }
+ else if(nCount == 5)
+ {
+ // five lines, first two are the outer ones
+ sal_Int32 nEndWidth = aSet.Get(XATTR_LINEENDWIDTH).GetValue();
+
+ aSet.Put(XLineEndWidthItem(0));
+
+ aPolyPoly.clear();
+ aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
+ pPath = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathLine,
+ aPolyPoly);
+
+ pPath->SetMergedItemSet(aSet);
+ pPath->SetStyleSheet(pStyleSheet, true);
+
+ pGroup->GetSubList()->NbcInsertObject(pPath);
+
+ aSet.Put(XLineEndWidthItem(nEndWidth));
+ aSet.Put(XLineStartWidthItem(0));
+
+ aPolyPoly.clear();
+ aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
+ pPath = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathLine,
+ aPolyPoly);
+
+ pPath->SetMergedItemSet(aSet);
+ pPath->SetStyleSheet(pStyleSheet, true);
+
+ pGroup->GetSubList()->NbcInsertObject(pPath);
+
+ aSet.Put(XLineEndWidthItem(0));
+ nLoopStart = 2;
+ }
+
+ for(;nLoopStart<nCount;nLoopStart++)
+ {
+ aPolyPoly.clear();
+ aPolyPoly.append(aTmpPolyPolygon[nLoopStart].getB2DPolygon());
+ pPath = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathLine,
+ aPolyPoly);
+
+ pPath->SetMergedItemSet(aSet);
+ pPath->SetStyleSheet(pStyleSheet, true);
+
+ pGroup->GetSubList()->NbcInsertObject(pPath);
+ }
+
+ if(bAddText)
+ {
+ return ImpConvertAddText(std::move(pGroup), bBezier);
+ }
+ else
+ {
+ return pGroup;
+ }
+}
+
+bool SdrMeasureObj::BegTextEdit(SdrOutliner& rOutl)
+{
+ UndirtyText();
+ return SdrTextObj::BegTextEdit(rOutl);
+}
+
+const Size& SdrMeasureObj::GetTextSize() const
+{
+ if (bTextDirty) UndirtyText();
+ return SdrTextObj::GetTextSize();
+}
+
+OutlinerParaObject* SdrMeasureObj::GetOutlinerParaObject() const
+{
+ if(bTextDirty)
+ UndirtyText();
+ return SdrTextObj::GetOutlinerParaObject();
+}
+
+void SdrMeasureObj::NbcSetOutlinerParaObject(std::optional<OutlinerParaObject> pTextObject)
+{
+ SdrTextObj::NbcSetOutlinerParaObject(std::move(pTextObject));
+ if(SdrTextObj::GetOutlinerParaObject())
+ SetTextDirty(); // recalculate text
+}
+
+void SdrMeasureObj::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText,
+ tools::Rectangle* pAnchorRect, bool bLineWidth ) const
+{
+ if (bTextDirty) UndirtyText();
+ SdrTextObj::TakeTextRect( rOutliner, rTextRect, bNoEditText, pAnchorRect, bLineWidth );
+}
+
+void SdrMeasureObj::TakeTextAnchorRect(tools::Rectangle& rAnchorRect) const
+{
+ if (bTextDirty) UndirtyText();
+ SdrTextObj::TakeTextAnchorRect(rAnchorRect);
+}
+
+void SdrMeasureObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin) const
+{
+ if (bTextDirty) UndirtyText();
+ SdrTextObj::TakeTextEditArea(pPaperMin,pPaperMax,pViewInit,pViewMin);
+}
+
+EEAnchorMode SdrMeasureObj::GetOutlinerViewAnchorMode() const
+{
+ if (bTextDirty) UndirtyText();
+ ImpMeasureRec aRec;
+ ImpMeasurePoly aMPol;
+ ImpTakeAttr(aRec);
+ ImpCalcGeometrics(aRec,aMPol);
+
+ SdrTextHorzAdjust eTH=GetTextHorizontalAdjust();
+ SdrTextVertAdjust eTV=GetTextVerticalAdjust();
+ css::drawing::MeasureTextHorzPos eMH = aMPol.eUsedTextHPos;
+ css::drawing::MeasureTextVertPos eMV = aMPol.eUsedTextVPos;
+ bool bTextRota90=aRec.bTextRota90;
+ bool bBelowRefEdge=aRec.bBelowRefEdge;
+
+ // TODO: bTextUpsideDown should be interpreted here!
+ if (!bTextRota90) {
+ if (eMH==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) eTH=SDRTEXTHORZADJUST_RIGHT;
+ if (eMH==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) eTH=SDRTEXTHORZADJUST_LEFT;
+ // at eMH==css::drawing::MeasureTextHorzPos_INSIDE we can anchor horizontally
+ if (eMV==css::drawing::MeasureTextVertPos_EAST) eTV=SDRTEXTVERTADJUST_BOTTOM;
+ if (eMV==css::drawing::MeasureTextVertPos_WEST) eTV=SDRTEXTVERTADJUST_TOP;
+ if (eMV==css::drawing::MeasureTextVertPos_CENTERED) eTV=SDRTEXTVERTADJUST_CENTER;
+ } else {
+ if (eMH==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) eTV=SDRTEXTVERTADJUST_BOTTOM;
+ if (eMH==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) eTV=SDRTEXTVERTADJUST_TOP;
+ // at eMH==css::drawing::MeasureTextHorzPos_INSIDE we can anchor vertically
+ if (!bBelowRefEdge) {
+ if (eMV==css::drawing::MeasureTextVertPos_EAST) eTH=SDRTEXTHORZADJUST_LEFT;
+ if (eMV==css::drawing::MeasureTextVertPos_WEST) eTH=SDRTEXTHORZADJUST_RIGHT;
+ } else {
+ if (eMV==css::drawing::MeasureTextVertPos_EAST) eTH=SDRTEXTHORZADJUST_RIGHT;
+ if (eMV==css::drawing::MeasureTextVertPos_WEST) eTH=SDRTEXTHORZADJUST_LEFT;
+ }
+ if (eMV==css::drawing::MeasureTextVertPos_CENTERED) eTH=SDRTEXTHORZADJUST_CENTER;
+ }
+
+ EEAnchorMode eRet=EEAnchorMode::BottomHCenter;
+ if (eTH==SDRTEXTHORZADJUST_LEFT) {
+ if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopLeft;
+ else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomLeft;
+ else eRet=EEAnchorMode::VCenterLeft;
+ } else if (eTH==SDRTEXTHORZADJUST_RIGHT) {
+ if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopRight;
+ else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomRight;
+ else eRet=EEAnchorMode::VCenterRight;
+ } else {
+ if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopHCenter;
+ else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomHCenter;
+ else eRet=EEAnchorMode::VCenterHCenter;
+ }
+ return eRet;
+}
+
+
+// #i97878#
+// TRGetBaseGeometry/TRSetBaseGeometry needs to be based on two positions,
+// same as line geometry in SdrPathObj. Thus needs to be overridden and
+// implemented since currently it is derived from SdrTextObj which uses
+// a functionality based on SnapRect which is not useful here
+
+bool SdrMeasureObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
+{
+ // handle the same as a simple line since the definition is based on two points
+ const basegfx::B2DRange aRange(aPt1.X(), aPt1.Y(), aPt2.X(), aPt2.Y());
+ basegfx::B2DTuple aScale(aRange.getRange());
+ basegfx::B2DTuple aTranslate(aRange.getMinimum());
+
+ // position maybe relative to anchor position, convert
+ if( getSdrModelFromSdrObject().IsWriter() )
+ {
+ if(GetAnchorPos().X() || GetAnchorPos().Y())
+ {
+ aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
+ }
+ }
+
+ // build return value matrix
+ rMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(aScale, aTranslate);
+
+ return true;
+}
+
+void SdrMeasureObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
+{
+ // use given transformation to derive the two defining points from unit line
+ basegfx::B2DPoint aPosA(rMatrix * basegfx::B2DPoint(0.0, 0.0));
+ basegfx::B2DPoint aPosB(rMatrix * basegfx::B2DPoint(1.0, 0.0));
+
+ if( getSdrModelFromSdrObject().IsWriter() )
+ {
+ // if anchor is used, make position relative to it
+ if(GetAnchorPos().X() || GetAnchorPos().Y())
+ {
+ const basegfx::B2DVector aAnchorOffset(GetAnchorPos().X(), GetAnchorPos().Y());
+
+ aPosA += aAnchorOffset;
+ aPosB += aAnchorOffset;
+ }
+ }
+
+ // derive new model data
+ const Point aNewPt1(basegfx::fround(aPosA.getX()), basegfx::fround(aPosA.getY()));
+ const Point aNewPt2(basegfx::fround(aPosB.getX()), basegfx::fround(aPosB.getY()));
+
+ if(aNewPt1 == aPt1 && aNewPt2 == aPt2)
+ return;
+
+ // set model values and broadcast
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+
+ aPt1 = aNewPt1;
+ aPt2 = aNewPt2;
+
+ SetTextDirty();
+ ActionChanged();
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */