bump product version to 4.1.6.2
[LibreOffice.git] / svx / source / svdraw / svdomeas.cxx
blob02599bb73d4153ee68e199ebbd4948a8f522689b
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 .
21 #include <svx/svdomeas.hxx>
22 #include <math.h>
23 #include <svx/xpoly.hxx>
24 #include <svx/svdtrans.hxx>
25 #include <svx/svdhdl.hxx>
26 #include <svx/svdoutl.hxx>
27 #include <svx/svddrag.hxx>
28 #include <svx/svdpool.hxx>
29 #include <svx/svdattrx.hxx>
30 #include <svx/svdmodel.hxx>
31 #include <svx/svdview.hxx>
32 #include "svx/svdglob.hxx" // StringCache
33 #include "svx/svdstr.hrc" // the object's name
34 #include <svl/style.hxx>
35 #include <svl/smplhint.hxx>
36 #include <editeng/editdata.hxx>
37 #include <editeng/eeitem.hxx>
38 #include <svx/xlnstit.hxx>
39 #include <svx/xlnstwit.hxx>
40 #include <svx/xlnedit.hxx>
41 #include <svx/xlnwtit.hxx>
42 #include <svx/xlnedwit.hxx>
43 #include <svx/xlnstcit.hxx>
44 #include <svx/xlnedcit.hxx>
45 #include <editeng/outlobj.hxx>
46 #include <editeng/outliner.hxx>
47 #include <editeng/editobj.hxx>
48 #include <editeng/measfld.hxx>
49 #include <editeng/flditem.hxx>
50 #include <svx/svdogrp.hxx>
51 #include <svx/svdopath.hxx>
52 #include <svx/svdpage.hxx>
53 #include <unotools/syslocale.hxx>
54 #include <svx/sdr/properties/measureproperties.hxx>
55 #include <svx/sdr/contact/viewcontactofsdrmeasureobj.hxx>
56 #include <basegfx/point/b2dpoint.hxx>
57 #include <basegfx/polygon/b2dpolygon.hxx>
58 #include <basegfx/polygon/b2dpolypolygon.hxx>
59 #include <basegfx/matrix/b2dhommatrix.hxx>
60 #include <basegfx/matrix/b2dhommatrixtools.hxx>
61 #include "svdconv.hxx"
63 ////////////////////////////////////////////////////////////////////////////////////////////////////
65 SdrMeasureObjGeoData::SdrMeasureObjGeoData() {}
66 SdrMeasureObjGeoData::~SdrMeasureObjGeoData() {}
68 void SdrMeasureObj::TakeRepresentation( XubString& rStr, SdrMeasureFieldKind eMeasureFieldKind ) const
70 rStr.Erase();
71 Fraction aMeasureScale(1, 1);
72 sal_Bool bTextRota90(sal_False);
73 sal_Bool bShowUnit(sal_False);
74 FieldUnit eMeasureUnit(FUNIT_NONE);
75 FieldUnit eModUIUnit(FUNIT_NONE);
77 const SfxItemSet& rSet = GetMergedItemSet();
78 bTextRota90 = ((SdrMeasureTextRota90Item&)rSet.Get(SDRATTR_MEASURETEXTROTA90)).GetValue();
79 eMeasureUnit = ((SdrMeasureUnitItem&)rSet.Get(SDRATTR_MEASUREUNIT)).GetValue();
80 aMeasureScale = ((SdrMeasureScaleItem&)rSet.Get(SDRATTR_MEASURESCALE)).GetValue();
81 bShowUnit = ((SdrMeasureShowUnitItem&)rSet.Get(SDRATTR_MEASURESHOWUNIT)).GetValue();
82 sal_Int16 nNumDigits = ((SdrMeasureDecimalPlacesItem&)rSet.Get(SDRATTR_MEASUREDECIMALPLACES)).GetValue();
84 switch(eMeasureFieldKind)
86 case SDRMEASUREFIELD_VALUE:
88 if(pModel)
90 eModUIUnit = pModel->GetUIUnit();
92 if(eMeasureUnit == FUNIT_NONE)
93 eMeasureUnit = eModUIUnit;
95 sal_Int32 nLen(GetLen(aPt2 - aPt1));
96 Fraction aFact(1,1);
98 if(eMeasureUnit != eModUIUnit)
100 // for the unit conversion
101 aFact *= GetMapFactor(eModUIUnit, eMeasureUnit).X();
104 if(aMeasureScale.GetNumerator() != aMeasureScale.GetDenominator())
106 aFact *= aMeasureScale;
109 if(aFact.GetNumerator() != aFact.GetDenominator())
111 // scale via BigInt, to avoid overruns
112 nLen = BigMulDiv(nLen, aFact.GetNumerator(), aFact.GetDenominator());
115 OUString aTmp;
116 pModel->TakeMetricStr(nLen, aTmp, true, nNumDigits);
117 rStr = aTmp;
119 if(!aFact.IsValid())
121 rStr = String();
122 rStr += sal_Unicode('?');
125 sal_Unicode cDec(SvtSysLocale().GetLocaleData().getNumDecimalSep()[0]);
127 if(rStr.Search(cDec) != STRING_NOTFOUND)
129 xub_StrLen nLen2(rStr.Len() - 1);
131 while(rStr.GetChar(nLen2) == sal_Unicode('0'))
133 rStr.Erase(nLen2);
134 nLen2--;
137 if(rStr.GetChar(nLen2) == cDec)
139 rStr.Erase(nLen2);
140 nLen2--;
143 if(!rStr.Len())
144 rStr += sal_Unicode('0');
147 else
149 // if there's no Model ... (e. g. preview in dialog)
150 rStr = String();
151 rStr.AppendAscii("4711");
154 break;
156 case SDRMEASUREFIELD_UNIT:
158 if(bShowUnit)
160 if(pModel)
162 eModUIUnit = pModel->GetUIUnit();
164 if(eMeasureUnit == FUNIT_NONE)
165 eMeasureUnit = eModUIUnit;
167 if(bShowUnit)
168 pModel->TakeUnitStr(eMeasureUnit, rStr);
172 break;
174 case SDRMEASUREFIELD_ROTA90BLANCS:
176 if(bTextRota90)
178 rStr = String();
179 rStr += sal_Unicode(' ');
182 break;
187 //////////////////////////////////////////////////////////////////////////////
188 // BaseProperties section
190 sdr::properties::BaseProperties* SdrMeasureObj::CreateObjectSpecificProperties()
192 return new sdr::properties::MeasureProperties(*this);
195 //////////////////////////////////////////////////////////////////////////////
196 // DrawContact section
198 sdr::contact::ViewContact* SdrMeasureObj::CreateObjectSpecificViewContact()
200 return new sdr::contact::ViewContactOfSdrMeasureObj(*this);
203 //////////////////////////////////////////////////////////////////////////////
205 TYPEINIT1(SdrMeasureObj,SdrTextObj);
207 SdrMeasureObj::SdrMeasureObj():
208 bTextDirty(sal_False)
210 // #i25616#
211 mbSupportTextIndentingOnLineWidthChange = sal_False;
214 SdrMeasureObj::SdrMeasureObj(const Point& rPt1, const Point& rPt2):
215 aPt1(rPt1),
216 aPt2(rPt2),
217 bTextDirty(sal_False)
219 // #i25616#
220 mbSupportTextIndentingOnLineWidthChange = sal_False;
223 SdrMeasureObj::~SdrMeasureObj()
227 void SdrMeasureObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
229 rInfo.bSelectAllowed =sal_True;
230 rInfo.bMoveAllowed =sal_True;
231 rInfo.bResizeFreeAllowed=sal_True;
232 rInfo.bResizePropAllowed=sal_True;
233 rInfo.bRotateFreeAllowed=sal_True;
234 rInfo.bRotate90Allowed =sal_True;
235 rInfo.bMirrorFreeAllowed=sal_True;
236 rInfo.bMirror45Allowed =sal_True;
237 rInfo.bMirror90Allowed =sal_True;
238 rInfo.bTransparenceAllowed = sal_False;
239 rInfo.bGradientAllowed = sal_False;
240 rInfo.bShearAllowed =sal_True;
241 rInfo.bEdgeRadiusAllowed=sal_False;
242 rInfo.bNoOrthoDesired =sal_True;
243 rInfo.bNoContortion =sal_False;
244 rInfo.bCanConvToPath =sal_False;
245 rInfo.bCanConvToPoly =sal_True;
246 rInfo.bCanConvToPathLineToArea=sal_False;
247 rInfo.bCanConvToPolyLineToArea=sal_False;
248 rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
251 sal_uInt16 SdrMeasureObj::GetObjIdentifier() const
253 return (sal_uInt16)OBJ_MEASURE;
256 struct ImpMeasureRec : public SdrDragStatUserData
258 Point aPt1;
259 Point aPt2;
260 SdrMeasureKind eKind;
261 SdrMeasureTextHPos eWantTextHPos;
262 SdrMeasureTextVPos eWantTextVPos;
263 long nLineDist;
264 long nHelplineOverhang;
265 long nHelplineDist;
266 long nHelpline1Len;
267 long nHelpline2Len;
268 bool bBelowRefEdge;
269 bool bTextRota90;
270 bool bTextUpsideDown;
271 long nMeasureOverhang;
272 FieldUnit eMeasureUnit;
273 Fraction aMeasureScale;
274 bool bShowUnit;
275 String aFormatString;
276 bool bTextAutoAngle;
277 long nTextAutoAngleView;
278 bool bTextIsFixedAngle;
279 long nTextFixedAngle;
282 struct ImpLineRec
284 Point aP1;
285 Point aP2;
288 struct ImpMeasurePoly
290 ImpLineRec aMainline1; // those with the 1st arrowhead
291 ImpLineRec aMainline2; // those with the 2nd arrowhead
292 ImpLineRec aMainline3; // those in between
293 ImpLineRec aHelpline1;
294 ImpLineRec aHelpline2;
295 Rectangle aTextRect;
296 Size aTextSize;
297 long nLineLen;
298 long nLineWink;
299 long nTextWink;
300 long nHlpWink;
301 double nLineSin;
302 double nLineCos;
303 double nHlpSin;
304 double nHlpCos;
305 sal_uInt16 nMainlineAnz;
306 SdrMeasureTextHPos eUsedTextHPos;
307 SdrMeasureTextVPos eUsedTextVPos;
308 long nLineWdt2; // half the line width
309 long nArrow1Len; // length of 1st arrowhead; for Center, use only half
310 long nArrow2Len; // length of 2nd arrowhead; for Center, use only half
311 long nArrow1Wdt; // width of 1st arrow
312 long nArrow2Wdt; // width of 2nd arrow
313 long nShortLineLen; // line length, if PfeileAussen (arrowheads on the outside)
314 bool bArrow1Center; // arrowhead 1 centered?
315 bool bArrow2Center; // arrowhead 2 centered?
316 bool bAutoUpsideDown; // UpsideDown via automation
317 bool bPfeileAussen; // arrowheads on the outside
318 bool bBreakedLine;
321 void SdrMeasureObj::ImpTakeAttr(ImpMeasureRec& rRec) const
323 rRec.aPt1 = aPt1;
324 rRec.aPt2 = aPt2;
326 const SfxItemSet& rSet = GetObjectItemSet();
327 rRec.eKind =((SdrMeasureKindItem& )rSet.Get(SDRATTR_MEASUREKIND )).GetValue();
328 rRec.eWantTextHPos =((SdrMeasureTextHPosItem& )rSet.Get(SDRATTR_MEASURETEXTHPOS )).GetValue();
329 rRec.eWantTextVPos =((SdrMeasureTextVPosItem& )rSet.Get(SDRATTR_MEASURETEXTVPOS )).GetValue();
330 rRec.nLineDist =((SdrMeasureLineDistItem& )rSet.Get(SDRATTR_MEASURELINEDIST )).GetValue();
331 rRec.nHelplineOverhang=((SdrMeasureHelplineOverhangItem&)rSet.Get(SDRATTR_MEASUREHELPLINEOVERHANG)).GetValue();
332 rRec.nHelplineDist =((SdrMeasureHelplineDistItem& )rSet.Get(SDRATTR_MEASUREHELPLINEDIST )).GetValue();
333 rRec.nHelpline1Len =((SdrMeasureHelpline1LenItem& )rSet.Get(SDRATTR_MEASUREHELPLINE1LEN )).GetValue();
334 rRec.nHelpline2Len =((SdrMeasureHelpline2LenItem& )rSet.Get(SDRATTR_MEASUREHELPLINE2LEN )).GetValue();
335 rRec.bBelowRefEdge =((SdrMeasureBelowRefEdgeItem& )rSet.Get(SDRATTR_MEASUREBELOWREFEDGE )).GetValue();
336 rRec.bTextRota90 =((SdrMeasureTextRota90Item& )rSet.Get(SDRATTR_MEASURETEXTROTA90 )).GetValue();
337 rRec.bTextUpsideDown =((SdrMeasureTextUpsideDownItem& )rSet.Get(SDRATTR_MEASURETEXTUPSIDEDOWN )).GetValue();
338 rRec.nMeasureOverhang =((SdrMeasureOverhangItem& )rSet.Get(SDRATTR_MEASUREOVERHANG )).GetValue();
339 rRec.eMeasureUnit =((SdrMeasureUnitItem& )rSet.Get(SDRATTR_MEASUREUNIT )).GetValue();
340 rRec.aMeasureScale =((SdrMeasureScaleItem& )rSet.Get(SDRATTR_MEASURESCALE )).GetValue();
341 rRec.bShowUnit =((SdrMeasureShowUnitItem& )rSet.Get(SDRATTR_MEASURESHOWUNIT )).GetValue();
342 rRec.aFormatString =((SdrMeasureFormatStringItem& )rSet.Get(SDRATTR_MEASUREFORMATSTRING )).GetValue();
343 rRec.bTextAutoAngle =((SdrMeasureTextAutoAngleItem& )rSet.Get(SDRATTR_MEASURETEXTAUTOANGLE )).GetValue();
344 rRec.nTextAutoAngleView=((SdrMeasureTextAutoAngleViewItem&)rSet.Get(SDRATTR_MEASURETEXTAUTOANGLEVIEW)).GetValue();
345 rRec.bTextIsFixedAngle =((SdrMeasureTextIsFixedAngleItem& )rSet.Get(SDRATTR_MEASURETEXTISFIXEDANGLE )).GetValue();
346 rRec.nTextFixedAngle =((SdrMeasureTextFixedAngleItem& )rSet.Get(SDRATTR_MEASURETEXTFIXEDANGLE )).GetValue();
349 long impGetLineStartEndDistance(const basegfx::B2DPolyPolygon& rPolyPolygon, long nNewWidth, bool bCenter)
351 const basegfx::B2DRange aPolygonRange(rPolyPolygon.getB2DRange());
352 const double fOldWidth(aPolygonRange.getWidth() > 1.0 ? aPolygonRange.getWidth() : 1.0);
353 const double fScale((double)nNewWidth / fOldWidth);
354 long nHeight(basegfx::fround(aPolygonRange.getHeight() * fScale));
356 if(bCenter)
358 nHeight /= 2L;
361 return nHeight;
364 void SdrMeasureObj::ImpCalcGeometrics(const ImpMeasureRec& rRec, ImpMeasurePoly& rPol) const
366 Point aP1(rRec.aPt1);
367 Point aP2(rRec.aPt2);
368 Point aDelt(aP2); aDelt-=aP1;
370 rPol.aTextSize=GetTextSize();
371 rPol.nLineLen=GetLen(aDelt);
373 rPol.nLineWdt2=0;
374 long nArrow1Len=0; bool bArrow1Center=false;
375 long nArrow2Len=0; bool bArrow2Center=false;
376 long nArrow1Wdt=0;
377 long nArrow2Wdt=0;
378 rPol.nArrow1Wdt=0;
379 rPol.nArrow2Wdt=0;
380 long nArrowNeed=0;
381 long nShortLen=0;
382 bool bPfeileAussen = false;
384 const SfxItemSet& rSet = GetObjectItemSet();
385 sal_Int32 nLineWdt = ((XLineWidthItem&)(rSet.Get(XATTR_LINEWIDTH))).GetValue(); // line width
386 rPol.nLineWdt2 = (nLineWdt + 1) / 2;
388 nArrow1Wdt = ((const XLineStartWidthItem&)(rSet.Get(XATTR_LINESTARTWIDTH))).GetValue();
389 if(nArrow1Wdt < 0)
390 nArrow1Wdt = -nLineWdt * nArrow1Wdt / 100; // <0 = relativ
392 nArrow2Wdt = ((const XLineEndWidthItem&)(rSet.Get(XATTR_LINEENDWIDTH))).GetValue();
393 if(nArrow2Wdt < 0)
394 nArrow2Wdt = -nLineWdt * nArrow2Wdt / 100; // <0 = relativ
396 basegfx::B2DPolyPolygon aPol1(((const XLineStartItem&)(rSet.Get(XATTR_LINESTART))).GetLineStartValue());
397 basegfx::B2DPolyPolygon aPol2(((const XLineEndItem&)(rSet.Get(XATTR_LINEEND))).GetLineEndValue());
398 bArrow1Center = ((const XLineStartCenterItem&)(rSet.Get(XATTR_LINESTARTCENTER))).GetValue();
399 bArrow2Center = ((const XLineEndCenterItem&)(rSet.Get(XATTR_LINEENDCENTER))).GetValue();
400 nArrow1Len = impGetLineStartEndDistance(aPol1, nArrow1Wdt, bArrow1Center) - 1;
401 nArrow2Len = impGetLineStartEndDistance(aPol2, nArrow2Wdt, bArrow2Center) - 1;
403 // nArrowLen is already halved at bCenter.
404 // In the case of 2 arrowheads each 4mm long, we can't go below 10mm.
405 nArrowNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2;
406 if (rPol.nLineLen<nArrowNeed) bPfeileAussen = true;
407 nShortLen=(nArrow1Len+nArrow1Wdt + nArrow2Len+nArrow2Wdt) /2;
409 rPol.eUsedTextHPos=rRec.eWantTextHPos;
410 rPol.eUsedTextVPos=rRec.eWantTextVPos;
411 if (rPol.eUsedTextVPos==SDRMEASURE_TEXTVAUTO) rPol.eUsedTextVPos=SDRMEASURE_ABOVE;
412 bool bBrkLine=rPol.eUsedTextVPos==SDRMEASURETEXT_BREAKEDLINE;
413 if (rPol.eUsedTextVPos==SDRMEASURETEXT_VERTICALCENTERED)
415 OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
416 if (pOutlinerParaObject!=NULL && pOutlinerParaObject->GetTextObject().GetParagraphCount()==1)
418 bBrkLine=sal_True; // dashed line if there's only on paragraph.
421 rPol.bBreakedLine=bBrkLine;
422 if (rPol.eUsedTextHPos==SDRMEASURE_TEXTHAUTO) { // if text is too wide, push it outside
423 bool bOutside = false;
424 long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
425 if (nNeedSiz>rPol.nLineLen) bOutside = true; // text doesn't fit in between
426 if (bBrkLine) {
427 if (nNeedSiz+nArrowNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
428 } else {
429 long nSmallNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2/4;
430 if (nNeedSiz+nSmallNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
432 rPol.eUsedTextHPos=bOutside ? SDRMEASURE_TEXTLEFTOUTSIDE : SDRMEASURE_TEXTINSIDE;
434 if (rPol.eUsedTextHPos!=SDRMEASURE_TEXTINSIDE) bPfeileAussen = true;
435 rPol.nArrow1Wdt=nArrow1Wdt;
436 rPol.nArrow2Wdt=nArrow2Wdt;
437 rPol.nShortLineLen=nShortLen;
438 rPol.bPfeileAussen=bPfeileAussen;
439 rPol.nArrow1Len=nArrow1Len;
440 rPol.bArrow1Center=bArrow1Center;
441 rPol.nArrow2Len=nArrow2Len;
442 rPol.bArrow2Center=bArrow2Center;
444 rPol.nLineWink=GetAngle(aDelt);
445 double a=rPol.nLineWink*nPi180;
446 double nLineSin=sin(a);
447 double nLineCos=cos(a);
448 rPol.nLineSin=nLineSin;
449 rPol.nLineCos=nLineCos;
451 rPol.nTextWink=rPol.nLineWink;
452 if (rRec.bTextRota90) rPol.nTextWink+=9000;
454 rPol.bAutoUpsideDown=sal_False;
455 if (rRec.bTextAutoAngle) {
456 long nTmpWink=NormAngle360(rPol.nTextWink-rRec.nTextAutoAngleView);
457 if (nTmpWink>=18000) {
458 rPol.nTextWink+=18000;
459 rPol.bAutoUpsideDown=sal_True;
463 if (rRec.bTextUpsideDown) rPol.nTextWink+=18000;
464 rPol.nTextWink=NormAngle360(rPol.nTextWink);
465 rPol.nHlpWink=rPol.nLineWink+9000;
466 if (rRec.bBelowRefEdge) rPol.nHlpWink+=18000;
467 rPol.nHlpWink=NormAngle360(rPol.nHlpWink);
468 double nHlpSin=nLineCos;
469 double nHlpCos=-nLineSin;
470 if (rRec.bBelowRefEdge) {
471 nHlpSin=-nHlpSin;
472 nHlpCos=-nHlpCos;
474 rPol.nHlpSin=nHlpSin;
475 rPol.nHlpCos=nHlpCos;
477 long nLineDist=rRec.nLineDist;
478 long nOverhang=rRec.nHelplineOverhang;
479 long nHelplineDist=rRec.nHelplineDist;
481 long dx= Round(nLineDist*nHlpCos);
482 long dy=-Round(nLineDist*nHlpSin);
483 long dxh1a= Round((nHelplineDist-rRec.nHelpline1Len)*nHlpCos);
484 long dyh1a=-Round((nHelplineDist-rRec.nHelpline1Len)*nHlpSin);
485 long dxh1b= Round((nHelplineDist-rRec.nHelpline2Len)*nHlpCos);
486 long dyh1b=-Round((nHelplineDist-rRec.nHelpline2Len)*nHlpSin);
487 long dxh2= Round((nLineDist+nOverhang)*nHlpCos);
488 long dyh2=-Round((nLineDist+nOverhang)*nHlpSin);
490 // extension line 1
491 rPol.aHelpline1.aP1=Point(aP1.X()+dxh1a,aP1.Y()+dyh1a);
492 rPol.aHelpline1.aP2=Point(aP1.X()+dxh2,aP1.Y()+dyh2);
494 // extension line 2
495 rPol.aHelpline2.aP1=Point(aP2.X()+dxh1b,aP2.Y()+dyh1b);
496 rPol.aHelpline2.aP2=Point(aP2.X()+dxh2,aP2.Y()+dyh2);
498 // dimension line
499 Point aMainlinePt1(aP1.X()+dx,aP1.Y()+dy);
500 Point aMainlinePt2(aP2.X()+dx,aP2.Y()+dy);
501 if (!bPfeileAussen) {
502 rPol.aMainline1.aP1=aMainlinePt1;
503 rPol.aMainline1.aP2=aMainlinePt2;
504 rPol.aMainline2=rPol.aMainline1;
505 rPol.aMainline3=rPol.aMainline1;
506 rPol.nMainlineAnz=1;
507 if (bBrkLine) {
508 long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
509 long nHalfLen=(rPol.nLineLen-nNeedSiz-nArrow1Wdt/4-nArrow2Wdt/4) /2;
510 rPol.nMainlineAnz=2;
511 rPol.aMainline1.aP2=aMainlinePt1;
512 rPol.aMainline1.aP2.X()+=nHalfLen;
513 RotatePoint(rPol.aMainline1.aP2,rPol.aMainline1.aP1,nLineSin,nLineCos);
514 rPol.aMainline2.aP1=aMainlinePt2;
515 rPol.aMainline2.aP1.X()-=nHalfLen;
516 RotatePoint(rPol.aMainline2.aP1,rPol.aMainline2.aP2,nLineSin,nLineCos);
518 } else {
519 long nLen1=nShortLen; // arrowhead's width as line length outside of the arrowhead
520 long nLen2=nShortLen;
521 long nTextWdt=rRec.bTextRota90 ? rPol.aTextSize.Height() : rPol.aTextSize.Width();
522 if (!bBrkLine) {
523 if (rPol.eUsedTextHPos==SDRMEASURE_TEXTLEFTOUTSIDE) nLen1=nArrow1Len+nTextWdt;
524 if (rPol.eUsedTextHPos==SDRMEASURE_TEXTRIGHTOUTSIDE) nLen2=nArrow2Len+nTextWdt;
526 rPol.aMainline1.aP1=aMainlinePt1;
527 rPol.aMainline1.aP2=aMainlinePt1; rPol.aMainline1.aP2.X()-=nLen1; RotatePoint(rPol.aMainline1.aP2,aMainlinePt1,nLineSin,nLineCos);
528 rPol.aMainline2.aP1=aMainlinePt2; rPol.aMainline2.aP1.X()+=nLen2; RotatePoint(rPol.aMainline2.aP1,aMainlinePt2,nLineSin,nLineCos);
529 rPol.aMainline2.aP2=aMainlinePt2;
530 rPol.aMainline3.aP1=aMainlinePt1;
531 rPol.aMainline3.aP2=aMainlinePt2;
532 rPol.nMainlineAnz=3;
533 if (bBrkLine && rPol.eUsedTextHPos==SDRMEASURE_TEXTINSIDE) rPol.nMainlineAnz=2;
537 basegfx::B2DPolyPolygon SdrMeasureObj::ImpCalcXPoly(const ImpMeasurePoly& rPol) const
539 basegfx::B2DPolyPolygon aRetval;
540 basegfx::B2DPolygon aPartPolyA;
541 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP1.X(), rPol.aMainline1.aP1.Y()));
542 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP2.X(), rPol.aMainline1.aP2.Y()));
543 aRetval.append(aPartPolyA);
545 if(rPol.nMainlineAnz > 1)
547 aPartPolyA.clear();
548 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP1.X(), rPol.aMainline2.aP1.Y()));
549 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP2.X(), rPol.aMainline2.aP2.Y()));
550 aRetval.append(aPartPolyA);
553 if(rPol.nMainlineAnz > 2)
555 aPartPolyA.clear();
556 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP1.X(), rPol.aMainline3.aP1.Y()));
557 aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP2.X(), rPol.aMainline3.aP2.Y()));
558 aRetval.append(aPartPolyA);
561 aPartPolyA.clear();
562 aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP1.X(), rPol.aHelpline1.aP1.Y()));
563 aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP2.X(), rPol.aHelpline1.aP2.Y()));
564 aRetval.append(aPartPolyA);
566 aPartPolyA.clear();
567 aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP1.X(), rPol.aHelpline2.aP1.Y()));
568 aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP2.X(), rPol.aHelpline2.aP2.Y()));
569 aRetval.append(aPartPolyA);
571 return aRetval;
574 bool SdrMeasureObj::CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_uInt16 nPos,
575 bool bEdit,
576 Color*& rpTxtColor, Color*& rpFldColor, XubString& rRet) const
578 const SvxFieldData* pField=rField.GetField();
579 SdrMeasureField* pMeasureField=PTR_CAST(SdrMeasureField,pField);
580 if (pMeasureField!=NULL) {
581 TakeRepresentation(rRet, pMeasureField->GetMeasureFieldKind());
582 if (rpFldColor!=NULL) {
583 if (!bEdit)
585 delete rpFldColor;
586 rpFldColor=NULL;
589 return sal_True;
590 } else {
591 return SdrTextObj::CalcFieldValue(rField,nPara,nPos,bEdit,rpTxtColor,rpFldColor,rRet);
595 void SdrMeasureObj::UndirtyText() const
597 if (bTextDirty)
599 SdrOutliner& rOutliner=ImpGetDrawOutliner();
600 OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
601 if(pOutlinerParaObject==NULL)
603 rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_ROTA90BLANCS), EE_FEATURE_FIELD), ESelection(0,0));
604 rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_VALUE), EE_FEATURE_FIELD),ESelection(0,1));
605 rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_UNIT), EE_FEATURE_FIELD),ESelection(0,2));
606 rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_ROTA90BLANCS), EE_FEATURE_FIELD),ESelection(0,3));
608 if(GetStyleSheet())
609 rOutliner.SetStyleSheet(0, GetStyleSheet());
611 rOutliner.SetParaAttribs(0, GetObjectItemSet());
613 // cast to nonconst
614 const_cast<SdrMeasureObj*>(this)->NbcSetOutlinerParaObject( rOutliner.CreateParaObject() );
616 else
618 rOutliner.SetText(*pOutlinerParaObject);
621 rOutliner.SetUpdateMode(sal_True);
622 rOutliner.UpdateFields();
623 Size aSiz(rOutliner.CalcTextSize());
624 rOutliner.Clear();
625 // cast to nonconst three times
626 ((SdrMeasureObj*)this)->aTextSize=aSiz;
627 ((SdrMeasureObj*)this)->bTextSizeDirty=sal_False;
628 ((SdrMeasureObj*)this)->bTextDirty=sal_False;
632 void SdrMeasureObj::TakeUnrotatedSnapRect(Rectangle& rRect) const
634 if (bTextDirty) UndirtyText();
635 ImpMeasureRec aRec;
636 ImpMeasurePoly aMPol;
637 ImpTakeAttr(aRec);
638 ImpCalcGeometrics(aRec,aMPol);
640 // determine TextSize including text frame margins
641 Size aTextSize2(aMPol.aTextSize);
642 if (aTextSize2.Width()<1) aTextSize2.Width()=1;
643 if (aTextSize2.Height()<1) aTextSize2.Height()=1;
644 aTextSize2.Width()+=GetTextLeftDistance()+GetTextRightDistance();
645 aTextSize2.Height()+=GetTextUpperDistance()+GetTextLowerDistance();
647 Point aPt1b(aMPol.aMainline1.aP1);
648 long nLen=aMPol.nLineLen;
649 long nLWdt=aMPol.nLineWdt2;
650 long nArr1Len=aMPol.nArrow1Len;
651 long nArr2Len=aMPol.nArrow2Len;
652 if (aMPol.bBreakedLine) {
653 // In the case of a dashed line and Outside, the text should be
654 // placed next to the line at the arrowhead instead of directly
655 // at the arrowhead.
656 nArr1Len=aMPol.nShortLineLen+aMPol.nArrow1Wdt/4;
657 nArr2Len=aMPol.nShortLineLen+aMPol.nArrow2Wdt/4;
660 Point aTextPos;
661 bool bRota90=aRec.bTextRota90;
662 bool bUpsideDown=aRec.bTextUpsideDown!=aMPol.bAutoUpsideDown;
663 bool bBelowRefEdge=aRec.bBelowRefEdge;
664 SdrMeasureTextHPos eMH=aMPol.eUsedTextHPos;
665 SdrMeasureTextVPos eMV=aMPol.eUsedTextVPos;
666 if (!bRota90) {
667 switch (eMH) {
668 case SDRMEASURE_TEXTLEFTOUTSIDE: aTextPos.X()=aPt1b.X()-aTextSize2.Width()-nArr1Len-nLWdt; break;
669 case SDRMEASURE_TEXTRIGHTOUTSIDE: aTextPos.X()=aPt1b.X()+nLen+nArr2Len+nLWdt; break;
670 default: aTextPos.X()=aPt1b.X(); aTextSize2.Width()=nLen;
672 switch (eMV) {
673 case SDRMEASURETEXT_VERTICALCENTERED:
674 case SDRMEASURETEXT_BREAKEDLINE: aTextPos.Y()=aPt1b.Y()-aTextSize2.Height()/2; break;
675 case SDRMEASURE_BELOW: {
676 if (!bUpsideDown) aTextPos.Y()=aPt1b.Y()+nLWdt;
677 else aTextPos.Y()=aPt1b.Y()-aTextSize2.Height()-nLWdt;
678 } break;
679 default: {
680 if (!bUpsideDown) aTextPos.Y()=aPt1b.Y()-aTextSize2.Height()-nLWdt;
681 else aTextPos.Y()=aPt1b.Y()+nLWdt;
684 if (bUpsideDown) {
685 aTextPos.X()+=aTextSize2.Width();
686 aTextPos.Y()+=aTextSize2.Height();
688 } else { // also if bTextRota90==TRUE
689 switch (eMH) {
690 case SDRMEASURE_TEXTLEFTOUTSIDE: aTextPos.X()=aPt1b.X()-aTextSize2.Height()-nArr1Len; break;
691 case SDRMEASURE_TEXTRIGHTOUTSIDE: aTextPos.X()=aPt1b.X()+nLen+nArr2Len; break;
692 default: aTextPos.X()=aPt1b.X(); aTextSize2.Height()=nLen;
694 switch (eMV) {
695 case SDRMEASURETEXT_VERTICALCENTERED:
696 case SDRMEASURETEXT_BREAKEDLINE: aTextPos.Y()=aPt1b.Y()+aTextSize2.Width()/2; break;
697 case SDRMEASURE_BELOW: {
698 if (!bBelowRefEdge) aTextPos.Y()=aPt1b.Y()+aTextSize2.Width()+nLWdt;
699 else aTextPos.Y()=aPt1b.Y()-nLWdt;
700 } break;
701 default: {
702 if (!bBelowRefEdge) aTextPos.Y()=aPt1b.Y()-nLWdt;
703 else aTextPos.Y()=aPt1b.Y()+aTextSize2.Width()+nLWdt;
706 if (bUpsideDown) {
707 aTextPos.X()+=aTextSize2.Height();
708 aTextPos.Y()-=aTextSize2.Width();
711 if (aMPol.nTextWink!=aGeo.nDrehWink) {
712 ((SdrMeasureObj*)this)->aGeo.nDrehWink=aMPol.nTextWink;
713 ((SdrMeasureObj*)this)->aGeo.RecalcSinCos();
715 RotatePoint(aTextPos,aPt1b,aMPol.nLineSin,aMPol.nLineCos);
716 aTextSize2.Width()++; aTextSize2.Height()++; // because of the Rect-Ctor's odd behavior
717 rRect=Rectangle(aTextPos,aTextSize2);
718 rRect.Justify();
719 ((SdrMeasureObj*)this)->aRect=rRect;
721 if (aMPol.nTextWink!=aGeo.nDrehWink) {
722 ((SdrMeasureObj*)this)->aGeo.nDrehWink=aMPol.nTextWink;
723 ((SdrMeasureObj*)this)->aGeo.RecalcSinCos();
727 SdrMeasureObj* SdrMeasureObj::Clone() const
729 return CloneHelper< SdrMeasureObj >();
732 void SdrMeasureObj::TakeObjNameSingul(XubString& rName) const
734 rName=ImpGetResStr(STR_ObjNameSingulMEASURE);
736 String aName( GetName() );
737 if(aName.Len())
739 rName += sal_Unicode(' ');
740 rName += sal_Unicode('\'');
741 rName += aName;
742 rName += sal_Unicode('\'');
746 void SdrMeasureObj::TakeObjNamePlural(XubString& rName) const
748 rName=ImpGetResStr(STR_ObjNamePluralMEASURE);
751 basegfx::B2DPolyPolygon SdrMeasureObj::TakeXorPoly() const
753 ImpMeasureRec aRec;
754 ImpMeasurePoly aMPol;
755 ImpTakeAttr(aRec);
756 ImpCalcGeometrics(aRec,aMPol);
757 return ImpCalcXPoly(aMPol);
760 sal_uInt32 SdrMeasureObj::GetHdlCount() const
762 return 6L;
765 SdrHdl* SdrMeasureObj::GetHdl(sal_uInt32 nHdlNum) const
767 ImpMeasureRec aRec;
768 ImpMeasurePoly aMPol;
769 ImpTakeAttr(aRec);
770 aRec.nHelplineDist=0;
771 ImpCalcGeometrics(aRec,aMPol);
772 Point aPt;
774 switch (nHdlNum) {
775 case 0: aPt=aMPol.aHelpline1.aP1; break;
776 case 1: aPt=aMPol.aHelpline2.aP1; break;
777 case 2: aPt=aPt1; break;
778 case 3: aPt=aPt2; break;
779 case 4: aPt=aMPol.aHelpline1.aP2; break;
780 case 5: aPt=aMPol.aHelpline2.aP2; break;
781 } // switch
782 SdrHdl* pHdl=new ImpMeasureHdl(aPt,HDL_USER);
783 pHdl->SetObjHdlNum(nHdlNum);
784 pHdl->SetDrehWink(aMPol.nLineWink);
785 return pHdl;
788 ////////////////////////////////////////////////////////////////////////////////////////////////////
790 bool SdrMeasureObj::hasSpecialDrag() const
792 return true;
795 bool SdrMeasureObj::beginSpecialDrag(SdrDragStat& rDrag) const
797 const SdrHdl* pHdl = rDrag.GetHdl();
799 if(pHdl)
801 const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
803 if(nHdlNum != 2 && nHdlNum != 3)
805 rDrag.SetEndDragChangesAttributes(true);
808 return true;
811 return false;
814 bool SdrMeasureObj::applySpecialDrag(SdrDragStat& rDrag)
816 ImpMeasureRec aMeasureRec;
817 const SdrHdl* pHdl = rDrag.GetHdl();
818 const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
820 ImpTakeAttr(aMeasureRec);
821 ImpEvalDrag(aMeasureRec, rDrag);
823 switch (nHdlNum)
825 case 2:
827 aPt1 = aMeasureRec.aPt1;
828 SetTextDirty();
829 break;
831 case 3:
833 aPt2 = aMeasureRec.aPt2;
834 SetTextDirty();
835 break;
837 default:
839 switch(nHdlNum)
841 case 0:
842 case 1:
844 ImpMeasureRec aOrigMeasureRec;
845 ImpTakeAttr(aOrigMeasureRec);
847 if(aMeasureRec.nHelpline1Len != aOrigMeasureRec.nHelpline1Len)
849 SetObjectItem(SdrMeasureHelpline1LenItem(aMeasureRec.nHelpline1Len));
852 if(aMeasureRec.nHelpline2Len != aOrigMeasureRec.nHelpline2Len)
854 SetObjectItem(SdrMeasureHelpline2LenItem(aMeasureRec.nHelpline2Len));
857 break;
860 case 4:
861 case 5:
863 ImpMeasureRec aOrigMeasureRec;
864 ImpTakeAttr(aOrigMeasureRec);
866 if(aMeasureRec.nLineDist != aOrigMeasureRec.nLineDist)
868 SetObjectItem(SdrMeasureLineDistItem(aMeasureRec.nLineDist));
871 if(aMeasureRec.bBelowRefEdge != aOrigMeasureRec.bBelowRefEdge)
873 SetObjectItem(SdrMeasureBelowRefEdgeItem(aMeasureRec.bBelowRefEdge));
878 } // switch
880 SetRectsDirty();
881 SetChanged();
883 return true;
886 String SdrMeasureObj::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
888 XubString aStr;
889 return aStr;
892 void SdrMeasureObj::ImpEvalDrag(ImpMeasureRec& rRec, const SdrDragStat& rDrag) const
894 long nLineWink=GetAngle(rRec.aPt2-rRec.aPt1);
895 double a=nLineWink*nPi180;
896 double nSin=sin(a);
897 double nCos=cos(a);
899 const SdrHdl* pHdl=rDrag.GetHdl();
900 sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
901 bool bOrtho=rDrag.GetView()!=NULL && rDrag.GetView()->IsOrtho();
902 bool bBigOrtho=bOrtho && rDrag.GetView()->IsBigOrtho();
903 bool bBelow=rRec.bBelowRefEdge;
904 Point aPt(rDrag.GetNow());
906 switch (nHdlNum) {
907 case 0: {
908 RotatePoint(aPt,aPt1,nSin,-nCos);
909 rRec.nHelpline1Len=aPt1.Y()-aPt.Y();
910 if (bBelow) rRec.nHelpline1Len=-rRec.nHelpline1Len;
911 if (bOrtho) rRec.nHelpline2Len=rRec.nHelpline1Len;
912 } break;
913 case 1: {
914 RotatePoint(aPt,aPt2,nSin,-nCos);
915 rRec.nHelpline2Len=aPt2.Y()-aPt.Y();
916 if (bBelow) rRec.nHelpline2Len=-rRec.nHelpline2Len;
917 if (bOrtho) rRec.nHelpline1Len=rRec.nHelpline2Len;
918 } break;
919 case 2: case 3: {
920 bool bAnf=nHdlNum==2;
921 Point& rMov=bAnf ? rRec.aPt1 : rRec.aPt2;
922 Point aMov(rMov);
923 Point aFix(bAnf ? rRec.aPt2 : rRec.aPt1);
924 if (bOrtho) {
925 long ndx0=aMov.X()-aFix.X();
926 long ndy0=aMov.Y()-aFix.Y();
927 bool bHLin=ndy0==0;
928 bool bVLin=ndx0==0;
929 if (!bHLin || !bVLin) { // else aPt1==aPt2
930 long ndx=aPt.X()-aFix.X();
931 long ndy=aPt.Y()-aFix.Y();
932 double nXFact=0; if (!bVLin) nXFact=(double)ndx/(double)ndx0;
933 double nYFact=0; if (!bHLin) nYFact=(double)ndy/(double)ndy0;
934 bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
935 bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
936 if (bHor) ndy=long(ndy0*nXFact);
937 if (bVer) ndx=long(ndx0*nYFact);
938 aPt=aFix;
939 aPt.X()+=ndx;
940 aPt.Y()+=ndy;
941 } // else Ortho8
943 rMov=aPt;
944 } break;
945 case 4: case 5: {
946 long nVal0=rRec.nLineDist;
947 RotatePoint(aPt,(nHdlNum==4 ? aPt1 : aPt2),nSin,-nCos);
948 rRec.nLineDist=aPt.Y()- (nHdlNum==4 ? aPt1.Y() : aPt2.Y());
949 if (bBelow) rRec.nLineDist=-rRec.nLineDist;
950 if (rRec.nLineDist<0) {
951 rRec.nLineDist=-rRec.nLineDist;
952 rRec.bBelowRefEdge=!bBelow;
954 rRec.nLineDist-=rRec.nHelplineOverhang;
955 if (bOrtho) rRec.nLineDist=nVal0;
956 } break;
957 } // switch
960 ////////////////////////////////////////////////////////////////////////////////////////////////////
962 bool SdrMeasureObj::BegCreate(SdrDragStat& rStat)
964 rStat.SetOrtho8Possible();
965 aPt1=rStat.GetStart();
966 aPt2=rStat.GetNow();
967 SetTextDirty();
968 return sal_True;
971 bool SdrMeasureObj::MovCreate(SdrDragStat& rStat)
973 SdrView* pView=rStat.GetView();
974 aPt1=rStat.GetStart();
975 aPt2=rStat.GetNow();
976 if (pView!=NULL && pView->IsCreate1stPointAsCenter()) {
977 aPt1+=aPt1;
978 aPt1-=rStat.Now();
980 SetTextDirty();
981 SetBoundRectDirty();
982 bSnapRectDirty=sal_True;
983 return sal_True;
986 bool SdrMeasureObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
988 SetTextDirty();
989 SetRectsDirty();
990 return (eCmd==SDRCREATE_FORCEEND || rStat.GetPointAnz()>=2);
993 bool SdrMeasureObj::BckCreate(SdrDragStat& /*rStat*/)
995 return false;
998 void SdrMeasureObj::BrkCreate(SdrDragStat& /*rStat*/)
1002 basegfx::B2DPolyPolygon SdrMeasureObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
1004 ImpMeasureRec aRec;
1005 ImpMeasurePoly aMPol;
1007 ImpTakeAttr(aRec);
1008 ImpCalcGeometrics(aRec, aMPol);
1010 return ImpCalcXPoly(aMPol);
1013 Pointer SdrMeasureObj::GetCreatePointer() const
1015 return Pointer(POINTER_CROSS);
1018 void SdrMeasureObj::NbcMove(const Size& rSiz)
1020 SdrTextObj::NbcMove(rSiz);
1021 MovePoint(aPt1,rSiz);
1022 MovePoint(aPt2,rSiz);
1025 void SdrMeasureObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
1027 SdrTextObj::NbcResize(rRef,xFact,yFact);
1028 ResizePoint(aPt1,rRef,xFact,yFact);
1029 ResizePoint(aPt2,rRef,xFact,yFact);
1030 SetTextDirty();
1033 void SdrMeasureObj::NbcRotate(const Point& rRef, long nWink, double sn, double cs)
1035 SdrTextObj::NbcRotate(rRef,nWink,sn,cs);
1036 long nLen0=GetLen(aPt2-aPt1);
1037 RotatePoint(aPt1,rRef,sn,cs);
1038 RotatePoint(aPt2,rRef,sn,cs);
1039 long nLen1=GetLen(aPt2-aPt1);
1040 if (nLen1!=nLen0) { // rounding error!
1041 long dx=aPt2.X()-aPt1.X();
1042 long dy=aPt2.Y()-aPt1.Y();
1043 dx=BigMulDiv(dx,nLen0,nLen1);
1044 dy=BigMulDiv(dy,nLen0,nLen1);
1045 if (rRef==aPt2) {
1046 aPt1.X()=aPt2.X()-dx;
1047 aPt1.Y()=aPt2.Y()-dy;
1048 } else {
1049 aPt2.X()=aPt1.X()+dx;
1050 aPt2.Y()=aPt1.Y()+dy;
1053 SetRectsDirty();
1056 void SdrMeasureObj::NbcMirror(const Point& rRef1, const Point& rRef2)
1058 SdrTextObj::NbcMirror(rRef1,rRef2);
1059 MirrorPoint(aPt1,rRef1,rRef2);
1060 MirrorPoint(aPt2,rRef1,rRef2);
1061 SetRectsDirty();
1064 void SdrMeasureObj::NbcShear(const Point& rRef, long nWink, double tn, bool bVShear)
1066 SdrTextObj::NbcShear(rRef,nWink,tn,bVShear);
1067 ShearPoint(aPt1,rRef,tn,bVShear);
1068 ShearPoint(aPt2,rRef,tn,bVShear);
1069 SetRectsDirty();
1070 SetTextDirty();
1073 long SdrMeasureObj::GetRotateAngle() const
1075 return GetAngle(aPt2-aPt1);
1078 void SdrMeasureObj::RecalcSnapRect()
1080 ImpMeasureRec aRec;
1081 ImpMeasurePoly aMPol;
1082 XPolyPolygon aXPP;
1084 ImpTakeAttr(aRec);
1085 ImpCalcGeometrics(aRec, aMPol);
1086 aXPP = XPolyPolygon(ImpCalcXPoly(aMPol));
1087 maSnapRect = aXPP.GetBoundRect();
1090 sal_uInt32 SdrMeasureObj::GetSnapPointCount() const
1092 return 2L;
1095 Point SdrMeasureObj::GetSnapPoint(sal_uInt32 i) const
1097 if (i==0) return aPt1;
1098 else return aPt2;
1101 sal_Bool SdrMeasureObj::IsPolyObj() const
1103 return sal_True;
1106 sal_uInt32 SdrMeasureObj::GetPointCount() const
1108 return 2L;
1111 Point SdrMeasureObj::GetPoint(sal_uInt32 i) const
1113 return (0L == i) ? aPt1 : aPt2;
1116 void SdrMeasureObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
1118 if (0L == i)
1119 aPt1=rPnt;
1120 if (1L == i)
1121 aPt2=rPnt;
1122 SetRectsDirty();
1123 SetTextDirty();
1126 SdrObjGeoData* SdrMeasureObj::NewGeoData() const
1128 return new SdrMeasureObjGeoData;
1131 void SdrMeasureObj::SaveGeoData(SdrObjGeoData& rGeo) const
1133 SdrTextObj::SaveGeoData(rGeo);
1134 SdrMeasureObjGeoData& rMGeo=(SdrMeasureObjGeoData&)rGeo;
1135 rMGeo.aPt1=aPt1;
1136 rMGeo.aPt2=aPt2;
1139 void SdrMeasureObj::RestGeoData(const SdrObjGeoData& rGeo)
1141 SdrTextObj::RestGeoData(rGeo);
1142 SdrMeasureObjGeoData& rMGeo=(SdrMeasureObjGeoData&)rGeo;
1143 aPt1=rMGeo.aPt1;
1144 aPt2=rMGeo.aPt2;
1145 SetTextDirty();
1148 SdrObject* SdrMeasureObj::DoConvertToPolyObj(sal_Bool bBezier, bool bAddText) const
1150 // get XOR Poly as base
1151 XPolyPolygon aTmpPolyPolygon(TakeXorPoly());
1153 // get local ItemSet and StyleSheet
1154 SfxItemSet aSet(GetObjectItemSet());
1155 SfxStyleSheet* pStyleSheet = GetStyleSheet();
1157 // prepare group
1158 SdrObjGroup* pGroup = new SdrObjGroup;
1159 pGroup->SetModel(GetModel());
1161 // prepare parameters
1162 basegfx::B2DPolyPolygon aPolyPoly;
1163 SdrPathObj* pPath;
1164 sal_uInt16 nCount(aTmpPolyPolygon.Count());
1165 sal_uInt16 nLoopStart(0);
1167 if(nCount == 3)
1169 // three lines, first one is the middle one
1170 aPolyPoly.clear();
1171 aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1173 pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1174 pPath->SetModel(GetModel());
1175 pPath->SetMergedItemSet(aSet);
1176 pPath->SetStyleSheet(pStyleSheet, true);
1177 pGroup->GetSubList()->NbcInsertObject(pPath);
1178 aSet.Put(XLineStartWidthItem(0L));
1179 aSet.Put(XLineEndWidthItem(0L));
1180 nLoopStart = 1;
1182 else if(nCount == 4)
1184 // four lines, middle line with gap, so there are two lines used
1185 // which have one arrow each
1186 sal_Int32 nEndWidth = ((const XLineEndWidthItem&)(aSet.Get(XATTR_LINEENDWIDTH))).GetValue();
1187 aSet.Put(XLineEndWidthItem(0L));
1189 aPolyPoly.clear();
1190 aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1191 pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1192 pPath->SetModel(GetModel());
1193 pPath->SetMergedItemSet(aSet);
1194 pPath->SetStyleSheet(pStyleSheet, true);
1196 pGroup->GetSubList()->NbcInsertObject(pPath);
1198 aSet.Put(XLineEndWidthItem(nEndWidth));
1199 aSet.Put(XLineStartWidthItem(0L));
1201 aPolyPoly.clear();
1202 aPolyPoly.append(aTmpPolyPolygon[1].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(0L));
1211 nLoopStart = 2;
1213 else if(nCount == 5)
1215 // five lines, first two are the outer ones
1216 sal_Int32 nEndWidth = ((const XLineEndWidthItem&)(aSet.Get(XATTR_LINEENDWIDTH))).GetValue();
1218 aSet.Put(XLineEndWidthItem(0L));
1220 aPolyPoly.clear();
1221 aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1222 pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1223 pPath->SetModel(GetModel());
1224 pPath->SetMergedItemSet(aSet);
1225 pPath->SetStyleSheet(pStyleSheet, true);
1227 pGroup->GetSubList()->NbcInsertObject(pPath);
1229 aSet.Put(XLineEndWidthItem(nEndWidth));
1230 aSet.Put(XLineStartWidthItem(0L));
1232 aPolyPoly.clear();
1233 aPolyPoly.append(aTmpPolyPolygon[1].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(0L));
1242 nLoopStart = 2;
1245 for(;nLoopStart<nCount;nLoopStart++)
1247 aPolyPoly.clear();
1248 aPolyPoly.append(aTmpPolyPolygon[nLoopStart].getB2DPolygon());
1249 pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1250 pPath->SetModel(GetModel());
1251 pPath->SetMergedItemSet(aSet);
1252 pPath->SetStyleSheet(pStyleSheet, true);
1254 pGroup->GetSubList()->NbcInsertObject(pPath);
1257 if(bAddText)
1259 return ImpConvertAddText(pGroup, bBezier);
1261 else
1263 return pGroup;
1267 sal_Bool SdrMeasureObj::BegTextEdit(SdrOutliner& rOutl)
1269 UndirtyText();
1270 return SdrTextObj::BegTextEdit(rOutl);
1273 const Size& SdrMeasureObj::GetTextSize() const
1275 if (bTextDirty) UndirtyText();
1276 return SdrTextObj::GetTextSize();
1279 OutlinerParaObject* SdrMeasureObj::GetOutlinerParaObject() const
1281 if(bTextDirty)
1282 UndirtyText();
1283 return SdrTextObj::GetOutlinerParaObject();
1286 void SdrMeasureObj::NbcSetOutlinerParaObject(OutlinerParaObject* pTextObject)
1288 SdrTextObj::NbcSetOutlinerParaObject(pTextObject);
1289 if(SdrTextObj::GetOutlinerParaObject())
1290 SetTextDirty(); // recalculate text
1293 void SdrMeasureObj::TakeTextRect( SdrOutliner& rOutliner, Rectangle& rTextRect, bool bNoEditText,
1294 Rectangle* pAnchorRect, bool bLineWidth ) const
1296 if (bTextDirty) UndirtyText();
1297 SdrTextObj::TakeTextRect( rOutliner, rTextRect, bNoEditText, pAnchorRect, bLineWidth );
1300 void SdrMeasureObj::TakeTextAnchorRect(Rectangle& rAnchorRect) const
1302 if (bTextDirty) UndirtyText();
1303 SdrTextObj::TakeTextAnchorRect(rAnchorRect);
1306 void SdrMeasureObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, Rectangle* pViewInit, Rectangle* pViewMin) const
1308 if (bTextDirty) UndirtyText();
1309 SdrTextObj::TakeTextEditArea(pPaperMin,pPaperMax,pViewInit,pViewMin);
1312 sal_uInt16 SdrMeasureObj::GetOutlinerViewAnchorMode() const
1314 if (bTextDirty) UndirtyText();
1315 ImpMeasureRec aRec;
1316 ImpMeasurePoly aMPol;
1317 ImpTakeAttr(aRec);
1318 ImpCalcGeometrics(aRec,aMPol);
1320 SdrTextHorzAdjust eTH=GetTextHorizontalAdjust();
1321 SdrTextVertAdjust eTV=GetTextVerticalAdjust();
1322 SdrMeasureTextHPos eMH=aMPol.eUsedTextHPos;
1323 SdrMeasureTextVPos eMV=aMPol.eUsedTextVPos;
1324 bool bTextRota90=aRec.bTextRota90;
1325 bool bBelowRefEdge=aRec.bBelowRefEdge;
1327 // TODO: bTextUpsideDown should be interpreted here!
1328 if (!bTextRota90) {
1329 if (eMH==SDRMEASURE_TEXTLEFTOUTSIDE) eTH=SDRTEXTHORZADJUST_RIGHT;
1330 if (eMH==SDRMEASURE_TEXTRIGHTOUTSIDE) eTH=SDRTEXTHORZADJUST_LEFT;
1331 // at eMH==SDRMEASURE_TEXTINSIDE we can anchor horizontally
1332 if (eMV==SDRMEASURE_ABOVE) eTV=SDRTEXTVERTADJUST_BOTTOM;
1333 if (eMV==SDRMEASURE_BELOW) eTV=SDRTEXTVERTADJUST_TOP;
1334 if (eMV==SDRMEASURETEXT_BREAKEDLINE || eMV==SDRMEASURETEXT_VERTICALCENTERED) eTV=SDRTEXTVERTADJUST_CENTER;
1335 } else {
1336 if (eMH==SDRMEASURE_TEXTLEFTOUTSIDE) eTV=SDRTEXTVERTADJUST_BOTTOM;
1337 if (eMH==SDRMEASURE_TEXTRIGHTOUTSIDE) eTV=SDRTEXTVERTADJUST_TOP;
1338 // at eMH==SDRMEASURE_TEXTINSIDE we can anchor vertically
1339 if (!bBelowRefEdge) {
1340 if (eMV==SDRMEASURE_ABOVE) eTH=SDRTEXTHORZADJUST_LEFT;
1341 if (eMV==SDRMEASURE_BELOW) eTH=SDRTEXTHORZADJUST_RIGHT;
1342 } else {
1343 if (eMV==SDRMEASURE_ABOVE) eTH=SDRTEXTHORZADJUST_RIGHT;
1344 if (eMV==SDRMEASURE_BELOW) eTH=SDRTEXTHORZADJUST_LEFT;
1346 if (eMV==SDRMEASURETEXT_BREAKEDLINE || eMV==SDRMEASURETEXT_VERTICALCENTERED) eTH=SDRTEXTHORZADJUST_CENTER;
1349 EVAnchorMode eRet=ANCHOR_BOTTOM_HCENTER;
1350 if (eTH==SDRTEXTHORZADJUST_LEFT) {
1351 if (eTV==SDRTEXTVERTADJUST_TOP) eRet=ANCHOR_TOP_LEFT;
1352 else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=ANCHOR_BOTTOM_LEFT;
1353 else eRet=ANCHOR_VCENTER_LEFT;
1354 } else if (eTH==SDRTEXTHORZADJUST_RIGHT) {
1355 if (eTV==SDRTEXTVERTADJUST_TOP) eRet=ANCHOR_TOP_RIGHT;
1356 else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=ANCHOR_BOTTOM_RIGHT;
1357 else eRet=ANCHOR_VCENTER_RIGHT;
1358 } else {
1359 if (eTV==SDRTEXTVERTADJUST_TOP) eRet=ANCHOR_TOP_HCENTER;
1360 else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=ANCHOR_BOTTOM_HCENTER;
1361 else eRet=ANCHOR_VCENTER_HCENTER;
1363 return (sal_uInt16)eRet;
1366 //////////////////////////////////////////////////////////////////////////////
1367 // #i97878#
1368 // TRGetBaseGeometry/TRSetBaseGeometry needs to be based on two positions,
1369 // same as line geometry in SdrPathObj. Thus needs to be overloaded and
1370 // implemented since currently it is derived from SdrTextObj which uses
1371 // a functionality based on SnapRect which is not useful here
1373 sal_Bool SdrMeasureObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
1375 // handle the same as a simple line since the definition is based on two points
1376 const basegfx::B2DRange aRange(aPt1.X(), aPt1.Y(), aPt2.X(), aPt2.Y());
1377 basegfx::B2DTuple aScale(aRange.getRange());
1378 basegfx::B2DTuple aTranslate(aRange.getMinimum());
1380 // position maybe relative to anchor position, convert
1381 if( pModel->IsWriter() )
1383 if(GetAnchorPos().X() || GetAnchorPos().Y())
1385 aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
1389 // force MapUnit to 100th mm
1390 SfxMapUnit eMapUnit = pModel->GetItemPool().GetMetric(0);
1391 if(eMapUnit != SFX_MAPUNIT_100TH_MM)
1393 switch(eMapUnit)
1395 case SFX_MAPUNIT_TWIP :
1397 // position
1398 aTranslate.setX(ImplTwipsToMM(aTranslate.getX()));
1399 aTranslate.setY(ImplTwipsToMM(aTranslate.getY()));
1401 // size
1402 aScale.setX(ImplTwipsToMM(aScale.getX()));
1403 aScale.setY(ImplTwipsToMM(aScale.getY()));
1405 break;
1407 default:
1409 OSL_FAIL("TRGetBaseGeometry: Missing unit translation to 100th mm!");
1414 // build return value matrix
1415 rMatrix = basegfx::tools::createScaleTranslateB2DHomMatrix(aScale, aTranslate);
1417 return sal_True;
1420 void SdrMeasureObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
1422 // use given transformation to derive the two defining points from unit line
1423 basegfx::B2DPoint aPosA(rMatrix * basegfx::B2DPoint(0.0, 0.0));
1424 basegfx::B2DPoint aPosB(rMatrix * basegfx::B2DPoint(1.0, 0.0));
1426 // force metric to pool metric
1427 SfxMapUnit eMapUnit = pModel->GetItemPool().GetMetric(0);
1428 if(eMapUnit != SFX_MAPUNIT_100TH_MM)
1430 switch(eMapUnit)
1432 case SFX_MAPUNIT_TWIP :
1434 // position
1435 aPosA.setX(ImplMMToTwips(aPosA.getX()));
1436 aPosA.setY(ImplMMToTwips(aPosA.getY()));
1437 aPosB.setX(ImplMMToTwips(aPosB.getX()));
1438 aPosB.setY(ImplMMToTwips(aPosB.getY()));
1440 break;
1442 default:
1444 OSL_FAIL("TRSetBaseGeometry: Missing unit translation to PoolMetric!");
1449 if( pModel->IsWriter() )
1451 // if anchor is used, make position relative to it
1452 if(GetAnchorPos().X() || GetAnchorPos().Y())
1454 const basegfx::B2DVector aAnchorOffset(GetAnchorPos().X(), GetAnchorPos().Y());
1456 aPosA += aAnchorOffset;
1457 aPosB += aAnchorOffset;
1461 // derive new model data
1462 const Point aNewPt1(basegfx::fround(aPosA.getX()), basegfx::fround(aPosA.getY()));
1463 const Point aNewPt2(basegfx::fround(aPosB.getX()), basegfx::fround(aPosB.getY()));
1465 if(aNewPt1 != aPt1 || aNewPt2 != aPt2)
1467 // set model values and broadcast
1468 Rectangle aBoundRect0; if (pUserCall!=NULL) aBoundRect0=GetLastBoundRect();
1470 aPt1 = aNewPt1;
1471 aPt2 = aNewPt2;
1473 SetTextDirty();
1474 ActionChanged();
1475 SetChanged();
1476 BroadcastObjectChange();
1477 SendUserCall(SDRUSERCALL_MOVEONLY,aBoundRect0);
1481 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */