update credits
[LibreOffice.git] / svx / source / sdr / primitive2d / sdrmeasureprimitive2d.cxx
blobe76d1f4138025b5a076921ef65007b03f0ad30e3
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 <svx/sdr/primitive2d/sdrmeasureprimitive2d.hxx>
21 #include <svx/sdr/primitive2d/sdrdecompositiontools.hxx>
22 #include <basegfx/matrix/b2dhommatrix.hxx>
23 #include <svx/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>
32 //////////////////////////////////////////////////////////////////////////////
34 using namespace com::sun::star;
36 //////////////////////////////////////////////////////////////////////////////
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);
56 if(rLineStartEnd.isDefault() || (!bLeftActive && !bRightActive))
58 return createPolygonLinePrimitive(
59 aPolygon,
60 rObjectMatrix,
61 rLineAttribute,
62 attribute::SdrLineStartEndAttribute());
65 if(bLeftActive && bRightActive)
67 return createPolygonLinePrimitive(
68 aPolygon,
69 rObjectMatrix,
70 rLineAttribute,
71 rLineStartEnd);
74 const basegfx::B2DPolyPolygon aEmpty;
75 const attribute::SdrLineStartEndAttribute aLineStartEnd(
76 bLeftActive ? rLineStartEnd.getStartPolyPolygon() : aEmpty, bRightActive ? rLineStartEnd.getEndPolyPolygon() : aEmpty,
77 bLeftActive ? rLineStartEnd.getStartWidth() : 0.0, bRightActive ? rLineStartEnd.getEndWidth() : 0.0,
78 bLeftActive ? rLineStartEnd.isStartActive() : false, bRightActive ? rLineStartEnd.isEndActive() : false,
79 bLeftActive ? rLineStartEnd.isStartCentered() : false, bRightActive? rLineStartEnd.isEndCentered() : false);
81 return createPolygonLinePrimitive(aPolygon, rObjectMatrix, rLineAttribute, aLineStartEnd);
84 Primitive2DSequence SdrMeasurePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& aViewInformation) const
86 Primitive2DSequence aRetval;
87 SdrBlockTextPrimitive2D* pBlockText = 0;
88 basegfx::B2DRange aTextRange;
89 double fTextX((getStart().getX() + getEnd().getX()) * 0.5);
90 double fTextY((getStart().getX() + getEnd().getX()) * 0.5);
91 const basegfx::B2DVector aLine(getEnd() - getStart());
92 const double fDistance(aLine.getLength());
93 const double fAngle(atan2(aLine.getY(), aLine.getX()));
94 bool bAutoUpsideDown(false);
95 const attribute::SdrTextAttribute rTextAttribute = getSdrLSTAttribute().getText();
96 const basegfx::B2DHomMatrix aObjectMatrix(
97 basegfx::tools::createShearXRotateTranslateB2DHomMatrix(0.0, fAngle, getStart()));
99 // preapare text, but do not add yet; it needs to be aligned to
100 // the line geometry
101 if(!rTextAttribute.isDefault())
103 basegfx::B2DHomMatrix aTextMatrix;
104 double fTestAngle(fAngle);
106 if(getTextRotation())
108 aTextMatrix.rotate(-90.0 * F_PI180);
109 fTestAngle -= (90.0 * F_PI180);
111 if(getTextAutoAngle() && fTestAngle < -F_PI)
113 fTestAngle += F_2PI;
117 if(getTextAutoAngle())
119 if(fTestAngle > (F_PI / 4.0) || fTestAngle < (-F_PI * (3.0 / 4.0)))
121 bAutoUpsideDown = true;
125 // create primitive and get text range
126 pBlockText = new SdrBlockTextPrimitive2D(
127 &rTextAttribute.getSdrText(),
128 rTextAttribute.getOutlinerParaObject(),
129 aTextMatrix,
130 SDRTEXTHORZADJUST_CENTER,
131 SDRTEXTVERTADJUST_CENTER,
132 rTextAttribute.isScroll(),
133 false,
134 false,
135 false,
136 false);
138 aTextRange = pBlockText->getB2DRange(aViewInformation);
141 // prepare line attribute and result
143 const attribute::SdrLineAttribute rLineAttribute(getSdrLSTAttribute().getLine());
144 bool bArrowsOutside(false);
145 bool bMainLineSplitted(false);
146 const attribute::SdrLineStartEndAttribute& rLineStartEnd = getSdrLSTAttribute().getLineStartEnd();
147 double fStartArrowW(0.0);
148 double fStartArrowH(0.0);
149 double fEndArrowW(0.0);
150 double fEndArrowH(0.0);
152 if(!rLineStartEnd.isDefault())
154 if(rLineStartEnd.isStartActive())
156 const basegfx::B2DRange aArrowRange(basegfx::tools::getRange(rLineStartEnd.getStartPolyPolygon()));
157 fStartArrowW = rLineStartEnd.getStartWidth();
158 fStartArrowH = aArrowRange.getHeight() * fStartArrowW / aArrowRange.getWidth();
160 if(rLineStartEnd.isStartCentered())
162 fStartArrowH *= 0.5;
166 if(rLineStartEnd.isEndActive())
168 const basegfx::B2DRange aArrowRange(basegfx::tools::getRange(rLineStartEnd.getEndPolyPolygon()));
169 fEndArrowW = rLineStartEnd.getEndWidth();
170 fEndArrowH = aArrowRange.getHeight() * fEndArrowW / aArrowRange.getWidth();
172 if(rLineStartEnd.isEndCentered())
174 fEndArrowH *= 0.5;
179 const double fSpaceNeededByArrows(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.5));
180 const double fArrowsOutsideLen((fStartArrowH + fEndArrowH + fStartArrowW + fEndArrowW) * 0.5);
181 const double fHalfLineWidth(rLineAttribute.getWidth() * 0.5);
183 if(fSpaceNeededByArrows > fDistance)
185 bArrowsOutside = true;
188 MeasureTextPosition eHorizontal(getHorizontal());
189 MeasureTextPosition eVertical(getVertical());
191 if(MEASURETEXTPOSITION_AUTOMATIC == eVertical)
193 eVertical = MEASURETEXTPOSITION_NEGATIVE;
196 if(MEASURETEXTPOSITION_CENTERED == eVertical)
198 bMainLineSplitted = true;
201 if(MEASURETEXTPOSITION_AUTOMATIC == eHorizontal)
203 if(aTextRange.getWidth() > fDistance)
205 eHorizontal = MEASURETEXTPOSITION_NEGATIVE;
207 else
209 eHorizontal = MEASURETEXTPOSITION_CENTERED;
212 if(bMainLineSplitted)
214 if(aTextRange.getWidth() + fSpaceNeededByArrows > fDistance)
216 bArrowsOutside = true;
219 else
221 const double fSmallArrowNeed(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.125));
223 if(aTextRange.getWidth() + fSmallArrowNeed > fDistance)
225 bArrowsOutside = true;
230 if(MEASURETEXTPOSITION_CENTERED != eHorizontal)
232 bArrowsOutside = true;
235 // switch text above/below?
236 if(getBelow() || (bAutoUpsideDown && !getTextRotation()))
238 if(MEASURETEXTPOSITION_NEGATIVE == eVertical)
240 eVertical = MEASURETEXTPOSITION_POSITIVE;
242 else if(MEASURETEXTPOSITION_POSITIVE == eVertical)
244 eVertical = MEASURETEXTPOSITION_NEGATIVE;
248 const double fMainLineOffset(getBelow() ? getDistance() : -getDistance());
249 const basegfx::B2DPoint aMainLeft(0.0, fMainLineOffset);
250 const basegfx::B2DPoint aMainRight(fDistance, fMainLineOffset);
252 // main line
253 if(bArrowsOutside)
255 double fLenLeft(fArrowsOutsideLen);
256 double fLenRight(fArrowsOutsideLen);
258 if(!bMainLineSplitted)
260 if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal)
262 fLenLeft = fStartArrowH + aTextRange.getWidth();
264 else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal)
266 fLenRight = fEndArrowH + aTextRange.getWidth();
270 const basegfx::B2DPoint aMainLeftLeft(aMainLeft.getX() - fLenLeft, aMainLeft.getY());
271 const basegfx::B2DPoint aMainRightRight(aMainRight.getX() + fLenRight, aMainRight.getY());
273 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeftLeft, aMainLeft, false, true));
274 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainRight, aMainRightRight, true, false));
276 if(!bMainLineSplitted || MEASURETEXTPOSITION_CENTERED != eHorizontal)
278 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, false, false));
281 else
283 if(bMainLineSplitted)
285 const double fHalfLength((fDistance - (aTextRange.getWidth() + (fStartArrowH + fEndArrowH) * 0.25)) * 0.5);
286 const basegfx::B2DPoint aMainInnerLeft(aMainLeft.getX() + fHalfLength, aMainLeft.getY());
287 const basegfx::B2DPoint aMainInnerRight(aMainRight.getX() - fHalfLength, aMainRight.getY());
289 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainInnerLeft, true, false));
290 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainInnerRight, aMainRight, false, true));
292 else
294 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, true, true));
298 // left/right help line value preparation
299 const double fTopEdge(getBelow() ? getUpper() + getDistance() : -getUpper() - getDistance());
300 const double fBottomLeft(getBelow() ? getLower() - getLeftDelta() : getLeftDelta() - getLower());
301 const double fBottomRight(getBelow() ? getLower() - getRightDelta() : getRightDelta() - getLower());
303 // left help line
304 const basegfx::B2DPoint aLeftUp(0.0, fTopEdge);
305 const basegfx::B2DPoint aLeftDown(0.0, fBottomLeft);
307 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aLeftDown, aLeftUp, false, false));
309 // right help line
310 const basegfx::B2DPoint aRightUp(fDistance, fTopEdge);
311 const basegfx::B2DPoint aRightDown(fDistance, fBottomRight);
313 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aRightDown, aRightUp, false, false));
315 // text horizontal position
316 if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal)
318 // left
319 const double fSmall(fArrowsOutsideLen * 0.18);
320 fTextX = aMainLeft.getX() - (fStartArrowH + aTextRange.getWidth() + fSmall + fHalfLineWidth);
322 if(bMainLineSplitted)
324 fTextX -= (fArrowsOutsideLen - fStartArrowH);
327 if(!rTextAttribute.isDefault())
329 fTextX -= rTextAttribute.getTextRightDistance();
332 else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal)
334 // right
335 const double fSmall(fArrowsOutsideLen * 0.18);
336 fTextX = aMainRight.getX() + (fEndArrowH + fSmall + fHalfLineWidth);
338 if(bMainLineSplitted)
340 fTextX += (fArrowsOutsideLen - fEndArrowH);
343 if(!rTextAttribute.isDefault())
345 fTextX += rTextAttribute.getTextLeftDistance();
348 else // MEASURETEXTPOSITION_CENTERED
350 // centered
351 fTextX = aMainLeft.getX() + ((fDistance - aTextRange.getWidth()) * 0.5);
353 if(!rTextAttribute.isDefault())
355 fTextX += (rTextAttribute.getTextLeftDistance() - rTextAttribute.getTextRightDistance()) / 2L;
359 // text vertical position
360 if(MEASURETEXTPOSITION_NEGATIVE == eVertical)
362 // top
363 const double fSmall(fArrowsOutsideLen * 0.10);
364 fTextY = aMainLeft.getY() - (aTextRange.getHeight() + fSmall + fHalfLineWidth);
366 if(!rTextAttribute.isDefault())
368 fTextY -= rTextAttribute.getTextLowerDistance();
371 else if(MEASURETEXTPOSITION_POSITIVE == eVertical)
373 // bottom
374 const double fSmall(fArrowsOutsideLen * 0.10);
375 fTextY = aMainLeft.getY() + (fSmall + fHalfLineWidth);
377 if(!rTextAttribute.isDefault())
379 fTextY += rTextAttribute.getTextUpperDistance();
382 else // MEASURETEXTPOSITION_CENTERED
384 // centered
385 fTextY = aMainLeft.getY() - (aTextRange.getHeight() * 0.5);
387 if(!rTextAttribute.isDefault())
389 fTextY += (rTextAttribute.getTextUpperDistance() - rTextAttribute.getTextLowerDistance()) / 2L;
394 if(getSdrLSTAttribute().getLine().isDefault())
396 // embed line geometry to invisible (100% transparent) line group for HitTest
397 const Primitive2DReference xHiddenLines(new HiddenGeometryPrimitive2D(aRetval));
399 aRetval = Primitive2DSequence(&xHiddenLines, 1);
402 if(pBlockText)
404 // create transformation to text primitive end position
405 basegfx::B2DHomMatrix aChange;
407 // handle auto text rotation
408 if(bAutoUpsideDown)
410 aChange.rotate(F_PI);
413 // move from aTextRange.TopLeft to fTextX, fTextY
414 aChange.translate(fTextX - aTextRange.getMinX(), fTextY - aTextRange.getMinY());
416 // apply object matrix
417 aChange *= aObjectMatrix;
419 // apply to existing text primitive
420 SdrTextPrimitive2D* pNewBlockText = pBlockText->createTransformedClone(aChange);
421 OSL_ENSURE(pNewBlockText, "SdrMeasurePrimitive2D::create2DDecomposition: Could not create transformed clone of text primitive (!)");
422 delete pBlockText;
424 // add to local primitives
425 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, Primitive2DReference(pNewBlockText));
428 // add shadow
429 if(!getSdrLSTAttribute().getShadow().isDefault())
431 aRetval = createEmbeddedShadowPrimitive(
432 aRetval,
433 getSdrLSTAttribute().getShadow());
436 return aRetval;
439 SdrMeasurePrimitive2D::SdrMeasurePrimitive2D(
440 const attribute::SdrLineShadowTextAttribute& rSdrLSTAttribute,
441 const basegfx::B2DPoint& rStart,
442 const basegfx::B2DPoint& rEnd,
443 MeasureTextPosition eHorizontal,
444 MeasureTextPosition eVertical,
445 double fDistance,
446 double fUpper,
447 double fLower,
448 double fLeftDelta,
449 double fRightDelta,
450 bool bBelow,
451 bool bTextRotation,
452 bool bTextAutoAngle)
453 : BufferedDecompositionPrimitive2D(),
454 maSdrLSTAttribute(rSdrLSTAttribute),
455 maStart(rStart),
456 maEnd(rEnd),
457 meHorizontal(eHorizontal),
458 meVertical(eVertical),
459 mfDistance(fDistance),
460 mfUpper(fUpper),
461 mfLower(fLower),
462 mfLeftDelta(fLeftDelta),
463 mfRightDelta(fRightDelta),
464 mbBelow(bBelow),
465 mbTextRotation(bTextRotation),
466 mbTextAutoAngle(bTextAutoAngle)
470 bool SdrMeasurePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
472 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
474 const SdrMeasurePrimitive2D& rCompare = (SdrMeasurePrimitive2D&)rPrimitive;
476 return (getStart() == rCompare.getStart()
477 && getEnd() == rCompare.getEnd()
478 && getHorizontal() == rCompare.getHorizontal()
479 && getVertical() == rCompare.getVertical()
480 && getDistance() == rCompare.getDistance()
481 && getUpper() == rCompare.getUpper()
482 && getLower() == rCompare.getLower()
483 && getLeftDelta() == rCompare.getLeftDelta()
484 && getRightDelta() == rCompare.getRightDelta()
485 && getBelow() == rCompare.getBelow()
486 && getTextRotation() == rCompare.getTextRotation()
487 && getTextAutoAngle() == rCompare.getTextAutoAngle()
488 && getSdrLSTAttribute() == rCompare.getSdrLSTAttribute());
491 return false;
494 // provide unique ID
495 ImplPrimitive2DIDBlock(SdrMeasurePrimitive2D, PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D)
497 } // end of namespace primitive2d
498 } // end of namespace drawinglayer
500 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */