xref: /AOO41X/main/svx/source/svdraw/svdomeas.cxx (revision ff0525f24f03981d56b7579b645949f111420994)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svx.hxx"
26 
27 #include <svx/svdomeas.hxx>
28 #include <math.h>
29 #include "svx/svditext.hxx" //
30 #include <svx/xpoly.hxx>
31 #include <svx/svdtrans.hxx>
32 #include <svx/svdhdl.hxx>
33 #include <svx/svdoutl.hxx>
34 #include <svx/svddrag.hxx>
35 #include <svx/svdpool.hxx>
36 #include <svx/svdattrx.hxx>
37 #include <svx/svdmodel.hxx>
38 #include <svx/svdview.hxx>
39 #include "svx/svdglob.hxx"   // StringCache
40 #include "svx/svdstr.hrc"    // Objektname
41 #include <svl/style.hxx>
42 #include <svl/smplhint.hxx>
43 #include <editeng/eeitem.hxx>
44 #include <svx/xlnstit.hxx>
45 #include <svx/xlnstwit.hxx>
46 #include <svx/xlnedit.hxx>
47 #include <svx/xlnwtit.hxx>
48 #include <svx/xlnedwit.hxx>
49 #include <svx/xlnstcit.hxx>
50 #include <svx/xlnedcit.hxx>
51 #include <editeng/outlobj.hxx>
52 #include <editeng/outliner.hxx>
53 #include <editeng/editobj.hxx>
54 #include <editeng/measfld.hxx>
55 #include <editeng/flditem.hxx>
56 #include <svx/svdogrp.hxx>
57 #include <svx/svdopath.hxx>
58 #include <svx/svdpage.hxx>
59 #include <unotools/syslocale.hxx>
60 #include "svdoimp.hxx"
61 #include <svx/sdr/properties/measureproperties.hxx>
62 #include <svx/sdr/contact/viewcontactofsdrmeasureobj.hxx>
63 #include <basegfx/point/b2dpoint.hxx>
64 #include <basegfx/polygon/b2dpolygon.hxx>
65 #include <basegfx/polygon/b2dpolypolygon.hxx>
66 #include <basegfx/matrix/b2dhommatrix.hxx>
67 #include <basegfx/matrix/b2dhommatrixtools.hxx>
68 
69 ////////////////////////////////////////////////////////////////////////////////////////////////////
70 
71 SdrMeasureObjGeoData::SdrMeasureObjGeoData() {}
72 SdrMeasureObjGeoData::~SdrMeasureObjGeoData() {}
73 
74 void SdrMeasureObj::TakeRepresentation( XubString& rStr, SdrMeasureFieldKind eMeasureFieldKind ) const
75 {
76     rStr.Erase();
77     Fraction aMeasureScale(1, 1);
78     sal_Bool bTextRota90(sal_False);
79     sal_Bool bShowUnit(sal_False);
80     FieldUnit eMeasureUnit(FUNIT_NONE);
81     FieldUnit eModUIUnit(FUNIT_NONE);
82 
83     const SfxItemSet& rSet = GetMergedItemSet();
84     bTextRota90 = ((SdrMeasureTextRota90Item&)rSet.Get(SDRATTR_MEASURETEXTROTA90)).GetValue();
85     eMeasureUnit = ((SdrMeasureUnitItem&)rSet.Get(SDRATTR_MEASUREUNIT)).GetValue();
86     aMeasureScale = ((SdrMeasureScaleItem&)rSet.Get(SDRATTR_MEASURESCALE)).GetValue();
87     bShowUnit = ((SdrMeasureShowUnitItem&)rSet.Get(SDRATTR_MEASURESHOWUNIT)).GetValue();
88     sal_Int16 nNumDigits = ((SdrMeasureDecimalPlacesItem&)rSet.Get(SDRATTR_MEASUREDECIMALPLACES)).GetValue();
89 
90     //SdrModel* pModel = rObj.pModel;
91 
92     switch(eMeasureFieldKind)
93     {
94         case SDRMEASUREFIELD_VALUE:
95         {
96             if(pModel)
97             {
98                 eModUIUnit = pModel->GetUIUnit();
99 
100                 if(eMeasureUnit == FUNIT_NONE)
101                     eMeasureUnit = eModUIUnit;
102 
103                 sal_Int32 nLen(GetLen(aPt2 - aPt1));
104                 Fraction aFact(1,1);
105 
106                 if(eMeasureUnit != eModUIUnit)
107                 {
108                     // Zur Umrechnung der Einheiten
109                     aFact *= GetMapFactor(eModUIUnit, eMeasureUnit).X();
110                 }
111 
112                 if(aMeasureScale.GetNumerator() != aMeasureScale.GetDenominator())
113                 {
114                     aFact *= aMeasureScale;
115                 }
116 
117                 if(aFact.GetNumerator() != aFact.GetDenominator())
118                 {
119                     // Scaling ueber BigInt, um Ueberlaeufe zu vermeiden
120                     nLen = BigMulDiv(nLen, aFact.GetNumerator(), aFact.GetDenominator());
121                 }
122 
123                 pModel->TakeMetricStr(nLen, rStr, sal_True, nNumDigits);
124 
125                 if(!aFact.IsValid())
126                 {
127                     rStr = String();
128                     rStr += sal_Unicode('?');
129                 }
130 
131                 sal_Unicode cDec(SvtSysLocale().GetLocaleData().getNumDecimalSep().GetChar(0));
132 
133                 if(rStr.Search(cDec) != STRING_NOTFOUND)
134                 {
135                     xub_StrLen nLen2(rStr.Len() - 1);
136 
137                     while(rStr.GetChar(nLen2) == sal_Unicode('0'))
138                     {
139                         rStr.Erase(nLen2);
140                         nLen2--;
141                     }
142 
143                     if(rStr.GetChar(nLen2) == cDec)
144                     {
145                         rStr.Erase(nLen2);
146                         nLen2--;
147                     }
148 
149                     if(!rStr.Len())
150                         rStr += sal_Unicode('0');
151                 }
152             }
153             else
154             {
155                 // falls kein Model da ... (z.B. Preview im Dialog)
156                 rStr = String();
157                 rStr.AppendAscii("4711");
158             }
159 
160             break;
161         }
162         case SDRMEASUREFIELD_UNIT:
163         {
164             if(bShowUnit)
165             {
166                 if(pModel)
167                 {
168                     eModUIUnit = pModel->GetUIUnit();
169 
170                     if(eMeasureUnit == FUNIT_NONE)
171                         eMeasureUnit = eModUIUnit;
172 
173                     if(bShowUnit)
174                         pModel->TakeUnitStr(eMeasureUnit, rStr);
175                 }
176             }
177 
178             break;
179         }
180         case SDRMEASUREFIELD_ROTA90BLANCS:
181         {
182             if(bTextRota90)
183             {
184                 rStr = String();
185                 rStr += sal_Unicode(' ');
186             }
187 
188             break;
189         }
190     }
191 }
192 
193 //////////////////////////////////////////////////////////////////////////////
194 // BaseProperties section
195 
196 sdr::properties::BaseProperties* SdrMeasureObj::CreateObjectSpecificProperties()
197 {
198     return new sdr::properties::MeasureProperties(*this);
199 }
200 
201 //////////////////////////////////////////////////////////////////////////////
202 // DrawContact section
203 
204 sdr::contact::ViewContact* SdrMeasureObj::CreateObjectSpecificViewContact()
205 {
206     return new sdr::contact::ViewContactOfSdrMeasureObj(*this);
207 }
208 
209 //////////////////////////////////////////////////////////////////////////////
210 
211 TYPEINIT1(SdrMeasureObj,SdrTextObj);
212 
213 SdrMeasureObj::SdrMeasureObj():
214     bTextDirty(sal_False)
215 {
216     // #i25616#
217     mbSupportTextIndentingOnLineWidthChange = sal_False;
218 }
219 
220 SdrMeasureObj::SdrMeasureObj(const Point& rPt1, const Point& rPt2):
221     aPt1(rPt1),
222     aPt2(rPt2),
223     bTextDirty(sal_False)
224 {
225     // #i25616#
226     mbSupportTextIndentingOnLineWidthChange = sal_False;
227 }
228 
229 SdrMeasureObj::~SdrMeasureObj()
230 {
231 }
232 
233 void SdrMeasureObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
234 {
235     rInfo.bSelectAllowed    =sal_True;
236     rInfo.bMoveAllowed      =sal_True;
237     rInfo.bResizeFreeAllowed=sal_True;
238     rInfo.bResizePropAllowed=sal_True;
239     rInfo.bRotateFreeAllowed=sal_True;
240     rInfo.bRotate90Allowed  =sal_True;
241     rInfo.bMirrorFreeAllowed=sal_True;
242     rInfo.bMirror45Allowed  =sal_True;
243     rInfo.bMirror90Allowed  =sal_True;
244     rInfo.bTransparenceAllowed = sal_False;
245     rInfo.bGradientAllowed = sal_False;
246     rInfo.bShearAllowed     =sal_True;
247     rInfo.bEdgeRadiusAllowed=sal_False;
248     rInfo.bNoOrthoDesired   =sal_True;
249     rInfo.bNoContortion     =sal_False;
250     rInfo.bCanConvToPath    =sal_False;
251     rInfo.bCanConvToPoly    =sal_True;
252     rInfo.bCanConvToPathLineToArea=sal_False;
253     rInfo.bCanConvToPolyLineToArea=sal_False;
254     rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
255 }
256 
257 sal_uInt16 SdrMeasureObj::GetObjIdentifier() const
258 {
259     return (sal_uInt16)OBJ_MEASURE;
260 }
261 
262 struct ImpMeasureRec : public SdrDragStatUserData
263 {
264     Point                       aPt1;
265     Point                       aPt2;
266     SdrMeasureKind              eKind;
267     SdrMeasureTextHPos          eWantTextHPos;
268     SdrMeasureTextVPos          eWantTextVPos;
269     long                        nLineDist;
270     long                        nHelplineOverhang;
271     long                        nHelplineDist;
272     long                        nHelpline1Len;
273     long                        nHelpline2Len;
274     FASTBOOL                    bBelowRefEdge;
275     FASTBOOL                    bTextRota90;
276     FASTBOOL                    bTextUpsideDown;
277     long                        nMeasureOverhang;
278     FieldUnit                   eMeasureUnit;
279     Fraction                    aMeasureScale;
280     FASTBOOL                    bShowUnit;
281     String                      aFormatString;
282     FASTBOOL                    bTextAutoAngle;
283     long                        nTextAutoAngleView;
284     FASTBOOL                    bTextIsFixedAngle;
285     long                        nTextFixedAngle;
286 };
287 
288 struct ImpLineRec
289 {
290     Point                       aP1;
291     Point                       aP2;
292 };
293 
294 struct ImpMeasurePoly
295 {
296     ImpLineRec                  aMainline1; // die mit dem 1. Pfeil
297     ImpLineRec                  aMainline2; // die mit dem 2. Pfeil
298     ImpLineRec                  aMainline3; // die dazwischen
299     ImpLineRec                  aHelpline1;
300     ImpLineRec                  aHelpline2;
301     Rectangle                   aTextRect;
302     Size                        aTextSize;
303     long                        nLineLen;
304     long                        nLineWink;
305     long                        nTextWink;
306     long                        nHlpWink;
307     double                      nLineSin;
308     double                      nLineCos;
309     double                      nHlpSin;
310     double                      nHlpCos;
311     sal_uInt16                      nMainlineAnz;
312     SdrMeasureTextHPos          eUsedTextHPos;
313     SdrMeasureTextVPos          eUsedTextVPos;
314     long                        nLineWdt2;  // Halbe Strichstaerke
315     long                        nArrow1Len; // Laenge des 1. Pfeils. Bei Center nur die Haelfte
316     long                        nArrow2Len; // Laenge des 2. Pfeils. Bei Center nur die Haelfte
317     long                        nArrow1Wdt; // Breite des 1. Pfeils
318     long                        nArrow2Wdt; // Breite des 2. Pfeils
319     long                        nShortLineLen; // Linienlaenge, wenn PfeileAussen
320     FASTBOOL                    bArrow1Center; // Pfeil 1 zentriert?
321     FASTBOOL                    bArrow2Center; // Pfeil 2 zentriert?
322     FASTBOOL                    bAutoUpsideDown; // UpsideDown durch Automatik
323     FASTBOOL                    bPfeileAussen;
324     FASTBOOL                    bBreakedLine;
325 };
326 
327 void SdrMeasureObj::ImpTakeAttr(ImpMeasureRec& rRec) const
328 {
329     rRec.aPt1 = aPt1;
330     rRec.aPt2 = aPt2;
331 
332     const SfxItemSet& rSet = GetObjectItemSet();
333     rRec.eKind            =((SdrMeasureKindItem&            )rSet.Get(SDRATTR_MEASUREKIND            )).GetValue();
334     rRec.eWantTextHPos    =((SdrMeasureTextHPosItem&        )rSet.Get(SDRATTR_MEASURETEXTHPOS        )).GetValue();
335     rRec.eWantTextVPos    =((SdrMeasureTextVPosItem&        )rSet.Get(SDRATTR_MEASURETEXTVPOS        )).GetValue();
336     rRec.nLineDist        =((SdrMeasureLineDistItem&        )rSet.Get(SDRATTR_MEASURELINEDIST        )).GetValue();
337     rRec.nHelplineOverhang=((SdrMeasureHelplineOverhangItem&)rSet.Get(SDRATTR_MEASUREHELPLINEOVERHANG)).GetValue();
338     rRec.nHelplineDist    =((SdrMeasureHelplineDistItem&    )rSet.Get(SDRATTR_MEASUREHELPLINEDIST    )).GetValue();
339     rRec.nHelpline1Len    =((SdrMeasureHelpline1LenItem&    )rSet.Get(SDRATTR_MEASUREHELPLINE1LEN    )).GetValue();
340     rRec.nHelpline2Len    =((SdrMeasureHelpline2LenItem&    )rSet.Get(SDRATTR_MEASUREHELPLINE2LEN    )).GetValue();
341     rRec.bBelowRefEdge    =((SdrMeasureBelowRefEdgeItem&    )rSet.Get(SDRATTR_MEASUREBELOWREFEDGE    )).GetValue();
342     rRec.bTextRota90      =((SdrMeasureTextRota90Item&      )rSet.Get(SDRATTR_MEASURETEXTROTA90      )).GetValue();
343     rRec.bTextUpsideDown  =((SdrMeasureTextUpsideDownItem&  )rSet.Get(SDRATTR_MEASURETEXTUPSIDEDOWN  )).GetValue();
344     rRec.nMeasureOverhang =((SdrMeasureOverhangItem&        )rSet.Get(SDRATTR_MEASUREOVERHANG        )).GetValue();
345     rRec.eMeasureUnit     =((SdrMeasureUnitItem&            )rSet.Get(SDRATTR_MEASUREUNIT            )).GetValue();
346     rRec.aMeasureScale    =((SdrMeasureScaleItem&           )rSet.Get(SDRATTR_MEASURESCALE           )).GetValue();
347     rRec.bShowUnit        =((SdrMeasureShowUnitItem&        )rSet.Get(SDRATTR_MEASURESHOWUNIT        )).GetValue();
348     rRec.aFormatString    =((SdrMeasureFormatStringItem&    )rSet.Get(SDRATTR_MEASUREFORMATSTRING    )).GetValue();
349     rRec.bTextAutoAngle    =((SdrMeasureTextAutoAngleItem&    )rSet.Get(SDRATTR_MEASURETEXTAUTOANGLE    )).GetValue();
350     rRec.nTextAutoAngleView=((SdrMeasureTextAutoAngleViewItem&)rSet.Get(SDRATTR_MEASURETEXTAUTOANGLEVIEW)).GetValue();
351     rRec.bTextIsFixedAngle =((SdrMeasureTextIsFixedAngleItem& )rSet.Get(SDRATTR_MEASURETEXTISFIXEDANGLE )).GetValue();
352     rRec.nTextFixedAngle   =((SdrMeasureTextFixedAngleItem&   )rSet.Get(SDRATTR_MEASURETEXTFIXEDANGLE   )).GetValue();
353 }
354 
355 long impGetLineStartEndDistance(const basegfx::B2DPolyPolygon& rPolyPolygon, long nNewWidth, bool bCenter)
356 {
357     const basegfx::B2DRange aPolygonRange(rPolyPolygon.getB2DRange());
358     const double fOldWidth(aPolygonRange.getWidth() > 1.0 ? aPolygonRange.getWidth() : 1.0);
359     const double fScale((double)nNewWidth / fOldWidth);
360     long nHeight(basegfx::fround(aPolygonRange.getHeight() * fScale));
361 
362     if(bCenter)
363     {
364         nHeight /= 2L;
365     }
366 
367     return nHeight;
368 }
369 
370 void SdrMeasureObj::ImpCalcGeometrics(const ImpMeasureRec& rRec, ImpMeasurePoly& rPol) const
371 {
372     Point aP1(rRec.aPt1);
373     Point aP2(rRec.aPt2);
374     Point aDelt(aP2); aDelt-=aP1;
375 
376     rPol.aTextSize=GetTextSize();
377     rPol.nLineLen=GetLen(aDelt);
378 
379     rPol.nLineWdt2=0;
380     long nArrow1Len=0; bool bArrow1Center=false;
381     long nArrow2Len=0; bool bArrow2Center=false;
382     long nArrow1Wdt=0;
383     long nArrow2Wdt=0;
384     rPol.nArrow1Wdt=0;
385     rPol.nArrow2Wdt=0;
386     long nArrowNeed=0;
387     long nShortLen=0;
388     FASTBOOL bPfeileAussen=sal_False;
389 
390     const SfxItemSet& rSet = GetObjectItemSet();
391     sal_Int32 nLineWdt = ((XLineWidthItem&)(rSet.Get(XATTR_LINEWIDTH))).GetValue(); // Strichstaerke
392     rPol.nLineWdt2 = (nLineWdt + 1) / 2;
393 
394     nArrow1Wdt = ((const XLineStartWidthItem&)(rSet.Get(XATTR_LINESTARTWIDTH))).GetValue();
395     if(nArrow1Wdt < 0)
396         nArrow1Wdt = -nLineWdt * nArrow1Wdt / 100; // <0 = relativ
397 
398     nArrow2Wdt = ((const XLineEndWidthItem&)(rSet.Get(XATTR_LINEENDWIDTH))).GetValue();
399     if(nArrow2Wdt < 0)
400         nArrow2Wdt = -nLineWdt * nArrow2Wdt / 100; // <0 = relativ
401 
402     basegfx::B2DPolyPolygon aPol1(((const XLineStartItem&)(rSet.Get(XATTR_LINESTART))).GetLineStartValue());
403     basegfx::B2DPolyPolygon aPol2(((const XLineEndItem&)(rSet.Get(XATTR_LINEEND))).GetLineEndValue());
404     bArrow1Center = ((const XLineStartCenterItem&)(rSet.Get(XATTR_LINESTARTCENTER))).GetValue();
405     bArrow2Center = ((const XLineEndCenterItem&)(rSet.Get(XATTR_LINEENDCENTER))).GetValue();
406     nArrow1Len = impGetLineStartEndDistance(aPol1, nArrow1Wdt, bArrow1Center) - 1;
407     nArrow2Len = impGetLineStartEndDistance(aPol2, nArrow2Wdt, bArrow2Center) - 1;
408 
409     // nArrowLen ist bei bCenter bereits halbiert
410     // Bei 2 Pfeilen a 4mm ist unter 10mm Schluss.
411     nArrowNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2;
412     if (rPol.nLineLen<nArrowNeed) bPfeileAussen=sal_True;
413     nShortLen=(nArrow1Len+nArrow1Wdt + nArrow2Len+nArrow2Wdt) /2;
414 
415     rPol.eUsedTextHPos=rRec.eWantTextHPos;
416     rPol.eUsedTextVPos=rRec.eWantTextVPos;
417     if (rPol.eUsedTextVPos==SDRMEASURE_TEXTVAUTO) rPol.eUsedTextVPos=SDRMEASURE_ABOVE;
418     FASTBOOL bBrkLine=rPol.eUsedTextVPos==SDRMEASURETEXT_BREAKEDLINE;
419     if (rPol.eUsedTextVPos==SDRMEASURETEXT_VERTICALCENTERED)
420     {
421         OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
422         if (pOutlinerParaObject!=NULL && pOutlinerParaObject->GetTextObject().GetParagraphCount()==1)
423         {
424             bBrkLine=sal_True; // Unterbrochene Linie, wenn nur 1 Absatz.
425         }
426     }
427     rPol.bBreakedLine=bBrkLine;
428     if (rPol.eUsedTextHPos==SDRMEASURE_TEXTHAUTO) { // bei zu breitem Text diesen eventuell nach aussen schieben
429         FASTBOOL bOutside=sal_False;
430         long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
431         if (nNeedSiz>rPol.nLineLen) bOutside=sal_True; // Text passt nicht in die Mitte
432         if (bBrkLine) {
433             if (nNeedSiz+nArrowNeed>rPol.nLineLen) bPfeileAussen=sal_True; // Text passt in die Mitte, wenn die Pfeile nach aussen kommen
434         } else {
435             long nSmallNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2/4;
436             if (nNeedSiz+nSmallNeed>rPol.nLineLen) bPfeileAussen=sal_True; // Text passt in die Mitte, wenn die Pfeile nach aussen kommen
437         }
438         rPol.eUsedTextHPos=bOutside ? SDRMEASURE_TEXTLEFTOUTSIDE : SDRMEASURE_TEXTINSIDE;
439     }
440     if (rPol.eUsedTextHPos!=SDRMEASURE_TEXTINSIDE) bPfeileAussen=sal_True;
441     rPol.nArrow1Wdt=nArrow1Wdt;
442     rPol.nArrow2Wdt=nArrow2Wdt;
443     rPol.nShortLineLen=nShortLen;
444     rPol.bPfeileAussen=bPfeileAussen;
445     rPol.nArrow1Len=nArrow1Len;
446     rPol.bArrow1Center=bArrow1Center;
447     rPol.nArrow2Len=nArrow2Len;
448     rPol.bArrow2Center=bArrow2Center;
449 
450     rPol.nLineWink=GetAngle(aDelt);
451     double a=rPol.nLineWink*nPi180;
452     double nLineSin=sin(a);
453     double nLineCos=cos(a);
454     rPol.nLineSin=nLineSin;
455     rPol.nLineCos=nLineCos;
456 
457     rPol.nTextWink=rPol.nLineWink;
458     if (rRec.bTextRota90) rPol.nTextWink+=9000;
459 
460     rPol.bAutoUpsideDown=sal_False;
461     if (rRec.bTextAutoAngle) {
462         long nTmpWink=NormAngle360(rPol.nTextWink-rRec.nTextAutoAngleView);
463         if (nTmpWink>=18000) {
464             rPol.nTextWink+=18000;
465             rPol.bAutoUpsideDown=sal_True;
466         }
467     }
468 
469     if (rRec.bTextUpsideDown) rPol.nTextWink+=18000;
470     rPol.nTextWink=NormAngle360(rPol.nTextWink);
471     rPol.nHlpWink=rPol.nLineWink+9000;
472     if (rRec.bBelowRefEdge) rPol.nHlpWink+=18000;
473     rPol.nHlpWink=NormAngle360(rPol.nHlpWink);
474     double nHlpSin=nLineCos;
475     double nHlpCos=-nLineSin;
476     if (rRec.bBelowRefEdge) {
477         nHlpSin=-nHlpSin;
478         nHlpCos=-nHlpCos;
479     }
480     rPol.nHlpSin=nHlpSin;
481     rPol.nHlpCos=nHlpCos;
482 
483     long nLineDist=rRec.nLineDist;
484     long nOverhang=rRec.nHelplineOverhang;
485     long nHelplineDist=rRec.nHelplineDist;
486 
487     long dx= Round(nLineDist*nHlpCos);
488     long dy=-Round(nLineDist*nHlpSin);
489     long dxh1a= Round((nHelplineDist-rRec.nHelpline1Len)*nHlpCos);
490     long dyh1a=-Round((nHelplineDist-rRec.nHelpline1Len)*nHlpSin);
491     long dxh1b= Round((nHelplineDist-rRec.nHelpline2Len)*nHlpCos);
492     long dyh1b=-Round((nHelplineDist-rRec.nHelpline2Len)*nHlpSin);
493     long dxh2= Round((nLineDist+nOverhang)*nHlpCos);
494     long dyh2=-Round((nLineDist+nOverhang)*nHlpSin);
495 
496     // Masshilfslinie 1
497     rPol.aHelpline1.aP1=Point(aP1.X()+dxh1a,aP1.Y()+dyh1a);
498     rPol.aHelpline1.aP2=Point(aP1.X()+dxh2,aP1.Y()+dyh2);
499 
500     // Masshilfslinie 2
501     rPol.aHelpline2.aP1=Point(aP2.X()+dxh1b,aP2.Y()+dyh1b);
502     rPol.aHelpline2.aP2=Point(aP2.X()+dxh2,aP2.Y()+dyh2);
503 
504     // Masslinie(n)
505     Point aMainlinePt1(aP1.X()+dx,aP1.Y()+dy);
506     Point aMainlinePt2(aP2.X()+dx,aP2.Y()+dy);
507     if (!bPfeileAussen) {
508         rPol.aMainline1.aP1=aMainlinePt1;
509         rPol.aMainline1.aP2=aMainlinePt2;
510         rPol.aMainline2=rPol.aMainline1;
511         rPol.aMainline3=rPol.aMainline1;
512         rPol.nMainlineAnz=1;
513         if (bBrkLine) {
514             long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
515             long nHalfLen=(rPol.nLineLen-nNeedSiz-nArrow1Wdt/4-nArrow2Wdt/4) /2;
516             rPol.nMainlineAnz=2;
517             rPol.aMainline1.aP2=aMainlinePt1;
518             rPol.aMainline1.aP2.X()+=nHalfLen;
519             RotatePoint(rPol.aMainline1.aP2,rPol.aMainline1.aP1,nLineSin,nLineCos);
520             rPol.aMainline2.aP1=aMainlinePt2;
521             rPol.aMainline2.aP1.X()-=nHalfLen;
522             RotatePoint(rPol.aMainline2.aP1,rPol.aMainline2.aP2,nLineSin,nLineCos);
523         }
524     } else {
525         long nLen1=nShortLen; // Pfeilbreite als Linienlaenge ausserhalb des Pfeils
526         long nLen2=nShortLen;
527         long nTextWdt=rRec.bTextRota90 ? rPol.aTextSize.Height() : rPol.aTextSize.Width();
528         if (!bBrkLine) {
529             if (rPol.eUsedTextHPos==SDRMEASURE_TEXTLEFTOUTSIDE) nLen1=nArrow1Len+nTextWdt;
530             if (rPol.eUsedTextHPos==SDRMEASURE_TEXTRIGHTOUTSIDE) nLen2=nArrow2Len+nTextWdt;
531         }
532         rPol.aMainline1.aP1=aMainlinePt1;
533         rPol.aMainline1.aP2=aMainlinePt1; rPol.aMainline1.aP2.X()-=nLen1; RotatePoint(rPol.aMainline1.aP2,aMainlinePt1,nLineSin,nLineCos);
534         rPol.aMainline2.aP1=aMainlinePt2; rPol.aMainline2.aP1.X()+=nLen2; RotatePoint(rPol.aMainline2.aP1,aMainlinePt2,nLineSin,nLineCos);
535         rPol.aMainline2.aP2=aMainlinePt2;
536         rPol.aMainline3.aP1=aMainlinePt1;
537         rPol.aMainline3.aP2=aMainlinePt2;
538         rPol.nMainlineAnz=3;
539         if (bBrkLine && rPol.eUsedTextHPos==SDRMEASURE_TEXTINSIDE) rPol.nMainlineAnz=2;
540     }
541 }
542 
543 basegfx::B2DPolyPolygon SdrMeasureObj::ImpCalcXPoly(const ImpMeasurePoly& rPol) const
544 {
545     basegfx::B2DPolyPolygon aRetval;
546     basegfx::B2DPolygon aPartPolyA;
547     aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP1.X(), rPol.aMainline1.aP1.Y()));
548     aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP2.X(), rPol.aMainline1.aP2.Y()));
549     aRetval.append(aPartPolyA);
550 
551     if(rPol.nMainlineAnz > 1)
552     {
553         aPartPolyA.clear();
554         aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP1.X(), rPol.aMainline2.aP1.Y()));
555         aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP2.X(), rPol.aMainline2.aP2.Y()));
556         aRetval.append(aPartPolyA);
557     }
558 
559     if(rPol.nMainlineAnz > 2)
560     {
561         aPartPolyA.clear();
562         aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP1.X(), rPol.aMainline3.aP1.Y()));
563         aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP2.X(), rPol.aMainline3.aP2.Y()));
564         aRetval.append(aPartPolyA);
565     }
566 
567     aPartPolyA.clear();
568     aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP1.X(), rPol.aHelpline1.aP1.Y()));
569     aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP2.X(), rPol.aHelpline1.aP2.Y()));
570     aRetval.append(aPartPolyA);
571 
572     aPartPolyA.clear();
573     aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP1.X(), rPol.aHelpline2.aP1.Y()));
574     aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP2.X(), rPol.aHelpline2.aP2.Y()));
575     aRetval.append(aPartPolyA);
576 
577     return aRetval;
578 }
579 
580 FASTBOOL SdrMeasureObj::CalcFieldValue(const SvxFieldItem& rField, sal_uInt16 nPara, sal_uInt16 nPos,
581     FASTBOOL bEdit,
582     Color*& rpTxtColor, Color*& rpFldColor, XubString& rRet) const
583 {
584     const SvxFieldData* pField=rField.GetField();
585     SdrMeasureField* pMeasureField=PTR_CAST(SdrMeasureField,pField);
586     if (pMeasureField!=NULL) {
587         TakeRepresentation(rRet, pMeasureField->GetMeasureFieldKind());
588         if (rpFldColor!=NULL) {
589             if (!bEdit)
590             {
591                 delete rpFldColor;
592                 rpFldColor=NULL;
593             }
594         }
595         return sal_True;
596     } else {
597         return SdrTextObj::CalcFieldValue(rField,nPara,nPos,bEdit,rpTxtColor,rpFldColor,rRet);
598     }
599 }
600 
601 void SdrMeasureObj::UndirtyText() const
602 {
603     if (bTextDirty)
604     {
605         SdrOutliner& rOutliner=ImpGetDrawOutliner();
606         OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
607         if(pOutlinerParaObject==NULL)
608         {
609             rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_ROTA90BLANCS), EE_FEATURE_FIELD), ESelection(0,0));
610             rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_VALUE), EE_FEATURE_FIELD),ESelection(0,1));
611             rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_UNIT), EE_FEATURE_FIELD),ESelection(0,2));
612             rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_ROTA90BLANCS), EE_FEATURE_FIELD),ESelection(0,3));
613 
614             if(GetStyleSheet())
615                 rOutliner.SetStyleSheet(0, GetStyleSheet());
616 
617             rOutliner.SetParaAttribs(0, GetObjectItemSet());
618 
619             // casting auf nonconst
620             const_cast<SdrMeasureObj*>(this)->NbcSetOutlinerParaObject( rOutliner.CreateParaObject() );
621         }
622         else
623         {
624             rOutliner.SetText(*pOutlinerParaObject);
625         }
626 
627         rOutliner.SetUpdateMode(sal_True);
628         rOutliner.UpdateFields();
629         Size aSiz(rOutliner.CalcTextSize());
630         rOutliner.Clear();
631         // 3x casting auf nonconst
632         ((SdrMeasureObj*)this)->aTextSize=aSiz;
633         ((SdrMeasureObj*)this)->bTextSizeDirty=sal_False;
634         ((SdrMeasureObj*)this)->bTextDirty=sal_False;
635     }
636 }
637 
638 void SdrMeasureObj::TakeUnrotatedSnapRect(Rectangle& rRect) const
639 {
640     if (bTextDirty) UndirtyText();
641     ImpMeasureRec aRec;
642     ImpMeasurePoly aMPol;
643     ImpTakeAttr(aRec);
644     ImpCalcGeometrics(aRec,aMPol);
645 
646     // TextSize ermitteln inkl. Textrahmenabstaende
647     Size aTextSize2(aMPol.aTextSize);
648     if (aTextSize2.Width()<1) aTextSize2.Width()=1;
649     if (aTextSize2.Height()<1) aTextSize2.Height()=1;
650     aTextSize2.Width()+=GetTextLeftDistance()+GetTextRightDistance();
651     aTextSize2.Height()+=GetTextUpperDistance()+GetTextLowerDistance();
652 
653     Point aPt1b(aMPol.aMainline1.aP1);
654     long nLen=aMPol.nLineLen;
655     long nLWdt=aMPol.nLineWdt2;
656     long nArr1Len=aMPol.nArrow1Len;
657     long nArr2Len=aMPol.nArrow2Len;
658     if (aMPol.bBreakedLine) {
659         // Bei Unterbrochener Linie und Outside muss der Text nicht neben den
660         // Pfeil sondern neben die Linie an dem Pfeil plaziert werden
661         nArr1Len=aMPol.nShortLineLen+aMPol.nArrow1Wdt/4;
662         nArr2Len=aMPol.nShortLineLen+aMPol.nArrow2Wdt/4;
663     }
664 
665     Point aTextPos;
666     FASTBOOL bRota90=aRec.bTextRota90;
667     FASTBOOL bUpsideDown=aRec.bTextUpsideDown!=aMPol.bAutoUpsideDown;
668     FASTBOOL bBelowRefEdge=aRec.bBelowRefEdge;
669     SdrMeasureTextHPos eMH=aMPol.eUsedTextHPos;
670     SdrMeasureTextVPos eMV=aMPol.eUsedTextVPos;
671     if (!bRota90) {
672         switch (eMH) {
673             case SDRMEASURE_TEXTLEFTOUTSIDE: aTextPos.X()=aPt1b.X()-aTextSize2.Width()-nArr1Len-nLWdt; break;
674             case SDRMEASURE_TEXTRIGHTOUTSIDE: aTextPos.X()=aPt1b.X()+nLen+nArr2Len+nLWdt; break;
675             default: aTextPos.X()=aPt1b.X(); aTextSize2.Width()=nLen;
676         }
677         switch (eMV) {
678             case SDRMEASURETEXT_VERTICALCENTERED:
679             case SDRMEASURETEXT_BREAKEDLINE: aTextPos.Y()=aPt1b.Y()-aTextSize2.Height()/2; break;
680             case SDRMEASURE_BELOW: {
681                 if (!bUpsideDown) aTextPos.Y()=aPt1b.Y()+nLWdt;
682                 else aTextPos.Y()=aPt1b.Y()-aTextSize2.Height()-nLWdt;
683             } break;
684             default: {
685                 if (!bUpsideDown) aTextPos.Y()=aPt1b.Y()-aTextSize2.Height()-nLWdt;
686                 else aTextPos.Y()=aPt1b.Y()+nLWdt;
687             }
688         }
689         if (bUpsideDown) {
690             aTextPos.X()+=aTextSize2.Width();
691             aTextPos.Y()+=aTextSize2.Height();
692         }
693     } else { // also wenn bTextRota90==TRUE
694         switch (eMH) {
695             case SDRMEASURE_TEXTLEFTOUTSIDE: aTextPos.X()=aPt1b.X()-aTextSize2.Height()-nArr1Len; break;
696             case SDRMEASURE_TEXTRIGHTOUTSIDE: aTextPos.X()=aPt1b.X()+nLen+nArr2Len; break;
697             default: aTextPos.X()=aPt1b.X(); aTextSize2.Height()=nLen;
698         }
699         switch (eMV) {
700             case SDRMEASURETEXT_VERTICALCENTERED:
701             case SDRMEASURETEXT_BREAKEDLINE: aTextPos.Y()=aPt1b.Y()+aTextSize2.Width()/2; break;
702             case SDRMEASURE_BELOW: {
703                 if (!bBelowRefEdge) aTextPos.Y()=aPt1b.Y()+aTextSize2.Width()+nLWdt;
704                 else aTextPos.Y()=aPt1b.Y()-nLWdt;
705             } break;
706             default: {
707                 if (!bBelowRefEdge) aTextPos.Y()=aPt1b.Y()-nLWdt;
708                 else aTextPos.Y()=aPt1b.Y()+aTextSize2.Width()+nLWdt;
709             }
710         }
711         if (bUpsideDown) {
712             aTextPos.X()+=aTextSize2.Height();
713             aTextPos.Y()-=aTextSize2.Width();
714         }
715     }
716     if (aMPol.nTextWink!=aGeo.nDrehWink) {
717         ((SdrMeasureObj*)this)->aGeo.nDrehWink=aMPol.nTextWink;
718         ((SdrMeasureObj*)this)->aGeo.RecalcSinCos();
719     }
720     RotatePoint(aTextPos,aPt1b,aMPol.nLineSin,aMPol.nLineCos);
721     aTextSize2.Width()++; aTextSize2.Height()++; // wg. des komischen Verhaltens beim Rect-Ctor
722     rRect=Rectangle(aTextPos,aTextSize2);
723     rRect.Justify();
724     ((SdrMeasureObj*)this)->aRect=rRect;
725 
726     if (aMPol.nTextWink!=aGeo.nDrehWink) {
727         ((SdrMeasureObj*)this)->aGeo.nDrehWink=aMPol.nTextWink;
728         ((SdrMeasureObj*)this)->aGeo.RecalcSinCos();
729     }
730 }
731 
732 void SdrMeasureObj::operator=(const SdrObject& rObj)
733 {
734     SdrTextObj::operator=(rObj);
735     aPt1=((SdrMeasureObj&)rObj).aPt1;
736     aPt2=((SdrMeasureObj&)rObj).aPt2;
737     bTextDirty=((SdrMeasureObj&)rObj).bTextDirty;
738 }
739 
740 void SdrMeasureObj::TakeObjNameSingul(XubString& rName) const
741 {
742     rName=ImpGetResStr(STR_ObjNameSingulMEASURE);
743 
744     String aName( GetName() );
745     if(aName.Len())
746     {
747         rName += sal_Unicode(' ');
748         rName += sal_Unicode('\'');
749         rName += aName;
750         rName += sal_Unicode('\'');
751     }
752 }
753 
754 void SdrMeasureObj::TakeObjNamePlural(XubString& rName) const
755 {
756     rName=ImpGetResStr(STR_ObjNamePluralMEASURE);
757 }
758 
759 basegfx::B2DPolyPolygon SdrMeasureObj::TakeXorPoly() const
760 {
761     ImpMeasureRec aRec;
762     ImpMeasurePoly aMPol;
763     ImpTakeAttr(aRec);
764     ImpCalcGeometrics(aRec,aMPol);
765     return ImpCalcXPoly(aMPol);
766 }
767 
768 sal_uInt32 SdrMeasureObj::GetHdlCount() const
769 {
770     return 6L;
771 }
772 
773 SdrHdl* SdrMeasureObj::GetHdl(sal_uInt32 nHdlNum) const
774 {
775     ImpMeasureRec aRec;
776     ImpMeasurePoly aMPol;
777     ImpTakeAttr(aRec);
778     aRec.nHelplineDist=0;
779     ImpCalcGeometrics(aRec,aMPol);
780     Point aPt;
781     //SdrHdlKind eHdl=HDL_POLY;
782     switch (nHdlNum) {
783         case 0: aPt=aMPol.aHelpline1.aP1; break;
784         case 1: aPt=aMPol.aHelpline2.aP1; break;
785         case 2: aPt=aPt1;       break;
786         case 3: aPt=aPt2;       break;
787         case 4: aPt=aMPol.aHelpline1.aP2; break;
788         case 5: aPt=aMPol.aHelpline2.aP2; break;
789     } // switch
790     SdrHdl* pHdl=new ImpMeasureHdl(aPt,HDL_USER);
791     pHdl->SetObjHdlNum(nHdlNum);
792     pHdl->SetDrehWink(aMPol.nLineWink);
793     return pHdl;
794 }
795 
796 ////////////////////////////////////////////////////////////////////////////////////////////////////
797 
798 bool SdrMeasureObj::hasSpecialDrag() const
799 {
800     return true;
801 }
802 
803 bool SdrMeasureObj::beginSpecialDrag(SdrDragStat& rDrag) const
804 {
805     const SdrHdl* pHdl = rDrag.GetHdl();
806 
807     if(pHdl)
808     {
809         const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
810 
811         if(nHdlNum != 2 && nHdlNum != 3)
812         {
813             rDrag.SetEndDragChangesAttributes(true);
814         }
815 
816         return true;
817     }
818 
819     return false;
820 }
821 
822 bool SdrMeasureObj::applySpecialDrag(SdrDragStat& rDrag)
823 {
824     ImpMeasureRec aMeasureRec;
825     const SdrHdl* pHdl = rDrag.GetHdl();
826     const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
827 
828     ImpTakeAttr(aMeasureRec);
829     ImpEvalDrag(aMeasureRec, rDrag);
830 
831     switch (nHdlNum)
832     {
833         case 2:
834         {
835             aPt1 = aMeasureRec.aPt1;
836             SetTextDirty();
837             break;
838         }
839         case 3:
840         {
841             aPt2 = aMeasureRec.aPt2;
842             SetTextDirty();
843             break;
844         }
845         default:
846         {
847             switch(nHdlNum)
848             {
849                 case 0:
850                 case 1:
851                 {
852                     ImpMeasureRec aOrigMeasureRec;
853                     ImpTakeAttr(aOrigMeasureRec);
854 
855                     if(aMeasureRec.nHelpline1Len != aOrigMeasureRec.nHelpline1Len)
856                     {
857                         SetObjectItem(SdrMeasureHelpline1LenItem(aMeasureRec.nHelpline1Len));
858                     }
859 
860                     if(aMeasureRec.nHelpline2Len != aOrigMeasureRec.nHelpline2Len)
861                     {
862                         SetObjectItem(SdrMeasureHelpline2LenItem(aMeasureRec.nHelpline2Len));
863                     }
864 
865                     break;
866                 }
867 
868                 case 4:
869                 case 5:
870                 {
871                     ImpMeasureRec aOrigMeasureRec;
872                     ImpTakeAttr(aOrigMeasureRec);
873 
874                     if(aMeasureRec.nLineDist != aOrigMeasureRec.nLineDist)
875                     {
876                         SetObjectItem(SdrMeasureLineDistItem(aMeasureRec.nLineDist));
877                     }
878 
879                     if(aMeasureRec.bBelowRefEdge != aOrigMeasureRec.bBelowRefEdge)
880                     {
881                         SetObjectItem(SdrMeasureBelowRefEdgeItem(aMeasureRec.bBelowRefEdge));
882                     }
883                 }
884             }
885         }
886     } // switch
887 
888     SetRectsDirty();
889     SetChanged();
890 
891     return true;
892 }
893 
894 String SdrMeasureObj::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
895 {
896     XubString aStr;
897     return aStr;
898 }
899 
900 void SdrMeasureObj::ImpEvalDrag(ImpMeasureRec& rRec, const SdrDragStat& rDrag) const
901 {
902     long nLineWink=GetAngle(rRec.aPt2-rRec.aPt1);
903     double a=nLineWink*nPi180;
904     double nSin=sin(a);
905     double nCos=cos(a);
906 
907     const SdrHdl* pHdl=rDrag.GetHdl();
908     sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
909     FASTBOOL bOrtho=rDrag.GetView()!=NULL && rDrag.GetView()->IsOrtho();
910     FASTBOOL bBigOrtho=bOrtho && rDrag.GetView()->IsBigOrtho();
911     FASTBOOL bBelow=rRec.bBelowRefEdge;
912     Point aPt(rDrag.GetNow());
913 
914     switch (nHdlNum) {
915         case 0: {
916             RotatePoint(aPt,aPt1,nSin,-nCos);
917             rRec.nHelpline1Len=aPt1.Y()-aPt.Y();
918             if (bBelow) rRec.nHelpline1Len=-rRec.nHelpline1Len;
919             if (bOrtho) rRec.nHelpline2Len=rRec.nHelpline1Len;
920         } break;
921         case 1: {
922             RotatePoint(aPt,aPt2,nSin,-nCos);
923             rRec.nHelpline2Len=aPt2.Y()-aPt.Y();
924             if (bBelow) rRec.nHelpline2Len=-rRec.nHelpline2Len;
925             if (bOrtho) rRec.nHelpline1Len=rRec.nHelpline2Len;
926         } break;
927         case 2: case 3: {
928             FASTBOOL bAnf=nHdlNum==2;
929             Point& rMov=bAnf ? rRec.aPt1 : rRec.aPt2;
930             Point aMov(rMov);
931             Point aFix(bAnf ? rRec.aPt2 : rRec.aPt1);
932             if (bOrtho) {
933                 long ndx0=aMov.X()-aFix.X();
934                 long ndy0=aMov.Y()-aFix.Y();
935                 FASTBOOL bHLin=ndy0==0;
936                 FASTBOOL bVLin=ndx0==0;
937                 if (!bHLin || !bVLin) { // sonst ist aPt1==aPt2
938                     long ndx=aPt.X()-aFix.X();
939                     long ndy=aPt.Y()-aFix.Y();
940                     double nXFact=0; if (!bVLin) nXFact=(double)ndx/(double)ndx0;
941                     double nYFact=0; if (!bHLin) nYFact=(double)ndy/(double)ndy0;
942                     FASTBOOL bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
943                     FASTBOOL bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
944                     if (bHor) ndy=long(ndy0*nXFact);
945                     if (bVer) ndx=long(ndx0*nYFact);
946                     aPt=aFix;
947                     aPt.X()+=ndx;
948                     aPt.Y()+=ndy;
949                 } // else Ortho8
950             }
951             rMov=aPt;
952         } break;
953         case 4: case 5: {
954             long nVal0=rRec.nLineDist;
955             RotatePoint(aPt,(nHdlNum==4 ? aPt1 : aPt2),nSin,-nCos);
956             rRec.nLineDist=aPt.Y()- (nHdlNum==4 ? aPt1.Y() : aPt2.Y());
957             if (bBelow) rRec.nLineDist=-rRec.nLineDist;
958             if (rRec.nLineDist<0) {
959                 rRec.nLineDist=-rRec.nLineDist;
960                 rRec.bBelowRefEdge=!bBelow;
961             }
962             rRec.nLineDist-=rRec.nHelplineOverhang;
963             if (bOrtho) rRec.nLineDist=nVal0;
964         } break;
965     } // switch
966 }
967 
968 ////////////////////////////////////////////////////////////////////////////////////////////////////
969 
970 FASTBOOL SdrMeasureObj::BegCreate(SdrDragStat& rStat)
971 {
972     rStat.SetOrtho8Possible();
973     aPt1=rStat.GetStart();
974     aPt2=rStat.GetNow();
975     SetTextDirty();
976     return sal_True;
977 }
978 
979 FASTBOOL SdrMeasureObj::MovCreate(SdrDragStat& rStat)
980 {
981     SdrView* pView=rStat.GetView();
982     aPt1=rStat.GetStart();
983     aPt2=rStat.GetNow();
984     if (pView!=NULL && pView->IsCreate1stPointAsCenter()) {
985         aPt1+=aPt1;
986         aPt1-=rStat.Now();
987     }
988     SetTextDirty();
989     SetBoundRectDirty();
990     bSnapRectDirty=sal_True;
991     return sal_True;
992 }
993 
994 FASTBOOL SdrMeasureObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
995 {
996     SetTextDirty();
997     SetRectsDirty();
998     return (eCmd==SDRCREATE_FORCEEND || rStat.GetPointAnz()>=2);
999 }
1000 
1001 FASTBOOL SdrMeasureObj::BckCreate(SdrDragStat& /*rStat*/)
1002 {
1003     return sal_False;
1004 }
1005 
1006 void SdrMeasureObj::BrkCreate(SdrDragStat& /*rStat*/)
1007 {
1008 }
1009 
1010 basegfx::B2DPolyPolygon SdrMeasureObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
1011 {
1012     ImpMeasureRec aRec;
1013     ImpMeasurePoly aMPol;
1014 
1015     ImpTakeAttr(aRec);
1016     ImpCalcGeometrics(aRec, aMPol);
1017 
1018     return ImpCalcXPoly(aMPol);
1019 }
1020 
1021 Pointer SdrMeasureObj::GetCreatePointer() const
1022 {
1023     return Pointer(POINTER_CROSS);
1024 }
1025 
1026 void SdrMeasureObj::NbcMove(const Size& rSiz)
1027 {
1028     SdrTextObj::NbcMove(rSiz);
1029     MovePoint(aPt1,rSiz);
1030     MovePoint(aPt2,rSiz);
1031 }
1032 
1033 void SdrMeasureObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
1034 {
1035     SdrTextObj::NbcResize(rRef,xFact,yFact);
1036     ResizePoint(aPt1,rRef,xFact,yFact);
1037     ResizePoint(aPt2,rRef,xFact,yFact);
1038     SetTextDirty();
1039 }
1040 
1041 void SdrMeasureObj::NbcRotate(const Point& rRef, long nWink, double sn, double cs)
1042 {
1043     SdrTextObj::NbcRotate(rRef,nWink,sn,cs);
1044     long nLen0=GetLen(aPt2-aPt1);
1045     RotatePoint(aPt1,rRef,sn,cs);
1046     RotatePoint(aPt2,rRef,sn,cs);
1047     long nLen1=GetLen(aPt2-aPt1);
1048     if (nLen1!=nLen0) { // Aha, Rundungsfehler
1049         long dx=aPt2.X()-aPt1.X();
1050         long dy=aPt2.Y()-aPt1.Y();
1051         dx=BigMulDiv(dx,nLen0,nLen1);
1052         dy=BigMulDiv(dy,nLen0,nLen1);
1053         if (rRef==aPt2) {
1054             aPt1.X()=aPt2.X()-dx;
1055             aPt1.Y()=aPt2.Y()-dy;
1056         } else {
1057             aPt2.X()=aPt1.X()+dx;
1058             aPt2.Y()=aPt1.Y()+dy;
1059         }
1060     }
1061     SetRectsDirty();
1062 }
1063 
1064 void SdrMeasureObj::NbcMirror(const Point& rRef1, const Point& rRef2)
1065 {
1066     SdrTextObj::NbcMirror(rRef1,rRef2);
1067     MirrorPoint(aPt1,rRef1,rRef2);
1068     MirrorPoint(aPt2,rRef1,rRef2);
1069     SetRectsDirty();
1070 }
1071 
1072 void SdrMeasureObj::NbcShear(const Point& rRef, long nWink, double tn, FASTBOOL bVShear)
1073 {
1074     SdrTextObj::NbcShear(rRef,nWink,tn,bVShear);
1075     ShearPoint(aPt1,rRef,tn,bVShear);
1076     ShearPoint(aPt2,rRef,tn,bVShear);
1077     SetRectsDirty();
1078     SetTextDirty();
1079 }
1080 
1081 long SdrMeasureObj::GetRotateAngle() const
1082 {
1083     return GetAngle(aPt2-aPt1);
1084 }
1085 
1086 void SdrMeasureObj::RecalcSnapRect()
1087 {
1088     // #94520# Added correct implementation here.
1089     ImpMeasureRec aRec;
1090     ImpMeasurePoly aMPol;
1091     XPolyPolygon aXPP;
1092 
1093     ImpTakeAttr(aRec);
1094     ImpCalcGeometrics(aRec, aMPol);
1095     aXPP = XPolyPolygon(ImpCalcXPoly(aMPol));
1096     maSnapRect = aXPP.GetBoundRect();
1097 }
1098 
1099 sal_uInt32 SdrMeasureObj::GetSnapPointCount() const
1100 {
1101     return 2L;
1102 }
1103 
1104 Point SdrMeasureObj::GetSnapPoint(sal_uInt32 i) const
1105 {
1106     if (i==0) return aPt1;
1107     else return aPt2;
1108 }
1109 
1110 sal_Bool SdrMeasureObj::IsPolyObj() const
1111 {
1112     return sal_True;
1113 }
1114 
1115 sal_uInt32 SdrMeasureObj::GetPointCount() const
1116 {
1117     return 2L;
1118 }
1119 
1120 Point SdrMeasureObj::GetPoint(sal_uInt32 i) const
1121 {
1122      return (0L == i) ? aPt1 : aPt2;
1123 }
1124 
1125 void SdrMeasureObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
1126 {
1127     if (0L == i)
1128         aPt1=rPnt;
1129     if (1L == i)
1130         aPt2=rPnt;
1131     SetRectsDirty();
1132     SetTextDirty();
1133 }
1134 
1135 SdrObjGeoData* SdrMeasureObj::NewGeoData() const
1136 {
1137     return new SdrMeasureObjGeoData;
1138 }
1139 
1140 void SdrMeasureObj::SaveGeoData(SdrObjGeoData& rGeo) const
1141 {
1142     SdrTextObj::SaveGeoData(rGeo);
1143     SdrMeasureObjGeoData& rMGeo=(SdrMeasureObjGeoData&)rGeo;
1144     rMGeo.aPt1=aPt1;
1145     rMGeo.aPt2=aPt2;
1146 }
1147 
1148 void SdrMeasureObj::RestGeoData(const SdrObjGeoData& rGeo)
1149 {
1150     SdrTextObj::RestGeoData(rGeo);
1151     SdrMeasureObjGeoData& rMGeo=(SdrMeasureObjGeoData&)rGeo;
1152     aPt1=rMGeo.aPt1;
1153     aPt2=rMGeo.aPt2;
1154     SetTextDirty();
1155 }
1156 
1157 SdrObject* SdrMeasureObj::DoConvertToPolyObj(sal_Bool bBezier, bool bAddText) const
1158 {
1159     // get XOR Poly as base
1160     XPolyPolygon aTmpPolyPolygon(TakeXorPoly());
1161 
1162     // get local ItemSet and StyleSheet
1163     SfxItemSet aSet(GetObjectItemSet());
1164     SfxStyleSheet* pStyleSheet = GetStyleSheet();
1165 
1166     // prepare group
1167     SdrObjGroup* pGroup = new SdrObjGroup;
1168     pGroup->SetModel(GetModel());
1169 
1170     // prepare parameters
1171     basegfx::B2DPolyPolygon aPolyPoly;
1172     SdrPathObj* pPath;
1173     sal_uInt16 nCount(aTmpPolyPolygon.Count());
1174     sal_uInt16 nLoopStart(0);
1175 
1176     if(nCount == 3)
1177     {
1178         // three lines, first one is the middle one
1179         aPolyPoly.clear();
1180         aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1181 
1182         pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1183         pPath->SetModel(GetModel());
1184         pPath->SetMergedItemSet(aSet);
1185         pPath->SetStyleSheet(pStyleSheet, true);
1186         pGroup->GetSubList()->NbcInsertObject(pPath);
1187         aSet.Put(XLineStartWidthItem(0L));
1188         aSet.Put(XLineEndWidthItem(0L));
1189         nLoopStart = 1;
1190     }
1191     else if(nCount == 4)
1192     {
1193         // four lines, middle line with gap, so there are two lines used
1194         // which have one arrow each
1195         //sal_Int32 nStartWidth = ((const XLineStartWidthItem&)(aSet.Get(XATTR_LINESTARTWIDTH))).GetValue();
1196         sal_Int32 nEndWidth = ((const XLineEndWidthItem&)(aSet.Get(XATTR_LINEENDWIDTH))).GetValue();
1197         aSet.Put(XLineEndWidthItem(0L));
1198 
1199         aPolyPoly.clear();
1200         aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1201         pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1202         pPath->SetModel(GetModel());
1203         pPath->SetMergedItemSet(aSet);
1204         pPath->SetStyleSheet(pStyleSheet, true);
1205 
1206         pGroup->GetSubList()->NbcInsertObject(pPath);
1207 
1208         aSet.Put(XLineEndWidthItem(nEndWidth));
1209         aSet.Put(XLineStartWidthItem(0L));
1210 
1211         aPolyPoly.clear();
1212         aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
1213         pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1214         pPath->SetModel(GetModel());
1215         pPath->SetMergedItemSet(aSet);
1216         pPath->SetStyleSheet(pStyleSheet, true);
1217 
1218         pGroup->GetSubList()->NbcInsertObject(pPath);
1219 
1220         aSet.Put(XLineEndWidthItem(0L));
1221         nLoopStart = 2;
1222     }
1223     else if(nCount == 5)
1224     {
1225         // five lines, first two are the outer ones
1226         //sal_Int32 nStartWidth = ((const XLineStartWidthItem&)(aSet.Get(XATTR_LINESTARTWIDTH))).GetValue();
1227         sal_Int32 nEndWidth = ((const XLineEndWidthItem&)(aSet.Get(XATTR_LINEENDWIDTH))).GetValue();
1228 
1229         aSet.Put(XLineEndWidthItem(0L));
1230 
1231         aPolyPoly.clear();
1232         aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1233         pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1234         pPath->SetModel(GetModel());
1235         pPath->SetMergedItemSet(aSet);
1236         pPath->SetStyleSheet(pStyleSheet, true);
1237 
1238         pGroup->GetSubList()->NbcInsertObject(pPath);
1239 
1240         aSet.Put(XLineEndWidthItem(nEndWidth));
1241         aSet.Put(XLineStartWidthItem(0L));
1242 
1243         aPolyPoly.clear();
1244         aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
1245         pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1246         pPath->SetModel(GetModel());
1247         pPath->SetMergedItemSet(aSet);
1248         pPath->SetStyleSheet(pStyleSheet, true);
1249 
1250         pGroup->GetSubList()->NbcInsertObject(pPath);
1251 
1252         aSet.Put(XLineEndWidthItem(0L));
1253         nLoopStart = 2;
1254     }
1255 
1256     for(;nLoopStart<nCount;nLoopStart++)
1257     {
1258         aPolyPoly.clear();
1259         aPolyPoly.append(aTmpPolyPolygon[nLoopStart].getB2DPolygon());
1260         pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1261         pPath->SetModel(GetModel());
1262         pPath->SetMergedItemSet(aSet);
1263         pPath->SetStyleSheet(pStyleSheet, true);
1264 
1265         pGroup->GetSubList()->NbcInsertObject(pPath);
1266     }
1267 
1268     if(bAddText)
1269     {
1270         return ImpConvertAddText(pGroup, bBezier);
1271     }
1272     else
1273     {
1274         return pGroup;
1275     }
1276 }
1277 
1278 sal_Bool SdrMeasureObj::BegTextEdit(SdrOutliner& rOutl)
1279 {
1280     UndirtyText();
1281     return SdrTextObj::BegTextEdit(rOutl);
1282 }
1283 
1284 const Size& SdrMeasureObj::GetTextSize() const
1285 {
1286     if (bTextDirty) UndirtyText();
1287     return SdrTextObj::GetTextSize();
1288 }
1289 
1290 OutlinerParaObject* SdrMeasureObj::GetOutlinerParaObject() const
1291 {
1292     if(bTextDirty)
1293         UndirtyText();
1294     return SdrTextObj::GetOutlinerParaObject();
1295 }
1296 
1297 void SdrMeasureObj::NbcSetOutlinerParaObject(OutlinerParaObject* pTextObject)
1298 {
1299     SdrTextObj::NbcSetOutlinerParaObject(pTextObject);
1300     if(SdrTextObj::GetOutlinerParaObject())
1301         SetTextDirty(); // Text neu berechnen!
1302 }
1303 
1304 void SdrMeasureObj::TakeTextRect( SdrOutliner& rOutliner, Rectangle& rTextRect, FASTBOOL bNoEditText,
1305     Rectangle* pAnchorRect, sal_Bool bLineWidth ) const
1306 {
1307     if (bTextDirty) UndirtyText();
1308     SdrTextObj::TakeTextRect( rOutliner, rTextRect, bNoEditText, pAnchorRect, bLineWidth );
1309 }
1310 
1311 void SdrMeasureObj::TakeTextAnchorRect(Rectangle& rAnchorRect) const
1312 {
1313     if (bTextDirty) UndirtyText();
1314     SdrTextObj::TakeTextAnchorRect(rAnchorRect);
1315 }
1316 
1317 void SdrMeasureObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, Rectangle* pViewInit, Rectangle* pViewMin) const
1318 {
1319     if (bTextDirty) UndirtyText();
1320     SdrTextObj::TakeTextEditArea(pPaperMin,pPaperMax,pViewInit,pViewMin);
1321 }
1322 
1323 sal_uInt16 SdrMeasureObj::GetOutlinerViewAnchorMode() const
1324 {
1325     if (bTextDirty) UndirtyText();
1326     ImpMeasureRec aRec;
1327     ImpMeasurePoly aMPol;
1328     ImpTakeAttr(aRec);
1329     ImpCalcGeometrics(aRec,aMPol);
1330 
1331     SdrTextHorzAdjust eTH=GetTextHorizontalAdjust();
1332     SdrTextVertAdjust eTV=GetTextVerticalAdjust();
1333     SdrMeasureTextHPos eMH=aMPol.eUsedTextHPos;
1334     SdrMeasureTextVPos eMV=aMPol.eUsedTextVPos;
1335     FASTBOOL bTextRota90=aRec.bTextRota90;
1336     //int bTextUpsideDown=aRec.bTextUpsideDown;
1337     FASTBOOL bBelowRefEdge=aRec.bBelowRefEdge;
1338 
1339     // bTextUpsideDown muss hier noch ausgewertet werden!!!!
1340     if (!bTextRota90) {
1341         if (eMH==SDRMEASURE_TEXTLEFTOUTSIDE) eTH=SDRTEXTHORZADJUST_RIGHT;
1342         if (eMH==SDRMEASURE_TEXTRIGHTOUTSIDE) eTH=SDRTEXTHORZADJUST_LEFT;
1343         // bei eMH==SDRMEASURE_TEXTINSIDE kann horizontal geankert werden.
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         // bei eMH==SDRMEASURE_TEXTINSIDE kann vertikal geankert werden.
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;
1357         }
1358         if (eMV==SDRMEASURETEXT_BREAKEDLINE || eMV==SDRMEASURETEXT_VERTICALCENTERED) eTH=SDRTEXTHORZADJUST_CENTER;
1359     }
1360 
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;
1374     }
1375     return (sal_uInt16)eRet;
1376 }
1377 
1378 //////////////////////////////////////////////////////////////////////////////
1379 // #i97878#
1380 // TRGetBaseGeometry/TRSetBaseGeometry needs to be based on two positions,
1381 // same as line geometry in SdrPathObj. Thus needs to be overloaded and
1382 // implemented since currently it is derived from SdrTextObj which uses
1383 // a functionality based on SnapRect which is not useful here
1384 
1385 inline double ImplTwipsToMM(double fVal) { return (fVal * (127.0 / 72.0)); }
1386 inline double ImplMMToTwips(double fVal) { return (fVal * (72.0 / 127.0)); }
1387 
1388 sal_Bool SdrMeasureObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
1389 {
1390     // handle the same as a simple line since the definition is based on two points
1391     const basegfx::B2DRange aRange(aPt1.X(), aPt1.Y(), aPt2.X(), aPt2.Y());
1392     basegfx::B2DTuple aScale(aRange.getRange());
1393     basegfx::B2DTuple aTranslate(aRange.getMinimum());
1394 
1395     // position maybe relative to anchorpos, convert
1396     if( pModel->IsWriter() )
1397     {
1398         if(GetAnchorPos().X() || GetAnchorPos().Y())
1399         {
1400             aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
1401         }
1402     }
1403 
1404     // force MapUnit to 100th mm
1405     SfxMapUnit eMapUnit = pModel->GetItemPool().GetMetric(0);
1406     if(eMapUnit != SFX_MAPUNIT_100TH_MM)
1407     {
1408         switch(eMapUnit)
1409         {
1410             case SFX_MAPUNIT_TWIP :
1411             {
1412                 // postion
1413                 aTranslate.setX(ImplTwipsToMM(aTranslate.getX()));
1414                 aTranslate.setY(ImplTwipsToMM(aTranslate.getY()));
1415 
1416                 // size
1417                 aScale.setX(ImplTwipsToMM(aScale.getX()));
1418                 aScale.setY(ImplTwipsToMM(aScale.getY()));
1419 
1420                 break;
1421             }
1422             default:
1423             {
1424                 DBG_ERROR("TRGetBaseGeometry: Missing unit translation to 100th mm!");
1425             }
1426         }
1427     }
1428 
1429     // build return value matrix
1430     rMatrix = basegfx::tools::createScaleTranslateB2DHomMatrix(aScale, aTranslate);
1431 
1432     return sal_True;
1433 }
1434 
1435 void SdrMeasureObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
1436 {
1437     // use given transformation to derive the two defining points from unit line
1438     basegfx::B2DPoint aPosA(rMatrix * basegfx::B2DPoint(0.0, 0.0));
1439     basegfx::B2DPoint aPosB(rMatrix * basegfx::B2DPoint(1.0, 0.0));
1440 
1441     // force metric to pool metric
1442     SfxMapUnit eMapUnit = pModel->GetItemPool().GetMetric(0);
1443     if(eMapUnit != SFX_MAPUNIT_100TH_MM)
1444     {
1445         switch(eMapUnit)
1446         {
1447             case SFX_MAPUNIT_TWIP :
1448             {
1449                 // position
1450                 aPosA.setX(ImplMMToTwips(aPosA.getX()));
1451                 aPosA.setY(ImplMMToTwips(aPosA.getY()));
1452                 aPosB.setX(ImplMMToTwips(aPosB.getX()));
1453                 aPosB.setY(ImplMMToTwips(aPosB.getY()));
1454 
1455                 break;
1456             }
1457             default:
1458             {
1459                 DBG_ERROR("TRSetBaseGeometry: Missing unit translation to PoolMetric!");
1460             }
1461         }
1462     }
1463 
1464     if( pModel->IsWriter() )
1465     {
1466         // if anchor is used, make position relative to it
1467         if(GetAnchorPos().X() || GetAnchorPos().Y())
1468         {
1469             const basegfx::B2DVector aAnchorOffset(GetAnchorPos().X(), GetAnchorPos().Y());
1470 
1471             aPosA += aAnchorOffset;
1472             aPosB += aAnchorOffset;
1473         }
1474     }
1475 
1476     // derive new model data
1477     const Point aNewPt1(basegfx::fround(aPosA.getX()), basegfx::fround(aPosA.getY()));
1478     const Point aNewPt2(basegfx::fround(aPosB.getX()), basegfx::fround(aPosB.getY()));
1479 
1480     if(aNewPt1 != aPt1 || aNewPt2 != aPt2)
1481     {
1482         // set model values and broadcast
1483         Rectangle aBoundRect0; if (pUserCall!=NULL) aBoundRect0=GetLastBoundRect();
1484 
1485         aPt1 = aNewPt1;
1486         aPt2 = aNewPt2;
1487 
1488         SetTextDirty();
1489         ActionChanged();
1490         SetChanged();
1491         BroadcastObjectChange();
1492         SendUserCall(SDRUSERCALL_MOVEONLY,aBoundRect0);
1493     }
1494 }
1495 
1496 //////////////////////////////////////////////////////////////////////////////
1497 // eof
1498