bump product version to 5.0.4.1
[LibreOffice.git] / svx / source / svdraw / svdomeas.cxx
blob5479193a019999de41320fb5ceb43f02a10741ea
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 "svdconv.hxx"
21 #include "svdglob.hxx"
22 #include "svx/svdstr.hrc"
24 #include <basegfx/matrix/b2dhommatrix.hxx>
25 #include <basegfx/matrix/b2dhommatrixtools.hxx>
26 #include <basegfx/point/b2dpoint.hxx>
27 #include <basegfx/polygon/b2dpolygon.hxx>
28 #include <basegfx/polygon/b2dpolypolygon.hxx>
29 #include <editeng/editdata.hxx>
30 #include <editeng/editobj.hxx>
31 #include <editeng/eeitem.hxx>
32 #include <editeng/flditem.hxx>
33 #include <editeng/measfld.hxx>
34 #include <editeng/outliner.hxx>
35 #include <editeng/outlobj.hxx>
36 #include <math.h>
37 #include <svl/smplhint.hxx>
38 #include <svl/style.hxx>
40 #include <sdr/contact/viewcontactofsdrmeasureobj.hxx>
41 #include <sdr/properties/measureproperties.hxx>
42 #include <svx/svddrag.hxx>
43 #include <svx/svdhdl.hxx>
44 #include <svx/svdmodel.hxx>
45 #include <svx/svdogrp.hxx>
46 #include <svx/svdomeas.hxx>
47 #include <svx/svdopath.hxx>
48 #include <svx/svdoutl.hxx>
49 #include <svx/svdpage.hxx>
50 #include <svx/svdpool.hxx>
51 #include <svx/svdtrans.hxx>
52 #include <svx/svdview.hxx>
53 #include <svx/sxmbritm.hxx>
54 #include <svx/sxmfsitm.hxx>
55 #include <sxmkitm.hxx>
56 #include <svx/sxmlhitm.hxx>
57 #include <sxmoitm.hxx>
58 #include <sxmsitm.hxx>
59 #include <svx/sxmsuitm.hxx>
60 #include <sxmtaitm.hxx>
61 #include <svx/sxmtfitm.hxx>
62 #include <svx/sxmtpitm.hxx>
63 #include <svx/sxmtritm.hxx>
64 #include <svx/sxmuitm.hxx>
65 #include <svx/xlnedcit.hxx>
66 #include <svx/xlnedit.hxx>
67 #include <svx/xlnedwit.hxx>
68 #include <svx/xlnstcit.hxx>
69 #include <svx/xlnstit.hxx>
70 #include <svx/xlnstwit.hxx>
71 #include <svx/xlnwtit.hxx>
72 #include <svx/xpoly.hxx>
73 #include <unotools/syslocale.hxx>
77 SdrMeasureObjGeoData::SdrMeasureObjGeoData() {}
78 SdrMeasureObjGeoData::~SdrMeasureObjGeoData() {}
80 OUString SdrMeasureObj::TakeRepresentation(SdrMeasureFieldKind eMeasureFieldKind) const
82 OUString aStr;
83 Fraction aMeasureScale(1, 1);
84 bool bTextRota90(false);
85 bool bShowUnit(false);
86 FieldUnit eMeasureUnit(FUNIT_NONE);
87 FieldUnit eModUIUnit(FUNIT_NONE);
89 const SfxItemSet& rSet = GetMergedItemSet();
90 bTextRota90 = static_cast<const SdrMeasureTextRota90Item&>(rSet.Get(SDRATTR_MEASURETEXTROTA90)).GetValue();
91 eMeasureUnit = static_cast<const SdrMeasureUnitItem&>(rSet.Get(SDRATTR_MEASUREUNIT)).GetValue();
92 aMeasureScale = static_cast<const SdrMeasureScaleItem&>(rSet.Get(SDRATTR_MEASURESCALE)).GetValue();
93 bShowUnit = static_cast<const SdrYesNoItem&>(rSet.Get(SDRATTR_MEASURESHOWUNIT)).GetValue();
94 sal_Int16 nNumDigits = static_cast<const SdrMeasureDecimalPlacesItem&>(rSet.Get(SDRATTR_MEASUREDECIMALPLACES)).GetValue();
96 switch(eMeasureFieldKind)
98 case SDRMEASUREFIELD_VALUE:
100 if(pModel)
102 eModUIUnit = pModel->GetUIUnit();
104 if(eMeasureUnit == FUNIT_NONE)
105 eMeasureUnit = eModUIUnit;
107 sal_Int32 nLen(GetLen(aPt2 - aPt1));
108 Fraction aFact(1,1);
110 if(eMeasureUnit != eModUIUnit)
112 // for the unit conversion
113 aFact *= GetMapFactor(eModUIUnit, eMeasureUnit).X();
116 if(aMeasureScale.GetNumerator() != aMeasureScale.GetDenominator())
118 aFact *= aMeasureScale;
121 if(aFact.GetNumerator() != aFact.GetDenominator())
123 // scale via BigInt, to avoid overruns
124 nLen = BigMulDiv(nLen, aFact.GetNumerator(), aFact.GetDenominator());
127 OUString aTmp;
128 pModel->TakeMetricStr(nLen, aTmp, true, nNumDigits);
129 aStr = aTmp;
131 if(!aFact.IsValid())
133 aStr = "?";
136 sal_Unicode cDec(SvtSysLocale().GetLocaleData().getNumDecimalSep()[0]);
138 if(aStr.indexOf(cDec) != -1)
140 sal_Int32 nLen2(aStr.getLength() - 1);
142 while(aStr[nLen2] == '0')
144 aStr = aStr.copy(0, nLen2);
145 nLen2--;
148 if(aStr[nLen2] == cDec)
150 aStr = aStr.copy(0, nLen2);
151 nLen2--;
154 if(aStr.isEmpty())
155 aStr += "0";
158 else
160 // if there's no Model ... (e. g. preview in dialog)
161 aStr = "4711";
164 break;
166 case SDRMEASUREFIELD_UNIT:
168 if(bShowUnit)
170 if(pModel)
172 eModUIUnit = pModel->GetUIUnit();
174 if(eMeasureUnit == FUNIT_NONE)
175 eMeasureUnit = eModUIUnit;
177 if(bShowUnit)
178 SdrModel::TakeUnitStr(eMeasureUnit, aStr);
182 break;
184 case SDRMEASUREFIELD_ROTA90BLANCS:
186 if(bTextRota90)
188 aStr = " ";
191 break;
194 return aStr;
198 // BaseProperties section
200 sdr::properties::BaseProperties* SdrMeasureObj::CreateObjectSpecificProperties()
202 return new sdr::properties::MeasureProperties(*this);
206 // DrawContact section
208 sdr::contact::ViewContact* SdrMeasureObj::CreateObjectSpecificViewContact()
210 return new sdr::contact::ViewContactOfSdrMeasureObj(*this);
215 TYPEINIT1(SdrMeasureObj,SdrTextObj);
217 SdrMeasureObj::SdrMeasureObj():
218 bTextDirty(false)
220 // #i25616#
221 mbSupportTextIndentingOnLineWidthChange = false;
224 SdrMeasureObj::SdrMeasureObj(const Point& rPt1, const Point& rPt2):
225 aPt1(rPt1),
226 aPt2(rPt2),
227 bTextDirty(false)
229 // #i25616#
230 mbSupportTextIndentingOnLineWidthChange = false;
233 SdrMeasureObj::~SdrMeasureObj()
237 void SdrMeasureObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
239 rInfo.bSelectAllowed =true;
240 rInfo.bMoveAllowed =true;
241 rInfo.bResizeFreeAllowed=true;
242 rInfo.bResizePropAllowed=true;
243 rInfo.bRotateFreeAllowed=true;
244 rInfo.bRotate90Allowed =true;
245 rInfo.bMirrorFreeAllowed=true;
246 rInfo.bMirror45Allowed =true;
247 rInfo.bMirror90Allowed =true;
248 rInfo.bTransparenceAllowed = false;
249 rInfo.bGradientAllowed = false;
250 rInfo.bShearAllowed =true;
251 rInfo.bEdgeRadiusAllowed=false;
252 rInfo.bNoOrthoDesired =true;
253 rInfo.bNoContortion =false;
254 rInfo.bCanConvToPath =false;
255 rInfo.bCanConvToPoly =true;
256 rInfo.bCanConvToPathLineToArea=false;
257 rInfo.bCanConvToPolyLineToArea=false;
258 rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
261 sal_uInt16 SdrMeasureObj::GetObjIdentifier() const
263 return (sal_uInt16)OBJ_MEASURE;
266 struct ImpMeasureRec : public SdrDragStatUserData
268 Point aPt1;
269 Point aPt2;
270 SdrMeasureKind eKind;
271 SdrMeasureTextHPos eWantTextHPos;
272 SdrMeasureTextVPos eWantTextVPos;
273 long nLineDist;
274 long nHelplineOverhang;
275 long nHelplineDist;
276 long nHelpline1Len;
277 long nHelpline2Len;
278 bool bBelowRefEdge;
279 bool bTextRota90;
280 bool bTextUpsideDown;
281 long nMeasureOverhang;
282 FieldUnit eMeasureUnit;
283 Fraction aMeasureScale;
284 bool bShowUnit;
285 OUString aFormatString;
286 bool bTextAutoAngle;
287 long nTextAutoAngleView;
288 bool bTextIsFixedAngle;
289 long nTextFixedAngle;
292 struct ImpLineRec
294 Point aP1;
295 Point aP2;
298 struct ImpMeasurePoly
300 ImpLineRec aMainline1; // those with the 1st arrowhead
301 ImpLineRec aMainline2; // those with the 2nd arrowhead
302 ImpLineRec aMainline3; // those in between
303 ImpLineRec aHelpline1;
304 ImpLineRec aHelpline2;
305 Rectangle aTextRect;
306 Size aTextSize;
307 long nLineLen;
308 long nLineAngle;
309 long nTextAngle;
310 long nHlpAngle;
311 double nLineSin;
312 double nLineCos;
313 double nHlpSin;
314 double nHlpCos;
315 sal_uInt16 nMainlineAnz;
316 SdrMeasureTextHPos eUsedTextHPos;
317 SdrMeasureTextVPos eUsedTextVPos;
318 long nLineWdt2; // half the line width
319 long nArrow1Len; // length of 1st arrowhead; for Center, use only half
320 long nArrow2Len; // length of 2nd arrowhead; for Center, use only half
321 long nArrow1Wdt; // width of 1st arrow
322 long nArrow2Wdt; // width of 2nd arrow
323 long nShortLineLen; // line length, if PfeileAussen (arrowheads on the outside)
324 bool bArrow1Center; // arrowhead 1 centered?
325 bool bArrow2Center; // arrowhead 2 centered?
326 bool bAutoUpsideDown; // UpsideDown via automation
327 bool bPfeileAussen; // arrowheads on the outside
328 bool bBreakedLine;
331 void SdrMeasureObj::ImpTakeAttr(ImpMeasureRec& rRec) const
333 rRec.aPt1 = aPt1;
334 rRec.aPt2 = aPt2;
336 const SfxItemSet& rSet = GetObjectItemSet();
337 rRec.eKind =static_cast<const SdrMeasureKindItem& >(rSet.Get(SDRATTR_MEASUREKIND )).GetValue();
338 rRec.eWantTextHPos =static_cast<const SdrMeasureTextHPosItem& >(rSet.Get(SDRATTR_MEASURETEXTHPOS )).GetValue();
339 rRec.eWantTextVPos =static_cast<const SdrMeasureTextVPosItem& >(rSet.Get(SDRATTR_MEASURETEXTVPOS )).GetValue();
340 rRec.nLineDist =static_cast<const SdrMetricItem& >(rSet.Get(SDRATTR_MEASURELINEDIST )).GetValue();
341 rRec.nHelplineOverhang =static_cast<const SdrMetricItem& >(rSet.Get(SDRATTR_MEASUREHELPLINEOVERHANG)).GetValue();
342 rRec.nHelplineDist =static_cast<const SdrMetricItem& >(rSet.Get(SDRATTR_MEASUREHELPLINEDIST )).GetValue();
343 rRec.nHelpline1Len =static_cast<const SdrMetricItem& >(rSet.Get(SDRATTR_MEASUREHELPLINE1LEN )).GetValue();
344 rRec.nHelpline2Len =static_cast<const SdrMetricItem& >(rSet.Get(SDRATTR_MEASUREHELPLINE2LEN )).GetValue();
345 rRec.bBelowRefEdge =static_cast<const SdrMeasureBelowRefEdgeItem& >(rSet.Get(SDRATTR_MEASUREBELOWREFEDGE )).GetValue();
346 rRec.bTextRota90 =static_cast<const SdrMeasureTextRota90Item& >(rSet.Get(SDRATTR_MEASURETEXTROTA90 )).GetValue();
347 rRec.bTextUpsideDown =static_cast<const SdrMeasureTextUpsideDownItem& >(rSet.Get(SDRATTR_MEASURETEXTUPSIDEDOWN )).GetValue();
348 rRec.nMeasureOverhang =static_cast<const SdrMeasureOverhangItem& >(rSet.Get(SDRATTR_MEASUREOVERHANG )).GetValue();
349 rRec.eMeasureUnit =static_cast<const SdrMeasureUnitItem& >(rSet.Get(SDRATTR_MEASUREUNIT )).GetValue();
350 rRec.aMeasureScale =static_cast<const SdrMeasureScaleItem& >(rSet.Get(SDRATTR_MEASURESCALE )).GetValue();
351 rRec.bShowUnit =static_cast<const SdrYesNoItem& >(rSet.Get(SDRATTR_MEASURESHOWUNIT )).GetValue();
352 rRec.aFormatString =static_cast<const SdrMeasureFormatStringItem& >(rSet.Get(SDRATTR_MEASUREFORMATSTRING )).GetValue();
353 rRec.bTextAutoAngle =static_cast<const SdrMeasureTextAutoAngleItem& >(rSet.Get(SDRATTR_MEASURETEXTAUTOANGLE )).GetValue();
354 rRec.nTextAutoAngleView=static_cast<const SdrMeasureTextAutoAngleViewItem&>(rSet.Get(SDRATTR_MEASURETEXTAUTOANGLEVIEW)).GetValue();
355 rRec.bTextIsFixedAngle =static_cast<const SdrMeasureTextIsFixedAngleItem& >(rSet.Get(SDRATTR_MEASURETEXTISFIXEDANGLE )).GetValue();
356 rRec.nTextFixedAngle =static_cast<const SdrMeasureTextFixedAngleItem& >(rSet.Get(SDRATTR_MEASURETEXTFIXEDANGLE )).GetValue();
359 long impGetLineStartEndDistance(const basegfx::B2DPolyPolygon& rPolyPolygon, long nNewWidth, bool bCenter)
361 const basegfx::B2DRange aPolygonRange(rPolyPolygon.getB2DRange());
362 const double fOldWidth(aPolygonRange.getWidth() > 1.0 ? aPolygonRange.getWidth() : 1.0);
363 const double fScale((double)nNewWidth / fOldWidth);
364 long nHeight(basegfx::fround(aPolygonRange.getHeight() * fScale));
366 if(bCenter)
368 nHeight /= 2L;
371 return nHeight;
374 void SdrMeasureObj::ImpCalcGeometrics(const ImpMeasureRec& rRec, ImpMeasurePoly& rPol) const
376 Point aP1(rRec.aPt1);
377 Point aP2(rRec.aPt2);
378 Point aDelt(aP2); aDelt-=aP1;
380 rPol.aTextSize=GetTextSize();
381 rPol.nLineLen=GetLen(aDelt);
383 rPol.nLineWdt2=0;
384 long nArrow1Len=0; bool bArrow1Center=false;
385 long nArrow2Len=0; bool bArrow2Center=false;
386 long nArrow1Wdt=0;
387 long nArrow2Wdt=0;
388 rPol.nArrow1Wdt=0;
389 rPol.nArrow2Wdt=0;
390 long nArrowNeed=0;
391 long nShortLen=0;
392 bool bPfeileAussen = false;
394 const SfxItemSet& rSet = GetObjectItemSet();
395 sal_Int32 nLineWdt = static_cast<const XLineWidthItem&>(rSet.Get(XATTR_LINEWIDTH)).GetValue(); // line width
396 rPol.nLineWdt2 = (nLineWdt + 1) / 2;
398 nArrow1Wdt = static_cast<const XLineStartWidthItem&>(rSet.Get(XATTR_LINESTARTWIDTH)).GetValue();
399 if(nArrow1Wdt < 0)
400 nArrow1Wdt = -nLineWdt * nArrow1Wdt / 100; // <0 = relativ
402 nArrow2Wdt = static_cast<const XLineEndWidthItem&>(rSet.Get(XATTR_LINEENDWIDTH)).GetValue();
403 if(nArrow2Wdt < 0)
404 nArrow2Wdt = -nLineWdt * nArrow2Wdt / 100; // <0 = relativ
406 basegfx::B2DPolyPolygon aPol1(static_cast<const XLineStartItem&>(rSet.Get(XATTR_LINESTART)).GetLineStartValue());
407 basegfx::B2DPolyPolygon aPol2(static_cast<const XLineEndItem&>(rSet.Get(XATTR_LINEEND)).GetLineEndValue());
408 bArrow1Center = static_cast<const XLineStartCenterItem&>(rSet.Get(XATTR_LINESTARTCENTER)).GetValue();
409 bArrow2Center = static_cast<const XLineEndCenterItem&>(rSet.Get(XATTR_LINEENDCENTER)).GetValue();
410 nArrow1Len = impGetLineStartEndDistance(aPol1, nArrow1Wdt, bArrow1Center) - 1;
411 nArrow2Len = impGetLineStartEndDistance(aPol2, nArrow2Wdt, bArrow2Center) - 1;
413 // nArrowLen is already halved at bCenter.
414 // In the case of 2 arrowheads each 4mm long, we can't go below 10mm.
415 nArrowNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2;
416 if (rPol.nLineLen<nArrowNeed) bPfeileAussen = true;
417 nShortLen=(nArrow1Len+nArrow1Wdt + nArrow2Len+nArrow2Wdt) /2;
419 rPol.eUsedTextHPos=rRec.eWantTextHPos;
420 rPol.eUsedTextVPos=rRec.eWantTextVPos;
421 if (rPol.eUsedTextVPos==SDRMEASURE_TEXTVAUTO) rPol.eUsedTextVPos=SDRMEASURE_ABOVE;
422 bool bBrkLine=rPol.eUsedTextVPos==SDRMEASURETEXT_BREAKEDLINE;
423 if (rPol.eUsedTextVPos==SDRMEASURETEXT_VERTICALCENTERED)
425 OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
426 if (pOutlinerParaObject!=NULL && pOutlinerParaObject->GetTextObject().GetParagraphCount()==1)
428 bBrkLine=true; // dashed line if there's only on paragraph.
431 rPol.bBreakedLine=bBrkLine;
432 if (rPol.eUsedTextHPos==SDRMEASURE_TEXTHAUTO) { // if text is too wide, push it outside
433 bool bOutside = false;
434 long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
435 if (nNeedSiz>rPol.nLineLen) bOutside = true; // text doesn't fit in between
436 if (bBrkLine) {
437 if (nNeedSiz+nArrowNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
438 } else {
439 long nSmallNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2/4;
440 if (nNeedSiz+nSmallNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
442 rPol.eUsedTextHPos=bOutside ? SDRMEASURE_TEXTLEFTOUTSIDE : SDRMEASURE_TEXTINSIDE;
444 if (rPol.eUsedTextHPos!=SDRMEASURE_TEXTINSIDE) bPfeileAussen = true;
445 rPol.nArrow1Wdt=nArrow1Wdt;
446 rPol.nArrow2Wdt=nArrow2Wdt;
447 rPol.nShortLineLen=nShortLen;
448 rPol.bPfeileAussen=bPfeileAussen;
449 rPol.nArrow1Len=nArrow1Len;
450 rPol.bArrow1Center=bArrow1Center;
451 rPol.nArrow2Len=nArrow2Len;
452 rPol.bArrow2Center=bArrow2Center;
454 rPol.nLineAngle=GetAngle(aDelt);
455 double a=rPol.nLineAngle*nPi180;
456 double nLineSin=sin(a);
457 double nLineCos=cos(a);
458 rPol.nLineSin=nLineSin;
459 rPol.nLineCos=nLineCos;
461 rPol.nTextAngle=rPol.nLineAngle;
462 if (rRec.bTextRota90) rPol.nTextAngle+=9000;
464 rPol.bAutoUpsideDown=false;
465 if (rRec.bTextAutoAngle) {
466 long nTmpAngle=NormAngle360(rPol.nTextAngle-rRec.nTextAutoAngleView);
467 if (nTmpAngle>=18000) {
468 rPol.nTextAngle+=18000;
469 rPol.bAutoUpsideDown=true;
473 if (rRec.bTextUpsideDown) rPol.nTextAngle+=18000;
474 rPol.nTextAngle=NormAngle360(rPol.nTextAngle);
475 rPol.nHlpAngle=rPol.nLineAngle+9000;
476 if (rRec.bBelowRefEdge) rPol.nHlpAngle+=18000;
477 rPol.nHlpAngle=NormAngle360(rPol.nHlpAngle);
478 double nHlpSin=nLineCos;
479 double nHlpCos=-nLineSin;
480 if (rRec.bBelowRefEdge) {
481 nHlpSin=-nHlpSin;
482 nHlpCos=-nHlpCos;
484 rPol.nHlpSin=nHlpSin;
485 rPol.nHlpCos=nHlpCos;
487 long nLineDist=rRec.nLineDist;
488 long nOverhang=rRec.nHelplineOverhang;
489 long nHelplineDist=rRec.nHelplineDist;
491 long dx= Round(nLineDist*nHlpCos);
492 long dy=-Round(nLineDist*nHlpSin);
493 long dxh1a= Round((nHelplineDist-rRec.nHelpline1Len)*nHlpCos);
494 long dyh1a=-Round((nHelplineDist-rRec.nHelpline1Len)*nHlpSin);
495 long dxh1b= Round((nHelplineDist-rRec.nHelpline2Len)*nHlpCos);
496 long dyh1b=-Round((nHelplineDist-rRec.nHelpline2Len)*nHlpSin);
497 long dxh2= Round((nLineDist+nOverhang)*nHlpCos);
498 long dyh2=-Round((nLineDist+nOverhang)*nHlpSin);
500 // extension line 1
501 rPol.aHelpline1.aP1=Point(aP1.X()+dxh1a,aP1.Y()+dyh1a);
502 rPol.aHelpline1.aP2=Point(aP1.X()+dxh2,aP1.Y()+dyh2);
504 // extension line 2
505 rPol.aHelpline2.aP1=Point(aP2.X()+dxh1b,aP2.Y()+dyh1b);
506 rPol.aHelpline2.aP2=Point(aP2.X()+dxh2,aP2.Y()+dyh2);
508 // dimension line
509 Point aMainlinePt1(aP1.X()+dx,aP1.Y()+dy);
510 Point aMainlinePt2(aP2.X()+dx,aP2.Y()+dy);
511 if (!bPfeileAussen) {
512 rPol.aMainline1.aP1=aMainlinePt1;
513 rPol.aMainline1.aP2=aMainlinePt2;
514 rPol.aMainline2=rPol.aMainline1;
515 rPol.aMainline3=rPol.aMainline1;
516 rPol.nMainlineAnz=1;
517 if (bBrkLine) {
518 long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
519 long nHalfLen=(rPol.nLineLen-nNeedSiz-nArrow1Wdt/4-nArrow2Wdt/4) /2;
520 rPol.nMainlineAnz=2;
521 rPol.aMainline1.aP2=aMainlinePt1;
522 rPol.aMainline1.aP2.X()+=nHalfLen;
523 RotatePoint(rPol.aMainline1.aP2,rPol.aMainline1.aP1,nLineSin,nLineCos);
524 rPol.aMainline2.aP1=aMainlinePt2;
525 rPol.aMainline2.aP1.X()-=nHalfLen;
526 RotatePoint(rPol.aMainline2.aP1,rPol.aMainline2.aP2,nLineSin,nLineCos);
528 } else {
529 long nLen1=nShortLen; // arrowhead's width as line length outside of the arrowhead
530 long nLen2=nShortLen;
531 long nTextWdt=rRec.bTextRota90 ? rPol.aTextSize.Height() : rPol.aTextSize.Width();
532 if (!bBrkLine) {
533 if (rPol.eUsedTextHPos==SDRMEASURE_TEXTLEFTOUTSIDE) nLen1=nArrow1Len+nTextWdt;
534 if (rPol.eUsedTextHPos==SDRMEASURE_TEXTRIGHTOUTSIDE) nLen2=nArrow2Len+nTextWdt;
536 rPol.aMainline1.aP1=aMainlinePt1;
537 rPol.aMainline1.aP2=aMainlinePt1; rPol.aMainline1.aP2.X()-=nLen1; RotatePoint(rPol.aMainline1.aP2,aMainlinePt1,nLineSin,nLineCos);
538 rPol.aMainline2.aP1=aMainlinePt2; rPol.aMainline2.aP1.X()+=nLen2; RotatePoint(rPol.aMainline2.aP1,aMainlinePt2,nLineSin,nLineCos);
539 rPol.aMainline2.aP2=aMainlinePt2;
540 rPol.aMainline3.aP1=aMainlinePt1;
541 rPol.aMainline3.aP2=aMainlinePt2;
542 rPol.nMainlineAnz=3;
543 if (bBrkLine && rPol.eUsedTextHPos==SDRMEASURE_TEXTINSIDE) rPol.nMainlineAnz=2;
547 basegfx::B2DPolyPolygon SdrMeasureObj::ImpCalcXPoly(const ImpMeasurePoly& rPol)
549 basegfx::B2DPolyPolygon aRetval;
550 basegfx::B2DPolygon aPartPolyA;
551 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP1.X(), rPol.aMainline1.aP1.Y()));
552 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP2.X(), rPol.aMainline1.aP2.Y()));
553 aRetval.append(aPartPolyA);
555 if(rPol.nMainlineAnz > 1)
557 aPartPolyA.clear();
558 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP1.X(), rPol.aMainline2.aP1.Y()));
559 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP2.X(), rPol.aMainline2.aP2.Y()));
560 aRetval.append(aPartPolyA);
563 if(rPol.nMainlineAnz > 2)
565 aPartPolyA.clear();
566 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP1.X(), rPol.aMainline3.aP1.Y()));
567 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP2.X(), rPol.aMainline3.aP2.Y()));
568 aRetval.append(aPartPolyA);
571 aPartPolyA.clear();
572 aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP1.X(), rPol.aHelpline1.aP1.Y()));
573 aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP2.X(), rPol.aHelpline1.aP2.Y()));
574 aRetval.append(aPartPolyA);
576 aPartPolyA.clear();
577 aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP1.X(), rPol.aHelpline2.aP1.Y()));
578 aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP2.X(), rPol.aHelpline2.aP2.Y()));
579 aRetval.append(aPartPolyA);
581 return aRetval;
584 bool SdrMeasureObj::CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_uInt16 nPos,
585 bool bEdit,
586 Color*& rpTxtColor, Color*& rpFldColor, OUString& rRet) const
588 const SvxFieldData* pField=rField.GetField();
589 const SdrMeasureField* pMeasureField=PTR_CAST(SdrMeasureField,pField);
590 if (pMeasureField!=NULL) {
591 rRet = TakeRepresentation(pMeasureField->GetMeasureFieldKind());
592 if (rpFldColor!=NULL) {
593 if (!bEdit)
595 delete rpFldColor;
596 rpFldColor=NULL;
599 return true;
600 } else {
601 return SdrTextObj::CalcFieldValue(rField,nPara,nPos,bEdit,rpTxtColor,rpFldColor,rRet);
605 void SdrMeasureObj::UndirtyText() const
607 if (bTextDirty)
609 SdrOutliner& rOutliner=ImpGetDrawOutliner();
610 OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
611 if(pOutlinerParaObject==NULL)
613 rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_ROTA90BLANCS), EE_FEATURE_FIELD), ESelection(0,0));
614 rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_VALUE), EE_FEATURE_FIELD),ESelection(0,1));
615 rOutliner.QuickInsertText(" ", ESelection(0,2));
616 rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_UNIT), EE_FEATURE_FIELD),ESelection(0,3));
617 rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_ROTA90BLANCS), EE_FEATURE_FIELD),ESelection(0,4));
619 if(GetStyleSheet())
620 rOutliner.SetStyleSheet(0, GetStyleSheet());
622 rOutliner.SetParaAttribs(0, GetObjectItemSet());
624 // cast to nonconst
625 const_cast<SdrMeasureObj*>(this)->NbcSetOutlinerParaObject( rOutliner.CreateParaObject() );
627 else
629 rOutliner.SetText(*pOutlinerParaObject);
632 rOutliner.SetUpdateMode(true);
633 rOutliner.UpdateFields();
634 Size aSiz(rOutliner.CalcTextSize());
635 rOutliner.Clear();
636 // cast to nonconst three times
637 const_cast<SdrMeasureObj*>(this)->aTextSize=aSiz;
638 const_cast<SdrMeasureObj*>(this)->bTextSizeDirty=false;
639 const_cast<SdrMeasureObj*>(this)->bTextDirty=false;
643 void SdrMeasureObj::TakeUnrotatedSnapRect(Rectangle& rRect) const
645 if (bTextDirty) UndirtyText();
646 ImpMeasureRec aRec;
647 ImpMeasurePoly aMPol;
648 ImpTakeAttr(aRec);
649 ImpCalcGeometrics(aRec,aMPol);
651 // determine TextSize including text frame margins
652 Size aTextSize2(aMPol.aTextSize);
653 if (aTextSize2.Width()<1) aTextSize2.Width()=1;
654 if (aTextSize2.Height()<1) aTextSize2.Height()=1;
655 aTextSize2.Width()+=GetTextLeftDistance()+GetTextRightDistance();
656 aTextSize2.Height()+=GetTextUpperDistance()+GetTextLowerDistance();
658 Point aPt1b(aMPol.aMainline1.aP1);
659 long nLen=aMPol.nLineLen;
660 long nLWdt=aMPol.nLineWdt2;
661 long nArr1Len=aMPol.nArrow1Len;
662 long nArr2Len=aMPol.nArrow2Len;
663 if (aMPol.bBreakedLine) {
664 // In the case of a dashed line and Outside, the text should be
665 // placed next to the line at the arrowhead instead of directly
666 // at the arrowhead.
667 nArr1Len=aMPol.nShortLineLen+aMPol.nArrow1Wdt/4;
668 nArr2Len=aMPol.nShortLineLen+aMPol.nArrow2Wdt/4;
671 Point aTextPos;
672 bool bRota90=aRec.bTextRota90;
673 bool bUpsideDown=aRec.bTextUpsideDown!=aMPol.bAutoUpsideDown;
674 bool bBelowRefEdge=aRec.bBelowRefEdge;
675 SdrMeasureTextHPos eMH=aMPol.eUsedTextHPos;
676 SdrMeasureTextVPos eMV=aMPol.eUsedTextVPos;
677 if (!bRota90) {
678 switch (eMH) {
679 case SDRMEASURE_TEXTLEFTOUTSIDE: aTextPos.X()=aPt1b.X()-aTextSize2.Width()-nArr1Len-nLWdt; break;
680 case SDRMEASURE_TEXTRIGHTOUTSIDE: aTextPos.X()=aPt1b.X()+nLen+nArr2Len+nLWdt; break;
681 default: aTextPos.X()=aPt1b.X(); aTextSize2.Width()=nLen;
683 switch (eMV) {
684 case SDRMEASURETEXT_VERTICALCENTERED:
685 case SDRMEASURETEXT_BREAKEDLINE: aTextPos.Y()=aPt1b.Y()-aTextSize2.Height()/2; break;
686 case SDRMEASURE_BELOW: {
687 if (!bUpsideDown) aTextPos.Y()=aPt1b.Y()+nLWdt;
688 else aTextPos.Y()=aPt1b.Y()-aTextSize2.Height()-nLWdt;
689 } break;
690 default: {
691 if (!bUpsideDown) aTextPos.Y()=aPt1b.Y()-aTextSize2.Height()-nLWdt;
692 else aTextPos.Y()=aPt1b.Y()+nLWdt;
695 if (bUpsideDown) {
696 aTextPos.X()+=aTextSize2.Width();
697 aTextPos.Y()+=aTextSize2.Height();
699 } else { // also if bTextRota90==TRUE
700 switch (eMH) {
701 case SDRMEASURE_TEXTLEFTOUTSIDE: aTextPos.X()=aPt1b.X()-aTextSize2.Height()-nArr1Len; break;
702 case SDRMEASURE_TEXTRIGHTOUTSIDE: aTextPos.X()=aPt1b.X()+nLen+nArr2Len; break;
703 default: aTextPos.X()=aPt1b.X(); aTextSize2.Height()=nLen;
705 switch (eMV) {
706 case SDRMEASURETEXT_VERTICALCENTERED:
707 case SDRMEASURETEXT_BREAKEDLINE: aTextPos.Y()=aPt1b.Y()+aTextSize2.Width()/2; break;
708 case SDRMEASURE_BELOW: {
709 if (!bBelowRefEdge) aTextPos.Y()=aPt1b.Y()+aTextSize2.Width()+nLWdt;
710 else aTextPos.Y()=aPt1b.Y()-nLWdt;
711 } break;
712 default: {
713 if (!bBelowRefEdge) aTextPos.Y()=aPt1b.Y()-nLWdt;
714 else aTextPos.Y()=aPt1b.Y()+aTextSize2.Width()+nLWdt;
717 if (bUpsideDown) {
718 aTextPos.X()+=aTextSize2.Height();
719 aTextPos.Y()-=aTextSize2.Width();
722 if (aMPol.nTextAngle!=aGeo.nRotationAngle) {
723 const_cast<SdrMeasureObj*>(this)->aGeo.nRotationAngle=aMPol.nTextAngle;
724 const_cast<SdrMeasureObj*>(this)->aGeo.RecalcSinCos();
726 RotatePoint(aTextPos,aPt1b,aMPol.nLineSin,aMPol.nLineCos);
727 aTextSize2.Width()++; aTextSize2.Height()++; // because of the Rect-Ctor's odd behavior
728 rRect=Rectangle(aTextPos,aTextSize2);
729 rRect.Justify();
730 const_cast<SdrMeasureObj*>(this)->maRect=rRect;
732 if (aMPol.nTextAngle!=aGeo.nRotationAngle) {
733 const_cast<SdrMeasureObj*>(this)->aGeo.nRotationAngle=aMPol.nTextAngle;
734 const_cast<SdrMeasureObj*>(this)->aGeo.RecalcSinCos();
738 SdrMeasureObj* SdrMeasureObj::Clone() const
740 return CloneHelper< SdrMeasureObj >();
743 OUString SdrMeasureObj::TakeObjNameSingul() const
745 OUStringBuffer sName(ImpGetResStr(STR_ObjNameSingulMEASURE));
747 OUString aName( GetName() );
748 if (!aName.isEmpty())
750 sName.append(' ');
751 sName.append('\'');
752 sName.append(aName);
753 sName.append('\'');
756 return sName.makeStringAndClear();
759 OUString SdrMeasureObj::TakeObjNamePlural() const
761 return ImpGetResStr(STR_ObjNamePluralMEASURE);
764 basegfx::B2DPolyPolygon SdrMeasureObj::TakeXorPoly() const
766 ImpMeasureRec aRec;
767 ImpMeasurePoly aMPol;
768 ImpTakeAttr(aRec);
769 ImpCalcGeometrics(aRec,aMPol);
770 return ImpCalcXPoly(aMPol);
773 sal_uInt32 SdrMeasureObj::GetHdlCount() const
775 return 6L;
778 SdrHdl* SdrMeasureObj::GetHdl(sal_uInt32 nHdlNum) const
780 ImpMeasureRec aRec;
781 ImpMeasurePoly aMPol;
782 ImpTakeAttr(aRec);
783 aRec.nHelplineDist=0;
784 ImpCalcGeometrics(aRec,aMPol);
785 Point aPt;
787 switch (nHdlNum) {
788 case 0: aPt=aMPol.aHelpline1.aP1; break;
789 case 1: aPt=aMPol.aHelpline2.aP1; break;
790 case 2: aPt=aPt1; break;
791 case 3: aPt=aPt2; break;
792 case 4: aPt=aMPol.aHelpline1.aP2; break;
793 case 5: aPt=aMPol.aHelpline2.aP2; break;
794 } // switch
795 SdrHdl* pHdl=new ImpMeasureHdl(aPt,HDL_USER);
796 pHdl->SetObjHdlNum(nHdlNum);
797 pHdl->SetRotationAngle(aMPol.nLineAngle);
798 return pHdl;
803 bool SdrMeasureObj::hasSpecialDrag() const
805 return true;
808 bool SdrMeasureObj::beginSpecialDrag(SdrDragStat& rDrag) const
810 const SdrHdl* pHdl = rDrag.GetHdl();
812 if(pHdl)
814 const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
816 if(nHdlNum != 2 && nHdlNum != 3)
818 rDrag.SetEndDragChangesAttributes(true);
821 return true;
824 return false;
827 bool SdrMeasureObj::applySpecialDrag(SdrDragStat& rDrag)
829 ImpMeasureRec aMeasureRec;
830 const SdrHdl* pHdl = rDrag.GetHdl();
831 const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
833 ImpTakeAttr(aMeasureRec);
834 ImpEvalDrag(aMeasureRec, rDrag);
836 switch (nHdlNum)
838 case 2:
840 aPt1 = aMeasureRec.aPt1;
841 SetTextDirty();
842 break;
844 case 3:
846 aPt2 = aMeasureRec.aPt2;
847 SetTextDirty();
848 break;
850 default:
852 switch(nHdlNum)
854 case 0:
855 case 1:
857 ImpMeasureRec aOrigMeasureRec;
858 ImpTakeAttr(aOrigMeasureRec);
860 if(aMeasureRec.nHelpline1Len != aOrigMeasureRec.nHelpline1Len)
862 SetObjectItem(makeSdrMeasureHelpline1LenItem(aMeasureRec.nHelpline1Len));
865 if(aMeasureRec.nHelpline2Len != aOrigMeasureRec.nHelpline2Len)
867 SetObjectItem(makeSdrMeasureHelpline2LenItem(aMeasureRec.nHelpline2Len));
870 break;
873 case 4:
874 case 5:
876 ImpMeasureRec aOrigMeasureRec;
877 ImpTakeAttr(aOrigMeasureRec);
879 if(aMeasureRec.nLineDist != aOrigMeasureRec.nLineDist)
881 SetObjectItem(makeSdrMeasureLineDistItem(aMeasureRec.nLineDist));
884 if(aMeasureRec.bBelowRefEdge != aOrigMeasureRec.bBelowRefEdge)
886 SetObjectItem(SdrMeasureBelowRefEdgeItem(aMeasureRec.bBelowRefEdge));
891 } // switch
893 SetRectsDirty();
894 SetChanged();
896 return true;
899 OUString SdrMeasureObj::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
901 return OUString();
904 void SdrMeasureObj::ImpEvalDrag(ImpMeasureRec& rRec, const SdrDragStat& rDrag) const
906 long nLineAngle=GetAngle(rRec.aPt2-rRec.aPt1);
907 double a=nLineAngle*nPi180;
908 double nSin=sin(a);
909 double nCos=cos(a);
911 const SdrHdl* pHdl=rDrag.GetHdl();
912 sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
913 bool bOrtho=rDrag.GetView()!=NULL && rDrag.GetView()->IsOrtho();
914 bool bBigOrtho=bOrtho && rDrag.GetView()->IsBigOrtho();
915 bool bBelow=rRec.bBelowRefEdge;
916 Point aPt(rDrag.GetNow());
918 switch (nHdlNum) {
919 case 0: {
920 RotatePoint(aPt,aPt1,nSin,-nCos);
921 rRec.nHelpline1Len=aPt1.Y()-aPt.Y();
922 if (bBelow) rRec.nHelpline1Len=-rRec.nHelpline1Len;
923 if (bOrtho) rRec.nHelpline2Len=rRec.nHelpline1Len;
924 } break;
925 case 1: {
926 RotatePoint(aPt,aPt2,nSin,-nCos);
927 rRec.nHelpline2Len=aPt2.Y()-aPt.Y();
928 if (bBelow) rRec.nHelpline2Len=-rRec.nHelpline2Len;
929 if (bOrtho) rRec.nHelpline1Len=rRec.nHelpline2Len;
930 } break;
931 case 2: case 3: {
932 bool bAnf=nHdlNum==2;
933 Point& rMov=bAnf ? rRec.aPt1 : rRec.aPt2;
934 Point aMov(rMov);
935 Point aFix(bAnf ? rRec.aPt2 : rRec.aPt1);
936 if (bOrtho) {
937 long ndx0=aMov.X()-aFix.X();
938 long ndy0=aMov.Y()-aFix.Y();
939 bool bHLin=ndy0==0;
940 bool bVLin=ndx0==0;
941 if (!bHLin || !bVLin) { // else aPt1==aPt2
942 long ndx=aPt.X()-aFix.X();
943 long ndy=aPt.Y()-aFix.Y();
944 double nXFact=0; if (!bVLin) nXFact=(double)ndx/(double)ndx0;
945 double nYFact=0; if (!bHLin) nYFact=(double)ndy/(double)ndy0;
946 bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
947 bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
948 if (bHor) ndy=long(ndy0*nXFact);
949 if (bVer) ndx=long(ndx0*nYFact);
950 aPt=aFix;
951 aPt.X()+=ndx;
952 aPt.Y()+=ndy;
953 } // else Ortho8
955 rMov=aPt;
956 } break;
957 case 4: case 5: {
958 long nVal0=rRec.nLineDist;
959 RotatePoint(aPt,(nHdlNum==4 ? aPt1 : aPt2),nSin,-nCos);
960 rRec.nLineDist=aPt.Y()- (nHdlNum==4 ? aPt1.Y() : aPt2.Y());
961 if (bBelow) rRec.nLineDist=-rRec.nLineDist;
962 if (rRec.nLineDist<0) {
963 rRec.nLineDist=-rRec.nLineDist;
964 rRec.bBelowRefEdge=!bBelow;
966 rRec.nLineDist-=rRec.nHelplineOverhang;
967 if (bOrtho) rRec.nLineDist=nVal0;
968 } break;
969 } // switch
974 bool SdrMeasureObj::BegCreate(SdrDragStat& rStat)
976 rStat.SetOrtho8Possible();
977 aPt1=rStat.GetStart();
978 aPt2=rStat.GetNow();
979 SetTextDirty();
980 return true;
983 bool SdrMeasureObj::MovCreate(SdrDragStat& rStat)
985 SdrView* pView=rStat.GetView();
986 aPt1=rStat.GetStart();
987 aPt2=rStat.GetNow();
988 if (pView!=NULL && pView->IsCreate1stPointAsCenter()) {
989 aPt1+=aPt1;
990 aPt1-=rStat.Now();
992 SetTextDirty();
993 SetBoundRectDirty();
994 bSnapRectDirty=true;
995 return true;
998 bool SdrMeasureObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
1000 SetTextDirty();
1001 SetRectsDirty();
1002 return (eCmd==SDRCREATE_FORCEEND || rStat.GetPointAnz()>=2);
1005 bool SdrMeasureObj::BckCreate(SdrDragStat& /*rStat*/)
1007 return false;
1010 void SdrMeasureObj::BrkCreate(SdrDragStat& /*rStat*/)
1014 basegfx::B2DPolyPolygon SdrMeasureObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
1016 ImpMeasureRec aRec;
1017 ImpMeasurePoly aMPol;
1019 ImpTakeAttr(aRec);
1020 ImpCalcGeometrics(aRec, aMPol);
1022 return ImpCalcXPoly(aMPol);
1025 Pointer SdrMeasureObj::GetCreatePointer() const
1027 return Pointer(PointerStyle::Cross);
1030 void SdrMeasureObj::NbcMove(const Size& rSiz)
1032 SdrTextObj::NbcMove(rSiz);
1033 MovePoint(aPt1,rSiz);
1034 MovePoint(aPt2,rSiz);
1037 void SdrMeasureObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
1039 SdrTextObj::NbcResize(rRef,xFact,yFact);
1040 ResizePoint(aPt1,rRef,xFact,yFact);
1041 ResizePoint(aPt2,rRef,xFact,yFact);
1042 SetTextDirty();
1045 void SdrMeasureObj::NbcRotate(const Point& rRef, long nAngle, double sn, double cs)
1047 SdrTextObj::NbcRotate(rRef,nAngle,sn,cs);
1048 long nLen0=GetLen(aPt2-aPt1);
1049 RotatePoint(aPt1,rRef,sn,cs);
1050 RotatePoint(aPt2,rRef,sn,cs);
1051 long nLen1=GetLen(aPt2-aPt1);
1052 if (nLen1!=nLen0) { // rounding error!
1053 long dx=aPt2.X()-aPt1.X();
1054 long dy=aPt2.Y()-aPt1.Y();
1055 dx=BigMulDiv(dx,nLen0,nLen1);
1056 dy=BigMulDiv(dy,nLen0,nLen1);
1057 if (rRef==aPt2) {
1058 aPt1.X()=aPt2.X()-dx;
1059 aPt1.Y()=aPt2.Y()-dy;
1060 } else {
1061 aPt2.X()=aPt1.X()+dx;
1062 aPt2.Y()=aPt1.Y()+dy;
1065 SetRectsDirty();
1068 void SdrMeasureObj::NbcMirror(const Point& rRef1, const Point& rRef2)
1070 SdrTextObj::NbcMirror(rRef1,rRef2);
1071 MirrorPoint(aPt1,rRef1,rRef2);
1072 MirrorPoint(aPt2,rRef1,rRef2);
1073 SetRectsDirty();
1076 void SdrMeasureObj::NbcShear(const Point& rRef, long nAngle, double tn, bool bVShear)
1078 SdrTextObj::NbcShear(rRef,nAngle,tn,bVShear);
1079 ShearPoint(aPt1,rRef,tn,bVShear);
1080 ShearPoint(aPt2,rRef,tn,bVShear);
1081 SetRectsDirty();
1082 SetTextDirty();
1085 long SdrMeasureObj::GetRotateAngle() const
1087 return GetAngle(aPt2-aPt1);
1090 void SdrMeasureObj::RecalcSnapRect()
1092 ImpMeasureRec aRec;
1093 ImpMeasurePoly aMPol;
1094 XPolyPolygon aXPP;
1096 ImpTakeAttr(aRec);
1097 ImpCalcGeometrics(aRec, aMPol);
1098 aXPP = XPolyPolygon(ImpCalcXPoly(aMPol));
1099 maSnapRect = aXPP.GetBoundRect();
1102 sal_uInt32 SdrMeasureObj::GetSnapPointCount() const
1104 return 2L;
1107 Point SdrMeasureObj::GetSnapPoint(sal_uInt32 i) const
1109 if (i==0) return aPt1;
1110 else return aPt2;
1113 bool SdrMeasureObj::IsPolyObj() const
1115 return true;
1118 sal_uInt32 SdrMeasureObj::GetPointCount() const
1120 return 2L;
1123 Point SdrMeasureObj::GetPoint(sal_uInt32 i) const
1125 return (0L == i) ? aPt1 : aPt2;
1128 void SdrMeasureObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
1130 if (0L == i)
1131 aPt1=rPnt;
1132 if (1L == i)
1133 aPt2=rPnt;
1134 SetRectsDirty();
1135 SetTextDirty();
1138 SdrObjGeoData* SdrMeasureObj::NewGeoData() const
1140 return new SdrMeasureObjGeoData;
1143 void SdrMeasureObj::SaveGeoData(SdrObjGeoData& rGeo) const
1145 SdrTextObj::SaveGeoData(rGeo);
1146 SdrMeasureObjGeoData& rMGeo=static_cast<SdrMeasureObjGeoData&>(rGeo);
1147 rMGeo.aPt1=aPt1;
1148 rMGeo.aPt2=aPt2;
1151 void SdrMeasureObj::RestGeoData(const SdrObjGeoData& rGeo)
1153 SdrTextObj::RestGeoData(rGeo);
1154 const SdrMeasureObjGeoData& rMGeo=static_cast<const SdrMeasureObjGeoData&>(rGeo);
1155 aPt1=rMGeo.aPt1;
1156 aPt2=rMGeo.aPt2;
1157 SetTextDirty();
1160 SdrObject* SdrMeasureObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
1162 // get XOR Poly as base
1163 XPolyPolygon aTmpPolyPolygon(TakeXorPoly());
1165 // get local ItemSet and StyleSheet
1166 SfxItemSet aSet(GetObjectItemSet());
1167 SfxStyleSheet* pStyleSheet = GetStyleSheet();
1169 // prepare group
1170 SdrObjGroup* pGroup = new SdrObjGroup;
1171 pGroup->SetModel(GetModel());
1173 // prepare parameters
1174 basegfx::B2DPolyPolygon aPolyPoly;
1175 SdrPathObj* pPath;
1176 sal_uInt16 nCount(aTmpPolyPolygon.Count());
1177 sal_uInt16 nLoopStart(0);
1179 if(nCount == 3)
1181 // three lines, first one is the middle one
1182 aPolyPoly.clear();
1183 aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1185 pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1186 pPath->SetModel(GetModel());
1187 pPath->SetMergedItemSet(aSet);
1188 pPath->SetStyleSheet(pStyleSheet, true);
1189 pGroup->GetSubList()->NbcInsertObject(pPath);
1190 aSet.Put(XLineStartWidthItem(0L));
1191 aSet.Put(XLineEndWidthItem(0L));
1192 nLoopStart = 1;
1194 else if(nCount == 4)
1196 // four lines, middle line with gap, so there are two lines used
1197 // which have one arrow each
1198 sal_Int32 nEndWidth = static_cast<const XLineEndWidthItem&>(aSet.Get(XATTR_LINEENDWIDTH)).GetValue();
1199 aSet.Put(XLineEndWidthItem(0L));
1201 aPolyPoly.clear();
1202 aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1203 pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1204 pPath->SetModel(GetModel());
1205 pPath->SetMergedItemSet(aSet);
1206 pPath->SetStyleSheet(pStyleSheet, true);
1208 pGroup->GetSubList()->NbcInsertObject(pPath);
1210 aSet.Put(XLineEndWidthItem(nEndWidth));
1211 aSet.Put(XLineStartWidthItem(0L));
1213 aPolyPoly.clear();
1214 aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
1215 pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1216 pPath->SetModel(GetModel());
1217 pPath->SetMergedItemSet(aSet);
1218 pPath->SetStyleSheet(pStyleSheet, true);
1220 pGroup->GetSubList()->NbcInsertObject(pPath);
1222 aSet.Put(XLineEndWidthItem(0L));
1223 nLoopStart = 2;
1225 else if(nCount == 5)
1227 // five lines, first two are the outer ones
1228 sal_Int32 nEndWidth = static_cast<const XLineEndWidthItem&>(aSet.Get(XATTR_LINEENDWIDTH)).GetValue();
1230 aSet.Put(XLineEndWidthItem(0L));
1232 aPolyPoly.clear();
1233 aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1234 pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1235 pPath->SetModel(GetModel());
1236 pPath->SetMergedItemSet(aSet);
1237 pPath->SetStyleSheet(pStyleSheet, true);
1239 pGroup->GetSubList()->NbcInsertObject(pPath);
1241 aSet.Put(XLineEndWidthItem(nEndWidth));
1242 aSet.Put(XLineStartWidthItem(0L));
1244 aPolyPoly.clear();
1245 aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
1246 pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1247 pPath->SetModel(GetModel());
1248 pPath->SetMergedItemSet(aSet);
1249 pPath->SetStyleSheet(pStyleSheet, true);
1251 pGroup->GetSubList()->NbcInsertObject(pPath);
1253 aSet.Put(XLineEndWidthItem(0L));
1254 nLoopStart = 2;
1257 for(;nLoopStart<nCount;nLoopStart++)
1259 aPolyPoly.clear();
1260 aPolyPoly.append(aTmpPolyPolygon[nLoopStart].getB2DPolygon());
1261 pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1262 pPath->SetModel(GetModel());
1263 pPath->SetMergedItemSet(aSet);
1264 pPath->SetStyleSheet(pStyleSheet, true);
1266 pGroup->GetSubList()->NbcInsertObject(pPath);
1269 if(bAddText)
1271 return ImpConvertAddText(pGroup, bBezier);
1273 else
1275 return pGroup;
1279 bool SdrMeasureObj::BegTextEdit(SdrOutliner& rOutl)
1281 UndirtyText();
1282 return SdrTextObj::BegTextEdit(rOutl);
1285 const Size& SdrMeasureObj::GetTextSize() const
1287 if (bTextDirty) UndirtyText();
1288 return SdrTextObj::GetTextSize();
1291 OutlinerParaObject* SdrMeasureObj::GetOutlinerParaObject() const
1293 if(bTextDirty)
1294 UndirtyText();
1295 return SdrTextObj::GetOutlinerParaObject();
1298 void SdrMeasureObj::NbcSetOutlinerParaObject(OutlinerParaObject* pTextObject)
1300 SdrTextObj::NbcSetOutlinerParaObject(pTextObject);
1301 if(SdrTextObj::GetOutlinerParaObject())
1302 SetTextDirty(); // recalculate text
1305 void SdrMeasureObj::TakeTextRect( SdrOutliner& rOutliner, Rectangle& rTextRect, bool bNoEditText,
1306 Rectangle* pAnchorRect, bool bLineWidth ) const
1308 if (bTextDirty) UndirtyText();
1309 SdrTextObj::TakeTextRect( rOutliner, rTextRect, bNoEditText, pAnchorRect, bLineWidth );
1312 void SdrMeasureObj::TakeTextAnchorRect(Rectangle& rAnchorRect) const
1314 if (bTextDirty) UndirtyText();
1315 SdrTextObj::TakeTextAnchorRect(rAnchorRect);
1318 void SdrMeasureObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, Rectangle* pViewInit, Rectangle* pViewMin) const
1320 if (bTextDirty) UndirtyText();
1321 SdrTextObj::TakeTextEditArea(pPaperMin,pPaperMax,pViewInit,pViewMin);
1324 sal_uInt16 SdrMeasureObj::GetOutlinerViewAnchorMode() const
1326 if (bTextDirty) UndirtyText();
1327 ImpMeasureRec aRec;
1328 ImpMeasurePoly aMPol;
1329 ImpTakeAttr(aRec);
1330 ImpCalcGeometrics(aRec,aMPol);
1332 SdrTextHorzAdjust eTH=GetTextHorizontalAdjust();
1333 SdrTextVertAdjust eTV=GetTextVerticalAdjust();
1334 SdrMeasureTextHPos eMH=aMPol.eUsedTextHPos;
1335 SdrMeasureTextVPos eMV=aMPol.eUsedTextVPos;
1336 bool bTextRota90=aRec.bTextRota90;
1337 bool bBelowRefEdge=aRec.bBelowRefEdge;
1339 // TODO: bTextUpsideDown should be interpreted here!
1340 if (!bTextRota90) {
1341 if (eMH==SDRMEASURE_TEXTLEFTOUTSIDE) eTH=SDRTEXTHORZADJUST_RIGHT;
1342 if (eMH==SDRMEASURE_TEXTRIGHTOUTSIDE) eTH=SDRTEXTHORZADJUST_LEFT;
1343 // at eMH==SDRMEASURE_TEXTINSIDE we can anchor horizontally
1344 if (eMV==SDRMEASURE_ABOVE) eTV=SDRTEXTVERTADJUST_BOTTOM;
1345 if (eMV==SDRMEASURE_BELOW) eTV=SDRTEXTVERTADJUST_TOP;
1346 if (eMV==SDRMEASURETEXT_BREAKEDLINE || eMV==SDRMEASURETEXT_VERTICALCENTERED) eTV=SDRTEXTVERTADJUST_CENTER;
1347 } else {
1348 if (eMH==SDRMEASURE_TEXTLEFTOUTSIDE) eTV=SDRTEXTVERTADJUST_BOTTOM;
1349 if (eMH==SDRMEASURE_TEXTRIGHTOUTSIDE) eTV=SDRTEXTVERTADJUST_TOP;
1350 // at eMH==SDRMEASURE_TEXTINSIDE we can anchor vertically
1351 if (!bBelowRefEdge) {
1352 if (eMV==SDRMEASURE_ABOVE) eTH=SDRTEXTHORZADJUST_LEFT;
1353 if (eMV==SDRMEASURE_BELOW) eTH=SDRTEXTHORZADJUST_RIGHT;
1354 } else {
1355 if (eMV==SDRMEASURE_ABOVE) eTH=SDRTEXTHORZADJUST_RIGHT;
1356 if (eMV==SDRMEASURE_BELOW) eTH=SDRTEXTHORZADJUST_LEFT;
1358 if (eMV==SDRMEASURETEXT_BREAKEDLINE || eMV==SDRMEASURETEXT_VERTICALCENTERED) eTH=SDRTEXTHORZADJUST_CENTER;
1361 EVAnchorMode eRet=ANCHOR_BOTTOM_HCENTER;
1362 if (eTH==SDRTEXTHORZADJUST_LEFT) {
1363 if (eTV==SDRTEXTVERTADJUST_TOP) eRet=ANCHOR_TOP_LEFT;
1364 else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=ANCHOR_BOTTOM_LEFT;
1365 else eRet=ANCHOR_VCENTER_LEFT;
1366 } else if (eTH==SDRTEXTHORZADJUST_RIGHT) {
1367 if (eTV==SDRTEXTVERTADJUST_TOP) eRet=ANCHOR_TOP_RIGHT;
1368 else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=ANCHOR_BOTTOM_RIGHT;
1369 else eRet=ANCHOR_VCENTER_RIGHT;
1370 } else {
1371 if (eTV==SDRTEXTVERTADJUST_TOP) eRet=ANCHOR_TOP_HCENTER;
1372 else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=ANCHOR_BOTTOM_HCENTER;
1373 else eRet=ANCHOR_VCENTER_HCENTER;
1375 return (sal_uInt16)eRet;
1379 // #i97878#
1380 // TRGetBaseGeometry/TRSetBaseGeometry needs to be based on two positions,
1381 // same as line geometry in SdrPathObj. Thus needs to be overridden and
1382 // implemented since currently it is derived from SdrTextObj which uses
1383 // a functionality based on SnapRect which is not useful here
1385 bool SdrMeasureObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
1387 // handle the same as a simple line since the definition is based on two points
1388 const basegfx::B2DRange aRange(aPt1.X(), aPt1.Y(), aPt2.X(), aPt2.Y());
1389 basegfx::B2DTuple aScale(aRange.getRange());
1390 basegfx::B2DTuple aTranslate(aRange.getMinimum());
1392 // position maybe relative to anchor position, convert
1393 if( pModel->IsWriter() )
1395 if(GetAnchorPos().X() || GetAnchorPos().Y())
1397 aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
1401 // force MapUnit to 100th mm
1402 SfxMapUnit eMapUnit = pModel->GetItemPool().GetMetric(0);
1403 if(eMapUnit != SFX_MAPUNIT_100TH_MM)
1405 switch(eMapUnit)
1407 case SFX_MAPUNIT_TWIP :
1409 // position
1410 aTranslate.setX(ImplTwipsToMM(aTranslate.getX()));
1411 aTranslate.setY(ImplTwipsToMM(aTranslate.getY()));
1413 // size
1414 aScale.setX(ImplTwipsToMM(aScale.getX()));
1415 aScale.setY(ImplTwipsToMM(aScale.getY()));
1417 break;
1419 default:
1421 OSL_FAIL("TRGetBaseGeometry: Missing unit translation to 100th mm!");
1426 // build return value matrix
1427 rMatrix = basegfx::tools::createScaleTranslateB2DHomMatrix(aScale, aTranslate);
1429 return true;
1432 void SdrMeasureObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
1434 // use given transformation to derive the two defining points from unit line
1435 basegfx::B2DPoint aPosA(rMatrix * basegfx::B2DPoint(0.0, 0.0));
1436 basegfx::B2DPoint aPosB(rMatrix * basegfx::B2DPoint(1.0, 0.0));
1438 // force metric to pool metric
1439 SfxMapUnit eMapUnit = pModel->GetItemPool().GetMetric(0);
1440 if(eMapUnit != SFX_MAPUNIT_100TH_MM)
1442 switch(eMapUnit)
1444 case SFX_MAPUNIT_TWIP :
1446 // position
1447 aPosA.setX(ImplMMToTwips(aPosA.getX()));
1448 aPosA.setY(ImplMMToTwips(aPosA.getY()));
1449 aPosB.setX(ImplMMToTwips(aPosB.getX()));
1450 aPosB.setY(ImplMMToTwips(aPosB.getY()));
1452 break;
1454 default:
1456 OSL_FAIL("TRSetBaseGeometry: Missing unit translation to PoolMetric!");
1461 if( pModel->IsWriter() )
1463 // if anchor is used, make position relative to it
1464 if(GetAnchorPos().X() || GetAnchorPos().Y())
1466 const basegfx::B2DVector aAnchorOffset(GetAnchorPos().X(), GetAnchorPos().Y());
1468 aPosA += aAnchorOffset;
1469 aPosB += aAnchorOffset;
1473 // derive new model data
1474 const Point aNewPt1(basegfx::fround(aPosA.getX()), basegfx::fround(aPosA.getY()));
1475 const Point aNewPt2(basegfx::fround(aPosB.getX()), basegfx::fround(aPosB.getY()));
1477 if(aNewPt1 != aPt1 || aNewPt2 != aPt2)
1479 // set model values and broadcast
1480 Rectangle aBoundRect0; if (pUserCall!=NULL) aBoundRect0=GetLastBoundRect();
1482 aPt1 = aNewPt1;
1483 aPt2 = aNewPt2;
1485 SetTextDirty();
1486 ActionChanged();
1487 SetChanged();
1488 BroadcastObjectChange();
1489 SendUserCall(SDRUSERCALL_MOVEONLY,aBoundRect0);
1493 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */