Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / svx / source / sdr / primitive2d / sdrmeasureprimitive2d.cxx
blob05fb38232ad2581092cc3f6305df718b9515db9b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include <svx/sdr/primitive2d/sdrmeasureprimitive2d.hxx>
30 #include <svx/sdr/primitive2d/sdrdecompositiontools.hxx>
31 #include <basegfx/matrix/b2dhommatrix.hxx>
32 #include <svx/sdr/primitive2d/sdrtextprimitive2d.hxx>
33 #include <svx/sdr/attribute/sdrtextattribute.hxx>
34 #include <basegfx/polygon/b2dpolypolygontools.hxx>
35 #include <basegfx/tools/canvastools.hxx>
36 #include <drawinglayer/primitive2d/groupprimitive2d.hxx>
37 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
38 #include <basegfx/matrix/b2dhommatrixtools.hxx>
39 #include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
41 //////////////////////////////////////////////////////////////////////////////
43 using namespace com::sun::star;
45 //////////////////////////////////////////////////////////////////////////////
47 namespace drawinglayer
49 namespace primitive2d
51 Primitive2DReference SdrMeasurePrimitive2D::impCreatePart(
52 const attribute::SdrLineAttribute& rLineAttribute,
53 const basegfx::B2DHomMatrix& rObjectMatrix,
54 const basegfx::B2DPoint& rStart,
55 const basegfx::B2DPoint& rEnd,
56 bool bLeftActive,
57 bool bRightActive) const
59 const attribute::SdrLineStartEndAttribute& rLineStartEnd = getSdrLSTAttribute().getLineStartEnd();
60 basegfx::B2DPolygon aPolygon;
62 aPolygon.append(rStart);
63 aPolygon.append(rEnd);
65 if(rLineStartEnd.isDefault() || (!bLeftActive && !bRightActive))
67 return createPolygonLinePrimitive(
68 aPolygon,
69 rObjectMatrix,
70 rLineAttribute,
71 attribute::SdrLineStartEndAttribute());
74 if(bLeftActive && bRightActive)
76 return createPolygonLinePrimitive(
77 aPolygon,
78 rObjectMatrix,
79 rLineAttribute,
80 rLineStartEnd);
83 const basegfx::B2DPolyPolygon aEmpty;
84 const attribute::SdrLineStartEndAttribute aLineStartEnd(
85 bLeftActive ? rLineStartEnd.getStartPolyPolygon() : aEmpty, bRightActive ? rLineStartEnd.getEndPolyPolygon() : aEmpty,
86 bLeftActive ? rLineStartEnd.getStartWidth() : 0.0, bRightActive ? rLineStartEnd.getEndWidth() : 0.0,
87 bLeftActive ? rLineStartEnd.isStartActive() : false, bRightActive ? rLineStartEnd.isEndActive() : false,
88 bLeftActive ? rLineStartEnd.isStartCentered() : false, bRightActive? rLineStartEnd.isEndCentered() : false);
90 return createPolygonLinePrimitive(aPolygon, rObjectMatrix, rLineAttribute, aLineStartEnd);
93 Primitive2DSequence SdrMeasurePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& aViewInformation) const
95 Primitive2DSequence aRetval;
96 SdrBlockTextPrimitive2D* pBlockText = 0;
97 basegfx::B2DRange aTextRange;
98 double fTextX((getStart().getX() + getEnd().getX()) * 0.5);
99 double fTextY((getStart().getX() + getEnd().getX()) * 0.5);
100 const basegfx::B2DVector aLine(getEnd() - getStart());
101 const double fDistance(aLine.getLength());
102 const double fAngle(atan2(aLine.getY(), aLine.getX()));
103 bool bAutoUpsideDown(false);
104 const attribute::SdrTextAttribute rTextAttribute = getSdrLSTAttribute().getText();
105 const basegfx::B2DHomMatrix aObjectMatrix(
106 basegfx::tools::createShearXRotateTranslateB2DHomMatrix(0.0, fAngle, getStart()));
108 // preapare text, but do not add yet; it needs to be aligned to
109 // the line geometry
110 if(!rTextAttribute.isDefault())
112 basegfx::B2DHomMatrix aTextMatrix;
113 double fTestAngle(fAngle);
115 if(getTextRotation())
117 aTextMatrix.rotate(-90.0 * F_PI180);
118 fTestAngle -= (90.0 * F_PI180);
120 if(getTextAutoAngle() && fTestAngle < -F_PI)
122 fTestAngle += F_2PI;
126 if(getTextAutoAngle())
128 if(fTestAngle > (F_PI / 4.0) || fTestAngle < (-F_PI * (3.0 / 4.0)))
130 bAutoUpsideDown = true;
134 // create primitive and get text range
135 pBlockText = new SdrBlockTextPrimitive2D(
136 &rTextAttribute.getSdrText(),
137 rTextAttribute.getOutlinerParaObject(),
138 aTextMatrix,
139 SDRTEXTHORZADJUST_CENTER,
140 SDRTEXTVERTADJUST_CENTER,
141 rTextAttribute.isScroll(),
142 false,
143 false,
144 false,
145 false);
147 aTextRange = pBlockText->getB2DRange(aViewInformation);
150 // prepare line attribute and result
152 const attribute::SdrLineAttribute rLineAttribute(getSdrLSTAttribute().getLine());
153 bool bArrowsOutside(false);
154 bool bMainLineSplitted(false);
155 const attribute::SdrLineStartEndAttribute& rLineStartEnd = getSdrLSTAttribute().getLineStartEnd();
156 double fStartArrowW(0.0);
157 double fStartArrowH(0.0);
158 double fEndArrowW(0.0);
159 double fEndArrowH(0.0);
161 if(!rLineStartEnd.isDefault())
163 if(rLineStartEnd.isStartActive())
165 const basegfx::B2DRange aArrowRange(basegfx::tools::getRange(rLineStartEnd.getStartPolyPolygon()));
166 fStartArrowW = rLineStartEnd.getStartWidth();
167 fStartArrowH = aArrowRange.getHeight() * fStartArrowW / aArrowRange.getWidth();
169 if(rLineStartEnd.isStartCentered())
171 fStartArrowH *= 0.5;
175 if(rLineStartEnd.isEndActive())
177 const basegfx::B2DRange aArrowRange(basegfx::tools::getRange(rLineStartEnd.getEndPolyPolygon()));
178 fEndArrowW = rLineStartEnd.getEndWidth();
179 fEndArrowH = aArrowRange.getHeight() * fEndArrowW / aArrowRange.getWidth();
181 if(rLineStartEnd.isEndCentered())
183 fEndArrowH *= 0.5;
188 const double fSpaceNeededByArrows(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.5));
189 const double fArrowsOutsideLen((fStartArrowH + fEndArrowH + fStartArrowW + fEndArrowW) * 0.5);
190 const double fHalfLineWidth(rLineAttribute.getWidth() * 0.5);
192 if(fSpaceNeededByArrows > fDistance)
194 bArrowsOutside = true;
197 MeasureTextPosition eHorizontal(getHorizontal());
198 MeasureTextPosition eVertical(getVertical());
200 if(MEASURETEXTPOSITION_AUTOMATIC == eVertical)
202 eVertical = MEASURETEXTPOSITION_NEGATIVE;
205 if(MEASURETEXTPOSITION_CENTERED == eVertical)
207 bMainLineSplitted = true;
210 if(MEASURETEXTPOSITION_AUTOMATIC == eHorizontal)
212 if(aTextRange.getWidth() > fDistance)
214 eHorizontal = MEASURETEXTPOSITION_NEGATIVE;
216 else
218 eHorizontal = MEASURETEXTPOSITION_CENTERED;
221 if(bMainLineSplitted)
223 if(aTextRange.getWidth() + fSpaceNeededByArrows > fDistance)
225 bArrowsOutside = true;
228 else
230 const double fSmallArrowNeed(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.125));
232 if(aTextRange.getWidth() + fSmallArrowNeed > fDistance)
234 bArrowsOutside = true;
239 if(MEASURETEXTPOSITION_CENTERED != eHorizontal)
241 bArrowsOutside = true;
244 // switch text above/below?
245 if(getBelow() || (bAutoUpsideDown && !getTextRotation()))
247 if(MEASURETEXTPOSITION_NEGATIVE == eVertical)
249 eVertical = MEASURETEXTPOSITION_POSITIVE;
251 else if(MEASURETEXTPOSITION_POSITIVE == eVertical)
253 eVertical = MEASURETEXTPOSITION_NEGATIVE;
257 const double fMainLineOffset(getBelow() ? getDistance() : -getDistance());
258 const basegfx::B2DPoint aMainLeft(0.0, fMainLineOffset);
259 const basegfx::B2DPoint aMainRight(fDistance, fMainLineOffset);
261 // main line
262 if(bArrowsOutside)
264 double fLenLeft(fArrowsOutsideLen);
265 double fLenRight(fArrowsOutsideLen);
267 if(!bMainLineSplitted)
269 if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal)
271 fLenLeft = fStartArrowH + aTextRange.getWidth();
273 else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal)
275 fLenRight = fEndArrowH + aTextRange.getWidth();
279 const basegfx::B2DPoint aMainLeftLeft(aMainLeft.getX() - fLenLeft, aMainLeft.getY());
280 const basegfx::B2DPoint aMainRightRight(aMainRight.getX() + fLenRight, aMainRight.getY());
282 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeftLeft, aMainLeft, false, true));
283 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainRight, aMainRightRight, true, false));
285 if(!bMainLineSplitted || MEASURETEXTPOSITION_CENTERED != eHorizontal)
287 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, false, false));
290 else
292 if(bMainLineSplitted)
294 const double fHalfLength((fDistance - (aTextRange.getWidth() + (fStartArrowH + fEndArrowH) * 0.25)) * 0.5);
295 const basegfx::B2DPoint aMainInnerLeft(aMainLeft.getX() + fHalfLength, aMainLeft.getY());
296 const basegfx::B2DPoint aMainInnerRight(aMainRight.getX() - fHalfLength, aMainRight.getY());
298 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainInnerLeft, true, false));
299 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainInnerRight, aMainRight, false, true));
301 else
303 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, true, true));
307 // left/right help line value preparation
308 const double fTopEdge(getBelow() ? getUpper() + getDistance() : -getUpper() - getDistance());
309 const double fBottomLeft(getBelow() ? getLower() - getLeftDelta() : getLeftDelta() - getLower());
310 const double fBottomRight(getBelow() ? getLower() - getRightDelta() : getRightDelta() - getLower());
312 // left help line
313 const basegfx::B2DPoint aLeftUp(0.0, fTopEdge);
314 const basegfx::B2DPoint aLeftDown(0.0, fBottomLeft);
316 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aLeftDown, aLeftUp, false, false));
318 // right help line
319 const basegfx::B2DPoint aRightUp(fDistance, fTopEdge);
320 const basegfx::B2DPoint aRightDown(fDistance, fBottomRight);
322 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aRightDown, aRightUp, false, false));
324 // text horizontal position
325 if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal)
327 // left
328 const double fSmall(fArrowsOutsideLen * 0.18);
329 fTextX = aMainLeft.getX() - (fStartArrowH + aTextRange.getWidth() + fSmall + fHalfLineWidth);
331 if(bMainLineSplitted)
333 fTextX -= (fArrowsOutsideLen - fStartArrowH);
336 if(!rTextAttribute.isDefault())
338 fTextX -= rTextAttribute.getTextRightDistance();
341 else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal)
343 // right
344 const double fSmall(fArrowsOutsideLen * 0.18);
345 fTextX = aMainRight.getX() + (fEndArrowH + fSmall + fHalfLineWidth);
347 if(bMainLineSplitted)
349 fTextX += (fArrowsOutsideLen - fEndArrowH);
352 if(!rTextAttribute.isDefault())
354 fTextX += rTextAttribute.getTextLeftDistance();
357 else // MEASURETEXTPOSITION_CENTERED
359 // centered
360 fTextX = aMainLeft.getX() + ((fDistance - aTextRange.getWidth()) * 0.5);
362 if(!rTextAttribute.isDefault())
364 fTextX += (rTextAttribute.getTextLeftDistance() - rTextAttribute.getTextRightDistance()) / 2L;
368 // text vertical position
369 if(MEASURETEXTPOSITION_NEGATIVE == eVertical)
371 // top
372 const double fSmall(fArrowsOutsideLen * 0.10);
373 fTextY = aMainLeft.getY() - (aTextRange.getHeight() + fSmall + fHalfLineWidth);
375 if(!rTextAttribute.isDefault())
377 fTextY -= rTextAttribute.getTextLowerDistance();
380 else if(MEASURETEXTPOSITION_POSITIVE == eVertical)
382 // bottom
383 const double fSmall(fArrowsOutsideLen * 0.10);
384 fTextY = aMainLeft.getY() + (fSmall + fHalfLineWidth);
386 if(!rTextAttribute.isDefault())
388 fTextY += rTextAttribute.getTextUpperDistance();
391 else // MEASURETEXTPOSITION_CENTERED
393 // centered
394 fTextY = aMainLeft.getY() - (aTextRange.getHeight() * 0.5);
396 if(!rTextAttribute.isDefault())
398 fTextY += (rTextAttribute.getTextUpperDistance() - rTextAttribute.getTextLowerDistance()) / 2L;
403 if(getSdrLSTAttribute().getLine().isDefault())
405 // embed line geometry to invisible (100% transparent) line group for HitTest
406 const Primitive2DReference xHiddenLines(new HiddenGeometryPrimitive2D(aRetval));
408 aRetval = Primitive2DSequence(&xHiddenLines, 1);
411 if(pBlockText)
413 // create transformation to text primitive end position
414 basegfx::B2DHomMatrix aChange;
416 // handle auto text rotation
417 if(bAutoUpsideDown)
419 aChange.rotate(F_PI);
422 // move from aTextRange.TopLeft to fTextX, fTextY
423 aChange.translate(fTextX - aTextRange.getMinX(), fTextY - aTextRange.getMinY());
425 // apply object matrix
426 aChange *= aObjectMatrix;
428 // apply to existing text primitive
429 SdrTextPrimitive2D* pNewBlockText = pBlockText->createTransformedClone(aChange);
430 OSL_ENSURE(pNewBlockText, "SdrMeasurePrimitive2D::create2DDecomposition: Could not create transformed clone of text primitive (!)");
431 delete pBlockText;
433 // add to local primitives
434 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, Primitive2DReference(pNewBlockText));
437 // add shadow
438 if(!getSdrLSTAttribute().getShadow().isDefault())
440 aRetval = createEmbeddedShadowPrimitive(
441 aRetval,
442 getSdrLSTAttribute().getShadow());
445 return aRetval;
448 SdrMeasurePrimitive2D::SdrMeasurePrimitive2D(
449 const attribute::SdrLineShadowTextAttribute& rSdrLSTAttribute,
450 const basegfx::B2DPoint& rStart,
451 const basegfx::B2DPoint& rEnd,
452 MeasureTextPosition eHorizontal,
453 MeasureTextPosition eVertical,
454 double fDistance,
455 double fUpper,
456 double fLower,
457 double fLeftDelta,
458 double fRightDelta,
459 bool bBelow,
460 bool bTextRotation,
461 bool bTextAutoAngle)
462 : BufferedDecompositionPrimitive2D(),
463 maSdrLSTAttribute(rSdrLSTAttribute),
464 maStart(rStart),
465 maEnd(rEnd),
466 meHorizontal(eHorizontal),
467 meVertical(eVertical),
468 mfDistance(fDistance),
469 mfUpper(fUpper),
470 mfLower(fLower),
471 mfLeftDelta(fLeftDelta),
472 mfRightDelta(fRightDelta),
473 mbBelow(bBelow),
474 mbTextRotation(bTextRotation),
475 mbTextAutoAngle(bTextAutoAngle)
479 bool SdrMeasurePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
481 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
483 const SdrMeasurePrimitive2D& rCompare = (SdrMeasurePrimitive2D&)rPrimitive;
485 return (getStart() == rCompare.getStart()
486 && getEnd() == rCompare.getEnd()
487 && getHorizontal() == rCompare.getHorizontal()
488 && getVertical() == rCompare.getVertical()
489 && getDistance() == rCompare.getDistance()
490 && getUpper() == rCompare.getUpper()
491 && getLower() == rCompare.getLower()
492 && getLeftDelta() == rCompare.getLeftDelta()
493 && getRightDelta() == rCompare.getRightDelta()
494 && getBelow() == rCompare.getBelow()
495 && getTextRotation() == rCompare.getTextRotation()
496 && getTextAutoAngle() == rCompare.getTextAutoAngle()
497 && getSdrLSTAttribute() == rCompare.getSdrLSTAttribute());
500 return false;
503 // provide unique ID
504 ImplPrimitrive2DIDBlock(SdrMeasurePrimitive2D, PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D)
506 } // end of namespace primitive2d
507 } // end of namespace drawinglayer
509 //////////////////////////////////////////////////////////////////////////////
510 // eof
512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */