bump product version to 5.0.4.1
[LibreOffice.git] / svx / source / sdr / primitive2d / sdrmeasureprimitive2d.cxx
blob146bb629d7cd8811a5c86d80480f53a09546b559
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sdr/primitive2d/sdrmeasureprimitive2d.hxx>
21 #include <svx/sdr/primitive2d/sdrdecompositiontools.hxx>
22 #include <basegfx/matrix/b2dhommatrix.hxx>
23 #include <sdr/primitive2d/sdrtextprimitive2d.hxx>
24 #include <svx/sdr/attribute/sdrtextattribute.hxx>
25 #include <basegfx/polygon/b2dpolypolygontools.hxx>
26 #include <basegfx/tools/canvastools.hxx>
27 #include <drawinglayer/primitive2d/groupprimitive2d.hxx>
28 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
29 #include <basegfx/matrix/b2dhommatrixtools.hxx>
30 #include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
31 #include <boost/scoped_ptr.hpp>
34 using namespace com::sun::star;
38 namespace drawinglayer
40 namespace primitive2d
42 Primitive2DReference SdrMeasurePrimitive2D::impCreatePart(
43 const attribute::SdrLineAttribute& rLineAttribute,
44 const basegfx::B2DHomMatrix& rObjectMatrix,
45 const basegfx::B2DPoint& rStart,
46 const basegfx::B2DPoint& rEnd,
47 bool bLeftActive,
48 bool bRightActive) const
50 const attribute::SdrLineStartEndAttribute& rLineStartEnd = getSdrLSTAttribute().getLineStartEnd();
51 basegfx::B2DPolygon aPolygon;
53 aPolygon.append(rStart);
54 aPolygon.append(rEnd);
55 aPolygon.transform(rObjectMatrix);
57 if(rLineStartEnd.isDefault() || (!bLeftActive && !bRightActive))
59 return createPolygonLinePrimitive(
60 aPolygon,
61 rLineAttribute,
62 attribute::SdrLineStartEndAttribute());
65 if(bLeftActive && bRightActive)
67 return createPolygonLinePrimitive(
68 aPolygon,
69 rLineAttribute,
70 rLineStartEnd);
73 const basegfx::B2DPolyPolygon aEmpty;
74 const attribute::SdrLineStartEndAttribute aLineStartEnd(
75 bLeftActive ? rLineStartEnd.getStartPolyPolygon() : aEmpty, bRightActive ? rLineStartEnd.getEndPolyPolygon() : aEmpty,
76 bLeftActive ? rLineStartEnd.getStartWidth() : 0.0, bRightActive ? rLineStartEnd.getEndWidth() : 0.0,
77 bLeftActive && rLineStartEnd.isStartActive(), bRightActive && rLineStartEnd.isEndActive(),
78 bLeftActive && rLineStartEnd.isStartCentered(), bRightActive && rLineStartEnd.isEndCentered());
80 return createPolygonLinePrimitive(
81 aPolygon,
82 rLineAttribute,
83 aLineStartEnd);
86 Primitive2DSequence SdrMeasurePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& aViewInformation) const
88 Primitive2DSequence aRetval;
89 boost::scoped_ptr<SdrBlockTextPrimitive2D> pBlockText;
90 basegfx::B2DRange aTextRange;
91 double fTextX((getStart().getX() + getEnd().getX()) * 0.5);
92 double fTextY((getStart().getX() + getEnd().getX()) * 0.5);
93 const basegfx::B2DVector aLine(getEnd() - getStart());
94 const double fDistance(aLine.getLength());
95 const double fAngle(atan2(aLine.getY(), aLine.getX()));
96 bool bAutoUpsideDown(false);
97 const attribute::SdrTextAttribute rTextAttribute = getSdrLSTAttribute().getText();
98 const basegfx::B2DHomMatrix aObjectMatrix(
99 basegfx::tools::createShearXRotateTranslateB2DHomMatrix(0.0, fAngle, getStart()));
101 // preapare text, but do not add yet; it needs to be aligned to
102 // the line geometry
103 if(!rTextAttribute.isDefault())
105 basegfx::B2DHomMatrix aTextMatrix;
106 double fTestAngle(fAngle);
108 if(getTextRotation())
110 aTextMatrix.rotate(-90.0 * F_PI180);
111 fTestAngle -= (90.0 * F_PI180);
113 if(getTextAutoAngle() && fTestAngle < -F_PI)
115 fTestAngle += F_2PI;
119 if(getTextAutoAngle())
121 if(fTestAngle > (F_PI / 4.0) || fTestAngle < (-F_PI * (3.0 / 4.0)))
123 bAutoUpsideDown = true;
127 // create primitive and get text range
128 pBlockText.reset(new SdrBlockTextPrimitive2D(
129 &rTextAttribute.getSdrText(),
130 rTextAttribute.getOutlinerParaObject(),
131 aTextMatrix,
132 SDRTEXTHORZADJUST_CENTER,
133 SDRTEXTVERTADJUST_CENTER,
134 rTextAttribute.isScroll(),
135 false,
136 false,
137 false,
138 false));
140 aTextRange = pBlockText->getB2DRange(aViewInformation);
143 // prepare line attribute and result
145 const attribute::SdrLineAttribute rLineAttribute(getSdrLSTAttribute().getLine());
146 bool bArrowsOutside(false);
147 bool bMainLineSplitted(false);
148 const attribute::SdrLineStartEndAttribute& rLineStartEnd = getSdrLSTAttribute().getLineStartEnd();
149 double fStartArrowW(0.0);
150 double fStartArrowH(0.0);
151 double fEndArrowW(0.0);
152 double fEndArrowH(0.0);
154 if(!rLineStartEnd.isDefault())
156 if(rLineStartEnd.isStartActive())
158 const basegfx::B2DRange aArrowRange(basegfx::tools::getRange(rLineStartEnd.getStartPolyPolygon()));
159 fStartArrowW = rLineStartEnd.getStartWidth();
160 fStartArrowH = aArrowRange.getHeight() * fStartArrowW / aArrowRange.getWidth();
162 if(rLineStartEnd.isStartCentered())
164 fStartArrowH *= 0.5;
168 if(rLineStartEnd.isEndActive())
170 const basegfx::B2DRange aArrowRange(basegfx::tools::getRange(rLineStartEnd.getEndPolyPolygon()));
171 fEndArrowW = rLineStartEnd.getEndWidth();
172 fEndArrowH = aArrowRange.getHeight() * fEndArrowW / aArrowRange.getWidth();
174 if(rLineStartEnd.isEndCentered())
176 fEndArrowH *= 0.5;
181 const double fSpaceNeededByArrows(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.5));
182 const double fArrowsOutsideLen((fStartArrowH + fEndArrowH + fStartArrowW + fEndArrowW) * 0.5);
183 const double fHalfLineWidth(rLineAttribute.getWidth() * 0.5);
185 if(fSpaceNeededByArrows > fDistance)
187 bArrowsOutside = true;
190 MeasureTextPosition eHorizontal(getHorizontal());
191 MeasureTextPosition eVertical(getVertical());
193 if(MEASURETEXTPOSITION_AUTOMATIC == eVertical)
195 eVertical = MEASURETEXTPOSITION_NEGATIVE;
198 if(MEASURETEXTPOSITION_CENTERED == eVertical)
200 bMainLineSplitted = true;
203 if(MEASURETEXTPOSITION_AUTOMATIC == eHorizontal)
205 if(aTextRange.getWidth() > fDistance)
207 eHorizontal = MEASURETEXTPOSITION_NEGATIVE;
209 else
211 eHorizontal = MEASURETEXTPOSITION_CENTERED;
214 if(bMainLineSplitted)
216 if(aTextRange.getWidth() + fSpaceNeededByArrows > fDistance)
218 bArrowsOutside = true;
221 else
223 const double fSmallArrowNeed(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.125));
225 if(aTextRange.getWidth() + fSmallArrowNeed > fDistance)
227 bArrowsOutside = true;
232 if(MEASURETEXTPOSITION_CENTERED != eHorizontal)
234 bArrowsOutside = true;
237 // switch text above/below?
238 if(getBelow() || (bAutoUpsideDown && !getTextRotation()))
240 if(MEASURETEXTPOSITION_NEGATIVE == eVertical)
242 eVertical = MEASURETEXTPOSITION_POSITIVE;
244 else if(MEASURETEXTPOSITION_POSITIVE == eVertical)
246 eVertical = MEASURETEXTPOSITION_NEGATIVE;
250 const double fMainLineOffset(getBelow() ? getDistance() : -getDistance());
251 const basegfx::B2DPoint aMainLeft(0.0, fMainLineOffset);
252 const basegfx::B2DPoint aMainRight(fDistance, fMainLineOffset);
254 // main line
255 if(bArrowsOutside)
257 double fLenLeft(fArrowsOutsideLen);
258 double fLenRight(fArrowsOutsideLen);
260 if(!bMainLineSplitted)
262 if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal)
264 fLenLeft = fStartArrowH + aTextRange.getWidth();
266 else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal)
268 fLenRight = fEndArrowH + aTextRange.getWidth();
272 const basegfx::B2DPoint aMainLeftLeft(aMainLeft.getX() - fLenLeft, aMainLeft.getY());
273 const basegfx::B2DPoint aMainRightRight(aMainRight.getX() + fLenRight, aMainRight.getY());
275 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeftLeft, aMainLeft, false, true));
276 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainRight, aMainRightRight, true, false));
278 if(!bMainLineSplitted || MEASURETEXTPOSITION_CENTERED != eHorizontal)
280 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, false, false));
283 else
285 if(bMainLineSplitted)
287 const double fHalfLength((fDistance - (aTextRange.getWidth() + (fStartArrowH + fEndArrowH) * 0.25)) * 0.5);
288 const basegfx::B2DPoint aMainInnerLeft(aMainLeft.getX() + fHalfLength, aMainLeft.getY());
289 const basegfx::B2DPoint aMainInnerRight(aMainRight.getX() - fHalfLength, aMainRight.getY());
291 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainInnerLeft, true, false));
292 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainInnerRight, aMainRight, false, true));
294 else
296 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, true, true));
300 // left/right help line value preparation
301 const double fTopEdge(getBelow() ? getUpper() + getDistance() : -getUpper() - getDistance());
302 const double fBottomLeft(getBelow() ? getLower() - getLeftDelta() : getLeftDelta() - getLower());
303 const double fBottomRight(getBelow() ? getLower() - getRightDelta() : getRightDelta() - getLower());
305 // left help line
306 const basegfx::B2DPoint aLeftUp(0.0, fTopEdge);
307 const basegfx::B2DPoint aLeftDown(0.0, fBottomLeft);
309 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aLeftDown, aLeftUp, false, false));
311 // right help line
312 const basegfx::B2DPoint aRightUp(fDistance, fTopEdge);
313 const basegfx::B2DPoint aRightDown(fDistance, fBottomRight);
315 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aRightDown, aRightUp, false, false));
317 // text horizontal position
318 if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal)
320 // left
321 const double fSmall(fArrowsOutsideLen * 0.18);
322 fTextX = aMainLeft.getX() - (fStartArrowH + aTextRange.getWidth() + fSmall + fHalfLineWidth);
324 if(bMainLineSplitted)
326 fTextX -= (fArrowsOutsideLen - fStartArrowH);
329 if(!rTextAttribute.isDefault())
331 fTextX -= rTextAttribute.getTextRightDistance();
334 else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal)
336 // right
337 const double fSmall(fArrowsOutsideLen * 0.18);
338 fTextX = aMainRight.getX() + (fEndArrowH + fSmall + fHalfLineWidth);
340 if(bMainLineSplitted)
342 fTextX += (fArrowsOutsideLen - fEndArrowH);
345 if(!rTextAttribute.isDefault())
347 fTextX += rTextAttribute.getTextLeftDistance();
350 else // MEASURETEXTPOSITION_CENTERED
352 // centered
353 fTextX = aMainLeft.getX() + ((fDistance - aTextRange.getWidth()) * 0.5);
355 if(!rTextAttribute.isDefault())
357 fTextX += (rTextAttribute.getTextLeftDistance() - rTextAttribute.getTextRightDistance()) / 2L;
361 // text vertical position
362 if(MEASURETEXTPOSITION_NEGATIVE == eVertical)
364 // top
365 const double fSmall(fArrowsOutsideLen * 0.10);
366 fTextY = aMainLeft.getY() - (aTextRange.getHeight() + fSmall + fHalfLineWidth);
368 if(!rTextAttribute.isDefault())
370 fTextY -= rTextAttribute.getTextLowerDistance();
373 else if(MEASURETEXTPOSITION_POSITIVE == eVertical)
375 // bottom
376 const double fSmall(fArrowsOutsideLen * 0.10);
377 fTextY = aMainLeft.getY() + (fSmall + fHalfLineWidth);
379 if(!rTextAttribute.isDefault())
381 fTextY += rTextAttribute.getTextUpperDistance();
384 else // MEASURETEXTPOSITION_CENTERED
386 // centered
387 fTextY = aMainLeft.getY() - (aTextRange.getHeight() * 0.5);
389 if(!rTextAttribute.isDefault())
391 fTextY += (rTextAttribute.getTextUpperDistance() - rTextAttribute.getTextLowerDistance()) / 2L;
396 if(getSdrLSTAttribute().getLine().isDefault())
398 // embed line geometry to invisible (100% transparent) line group for HitTest
399 const Primitive2DReference xHiddenLines(new HiddenGeometryPrimitive2D(aRetval));
401 aRetval = Primitive2DSequence(&xHiddenLines, 1);
404 if(pBlockText)
406 // create transformation to text primitive end position
407 basegfx::B2DHomMatrix aChange;
409 // handle auto text rotation
410 if(bAutoUpsideDown)
412 aChange.rotate(F_PI);
415 // move from aTextRange.TopLeft to fTextX, fTextY
416 aChange.translate(fTextX - aTextRange.getMinX(), fTextY - aTextRange.getMinY());
418 // apply object matrix
419 aChange *= aObjectMatrix;
421 // apply to existing text primitive
422 SdrTextPrimitive2D* pNewBlockText = pBlockText->createTransformedClone(aChange);
423 OSL_ENSURE(pNewBlockText, "SdrMeasurePrimitive2D::create2DDecomposition: Could not create transformed clone of text primitive (!)");
424 pBlockText.reset();
426 // add to local primitives
427 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, Primitive2DReference(pNewBlockText));
430 // add shadow
431 if(!getSdrLSTAttribute().getShadow().isDefault())
433 aRetval = createEmbeddedShadowPrimitive(
434 aRetval,
435 getSdrLSTAttribute().getShadow());
438 return aRetval;
441 SdrMeasurePrimitive2D::SdrMeasurePrimitive2D(
442 const attribute::SdrLineShadowTextAttribute& rSdrLSTAttribute,
443 const basegfx::B2DPoint& rStart,
444 const basegfx::B2DPoint& rEnd,
445 MeasureTextPosition eHorizontal,
446 MeasureTextPosition eVertical,
447 double fDistance,
448 double fUpper,
449 double fLower,
450 double fLeftDelta,
451 double fRightDelta,
452 bool bBelow,
453 bool bTextRotation,
454 bool bTextAutoAngle)
455 : BufferedDecompositionPrimitive2D(),
456 maSdrLSTAttribute(rSdrLSTAttribute),
457 maStart(rStart),
458 maEnd(rEnd),
459 meHorizontal(eHorizontal),
460 meVertical(eVertical),
461 mfDistance(fDistance),
462 mfUpper(fUpper),
463 mfLower(fLower),
464 mfLeftDelta(fLeftDelta),
465 mfRightDelta(fRightDelta),
466 mbBelow(bBelow),
467 mbTextRotation(bTextRotation),
468 mbTextAutoAngle(bTextAutoAngle)
472 bool SdrMeasurePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
474 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
476 const SdrMeasurePrimitive2D& rCompare = static_cast<const SdrMeasurePrimitive2D&>(rPrimitive);
478 return (getStart() == rCompare.getStart()
479 && getEnd() == rCompare.getEnd()
480 && getHorizontal() == rCompare.getHorizontal()
481 && getVertical() == rCompare.getVertical()
482 && getDistance() == rCompare.getDistance()
483 && getUpper() == rCompare.getUpper()
484 && getLower() == rCompare.getLower()
485 && getLeftDelta() == rCompare.getLeftDelta()
486 && getRightDelta() == rCompare.getRightDelta()
487 && getBelow() == rCompare.getBelow()
488 && getTextRotation() == rCompare.getTextRotation()
489 && getTextAutoAngle() == rCompare.getTextAutoAngle()
490 && getSdrLSTAttribute() == rCompare.getSdrLSTAttribute());
493 return false;
496 // provide unique ID
497 ImplPrimitive2DIDBlock(SdrMeasurePrimitive2D, PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D)
499 } // end of namespace primitive2d
500 } // end of namespace drawinglayer
502 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */