1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
42 Primitive2DReference
SdrMeasurePrimitive2D::impCreatePart(
43 const attribute::SdrLineAttribute
& rLineAttribute
,
44 const basegfx::B2DHomMatrix
& rObjectMatrix
,
45 const basegfx::B2DPoint
& rStart
,
46 const basegfx::B2DPoint
& rEnd
,
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(
62 attribute::SdrLineStartEndAttribute());
65 if(bLeftActive
&& bRightActive
)
67 return createPolygonLinePrimitive(
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(
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
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
)
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(),
132 SDRTEXTHORZADJUST_CENTER
,
133 SDRTEXTVERTADJUST_CENTER
,
134 rTextAttribute
.isScroll(),
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())
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())
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
;
211 eHorizontal
= MEASURETEXTPOSITION_CENTERED
;
214 if(bMainLineSplitted
)
216 if(aTextRange
.getWidth() + fSpaceNeededByArrows
> fDistance
)
218 bArrowsOutside
= true;
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
);
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));
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));
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());
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));
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
)
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
)
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
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
)
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
)
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
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);
406 // create transformation to text primitive end position
407 basegfx::B2DHomMatrix aChange
;
409 // handle auto text rotation
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 (!)");
426 // add to local primitives
427 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, Primitive2DReference(pNewBlockText
));
431 if(!getSdrLSTAttribute().getShadow().isDefault())
433 aRetval
= createEmbeddedShadowPrimitive(
435 getSdrLSTAttribute().getShadow());
441 SdrMeasurePrimitive2D::SdrMeasurePrimitive2D(
442 const attribute::SdrLineShadowTextAttribute
& rSdrLSTAttribute
,
443 const basegfx::B2DPoint
& rStart
,
444 const basegfx::B2DPoint
& rEnd
,
445 MeasureTextPosition eHorizontal
,
446 MeasureTextPosition eVertical
,
455 : BufferedDecompositionPrimitive2D(),
456 maSdrLSTAttribute(rSdrLSTAttribute
),
459 meHorizontal(eHorizontal
),
460 meVertical(eVertical
),
461 mfDistance(fDistance
),
464 mfLeftDelta(fLeftDelta
),
465 mfRightDelta(fRightDelta
),
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());
497 ImplPrimitive2DIDBlock(SdrMeasurePrimitive2D
, PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D
)
499 } // end of namespace primitive2d
500 } // end of namespace drawinglayer
502 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */