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 <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
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
);
56 if(rLineStartEnd
.isDefault() || (!bLeftActive
&& !bRightActive
))
58 return createPolygonLinePrimitive(
62 attribute::SdrLineStartEndAttribute());
65 if(bLeftActive
&& bRightActive
)
67 return createPolygonLinePrimitive(
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
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
)
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(),
130 SDRTEXTHORZADJUST_CENTER
,
131 SDRTEXTVERTADJUST_CENTER
,
132 rTextAttribute
.isScroll(),
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())
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())
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
;
209 eHorizontal
= MEASURETEXTPOSITION_CENTERED
;
212 if(bMainLineSplitted
)
214 if(aTextRange
.getWidth() + fSpaceNeededByArrows
> fDistance
)
216 bArrowsOutside
= true;
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
);
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));
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));
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());
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));
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
)
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
)
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
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
)
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
)
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
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);
404 // create transformation to text primitive end position
405 basegfx::B2DHomMatrix aChange
;
407 // handle auto text rotation
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 (!)");
424 // add to local primitives
425 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, Primitive2DReference(pNewBlockText
));
429 if(!getSdrLSTAttribute().getShadow().isDefault())
431 aRetval
= createEmbeddedShadowPrimitive(
433 getSdrLSTAttribute().getShadow());
439 SdrMeasurePrimitive2D::SdrMeasurePrimitive2D(
440 const attribute::SdrLineShadowTextAttribute
& rSdrLSTAttribute
,
441 const basegfx::B2DPoint
& rStart
,
442 const basegfx::B2DPoint
& rEnd
,
443 MeasureTextPosition eHorizontal
,
444 MeasureTextPosition eVertical
,
453 : BufferedDecompositionPrimitive2D(),
454 maSdrLSTAttribute(rSdrLSTAttribute
),
457 meHorizontal(eHorizontal
),
458 meVertical(eVertical
),
459 mfDistance(fDistance
),
462 mfLeftDelta(fLeftDelta
),
463 mfRightDelta(fRightDelta
),
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());
495 ImplPrimitive2DIDBlock(SdrMeasurePrimitive2D
, PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D
)
497 } // end of namespace primitive2d
498 } // end of namespace drawinglayer
500 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */