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
51 Primitive2DReference
SdrMeasurePrimitive2D::impCreatePart(
52 const attribute::SdrLineAttribute
& rLineAttribute
,
53 const basegfx::B2DHomMatrix
& rObjectMatrix
,
54 const basegfx::B2DPoint
& rStart
,
55 const basegfx::B2DPoint
& rEnd
,
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(
71 attribute::SdrLineStartEndAttribute());
74 if(bLeftActive
&& bRightActive
)
76 return createPolygonLinePrimitive(
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
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
)
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(),
139 SDRTEXTHORZADJUST_CENTER
,
140 SDRTEXTVERTADJUST_CENTER
,
141 rTextAttribute
.isScroll(),
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())
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())
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
;
218 eHorizontal
= MEASURETEXTPOSITION_CENTERED
;
221 if(bMainLineSplitted
)
223 if(aTextRange
.getWidth() + fSpaceNeededByArrows
> fDistance
)
225 bArrowsOutside
= true;
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
);
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));
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));
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());
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));
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
)
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
)
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
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
)
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
)
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
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);
413 // create transformation to text primitive end position
414 basegfx::B2DHomMatrix aChange
;
416 // handle auto text rotation
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 (!)");
433 // add to local primitives
434 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, Primitive2DReference(pNewBlockText
));
438 if(!getSdrLSTAttribute().getShadow().isDefault())
440 aRetval
= createEmbeddedShadowPrimitive(
442 getSdrLSTAttribute().getShadow());
448 SdrMeasurePrimitive2D::SdrMeasurePrimitive2D(
449 const attribute::SdrLineShadowTextAttribute
& rSdrLSTAttribute
,
450 const basegfx::B2DPoint
& rStart
,
451 const basegfx::B2DPoint
& rEnd
,
452 MeasureTextPosition eHorizontal
,
453 MeasureTextPosition eVertical
,
462 : BufferedDecompositionPrimitive2D(),
463 maSdrLSTAttribute(rSdrLSTAttribute
),
466 meHorizontal(eHorizontal
),
467 meVertical(eVertical
),
468 mfDistance(fDistance
),
471 mfLeftDelta(fLeftDelta
),
472 mfRightDelta(fRightDelta
),
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());
504 ImplPrimitrive2DIDBlock(SdrMeasurePrimitive2D
, PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D
)
506 } // end of namespace primitive2d
507 } // end of namespace drawinglayer
509 //////////////////////////////////////////////////////////////////////////////
512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */