Get the style color and number just once
[LibreOffice.git] / svx / source / sdr / primitive2d / sdrmeasureprimitive2d.cxx
blobc5a3f812583f6faf124f84727cfb95eb72ce13f8
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 <sdr/primitive2d/sdrmeasureprimitive2d.hxx>
21 #include <sdr/primitive2d/sdrdecompositiontools.hxx>
22 #include <basegfx/matrix/b2dhommatrix.hxx>
23 #include <sdr/primitive2d/sdrtextprimitive2d.hxx>
24 #include <sdr/attribute/sdrtextattribute.hxx>
25 #include <basegfx/polygon/b2dpolypolygontools.hxx>
26 #include <rtl/ref.hxx>
27 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
28 #include <basegfx/matrix/b2dhommatrixtools.hxx>
29 #include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
30 #include <osl/diagnose.h>
33 using namespace com::sun::star;
36 namespace drawinglayer::primitive2d
38 Primitive2DReference SdrMeasurePrimitive2D::impCreatePart(
39 const attribute::SdrLineAttribute& rLineAttribute,
40 const basegfx::B2DHomMatrix& rObjectMatrix,
41 const basegfx::B2DPoint& rStart,
42 const basegfx::B2DPoint& rEnd,
43 bool bLeftActive,
44 bool bRightActive) const
46 const attribute::SdrLineStartEndAttribute& rLineStartEnd = getSdrLSTAttribute().getLineStartEnd();
47 basegfx::B2DPolygon aPolygon;
49 aPolygon.append(rStart);
50 aPolygon.append(rEnd);
51 aPolygon.transform(rObjectMatrix);
53 if(rLineStartEnd.isDefault() || (!bLeftActive && !bRightActive))
55 return createPolygonLinePrimitive(
56 aPolygon,
57 rLineAttribute,
58 attribute::SdrLineStartEndAttribute());
61 if(bLeftActive && bRightActive)
63 return createPolygonLinePrimitive(
64 aPolygon,
65 rLineAttribute,
66 rLineStartEnd);
69 const basegfx::B2DPolyPolygon aEmpty;
70 const attribute::SdrLineStartEndAttribute aLineStartEnd(
71 bLeftActive ? rLineStartEnd.getStartPolyPolygon() : aEmpty, bRightActive ? rLineStartEnd.getEndPolyPolygon() : aEmpty,
72 bLeftActive ? rLineStartEnd.getStartWidth() : 0.0, bRightActive ? rLineStartEnd.getEndWidth() : 0.0,
73 bLeftActive && rLineStartEnd.isStartActive(), bRightActive && rLineStartEnd.isEndActive(),
74 bLeftActive && rLineStartEnd.isStartCentered(), bRightActive && rLineStartEnd.isEndCentered());
76 return createPolygonLinePrimitive(
77 aPolygon,
78 rLineAttribute,
79 aLineStartEnd);
82 Primitive2DReference SdrMeasurePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& aViewInformation) const
84 Primitive2DContainer aRetval;
85 rtl::Reference<SdrBlockTextPrimitive2D> xBlockText;
86 basegfx::B2DRange aTextRange;
87 const basegfx::B2DVector aLine(getEnd() - getStart());
88 const double fDistance(aLine.getLength());
89 const double fAngle(atan2(aLine.getY(), aLine.getX()));
90 bool bAutoUpsideDown(false);
91 const attribute::SdrTextAttribute rTextAttribute = getSdrLSTAttribute().getText();
92 const basegfx::B2DHomMatrix aObjectMatrix(
93 basegfx::utils::createShearXRotateTranslateB2DHomMatrix(0.0, fAngle, getStart()));
95 // prepare text, but do not add yet; it needs to be aligned to
96 // the line geometry
97 if(!rTextAttribute.isDefault())
99 basegfx::B2DHomMatrix aTextMatrix;
100 double fTestAngle(fAngle);
102 if(getTextRotation())
104 aTextMatrix.rotate(-M_PI_2);
105 fTestAngle -= (M_PI_2);
107 if(getTextAutoAngle() && fTestAngle < -M_PI)
109 fTestAngle += 2 * M_PI;
113 if(getTextAutoAngle())
115 if(fTestAngle > (M_PI / 4.0) || fTestAngle < (-M_PI * (3.0 / 4.0)))
117 bAutoUpsideDown = true;
121 // create primitive and get text range
122 xBlockText = new SdrBlockTextPrimitive2D(
123 &rTextAttribute.getSdrText(),
124 rTextAttribute.getOutlinerParaObject(),
125 aTextMatrix,
126 SDRTEXTHORZADJUST_CENTER,
127 SDRTEXTVERTADJUST_CENTER,
128 rTextAttribute.isScroll(),
129 false,
130 false,
131 false);
133 aTextRange = xBlockText->getB2DRange(aViewInformation);
136 // prepare line attribute and result
137 double fTextX;
138 double fTextY;
140 const attribute::SdrLineAttribute rLineAttribute(getSdrLSTAttribute().getLine());
141 bool bArrowsOutside(false);
142 bool bMainLineSplitted(false);
143 const attribute::SdrLineStartEndAttribute& rLineStartEnd = getSdrLSTAttribute().getLineStartEnd();
144 double fStartArrowW(0.0);
145 double fStartArrowH(0.0);
146 double fEndArrowW(0.0);
147 double fEndArrowH(0.0);
149 if(!rLineStartEnd.isDefault())
151 if(rLineStartEnd.isStartActive())
153 const basegfx::B2DRange aArrowRange(basegfx::utils::getRange(rLineStartEnd.getStartPolyPolygon()));
154 fStartArrowW = rLineStartEnd.getStartWidth();
155 fStartArrowH = aArrowRange.getHeight() * fStartArrowW / aArrowRange.getWidth();
157 if(rLineStartEnd.isStartCentered())
159 fStartArrowH *= 0.5;
163 if(rLineStartEnd.isEndActive())
165 const basegfx::B2DRange aArrowRange(basegfx::utils::getRange(rLineStartEnd.getEndPolyPolygon()));
166 fEndArrowW = rLineStartEnd.getEndWidth();
167 fEndArrowH = aArrowRange.getHeight() * fEndArrowW / aArrowRange.getWidth();
169 if(rLineStartEnd.isEndCentered())
171 fEndArrowH *= 0.5;
176 const double fSpaceNeededByArrows(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.5));
177 const double fArrowsOutsideLen((fStartArrowH + fEndArrowH + fStartArrowW + fEndArrowW) * 0.5);
178 const double fHalfLineWidth(rLineAttribute.getWidth() * 0.5);
180 if(fSpaceNeededByArrows > fDistance)
182 bArrowsOutside = true;
185 MeasureTextPosition eHorizontal(getHorizontal());
186 MeasureTextPosition eVertical(getVertical());
188 if(MEASURETEXTPOSITION_AUTOMATIC == eVertical)
190 eVertical = MEASURETEXTPOSITION_NEGATIVE;
193 if(MEASURETEXTPOSITION_CENTERED == eVertical)
195 bMainLineSplitted = true;
198 if(MEASURETEXTPOSITION_AUTOMATIC == eHorizontal)
200 if(aTextRange.getWidth() > fDistance)
202 eHorizontal = MEASURETEXTPOSITION_NEGATIVE;
204 else
206 eHorizontal = MEASURETEXTPOSITION_CENTERED;
209 if(bMainLineSplitted)
211 if(aTextRange.getWidth() + fSpaceNeededByArrows > fDistance)
213 bArrowsOutside = true;
216 else
218 const double fSmallArrowNeed(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.125));
220 if(aTextRange.getWidth() + fSmallArrowNeed > fDistance)
222 bArrowsOutside = true;
227 if(MEASURETEXTPOSITION_CENTERED != eHorizontal)
229 bArrowsOutside = true;
232 // switch text above/below?
233 if(getBelow() || (bAutoUpsideDown && !getTextRotation()))
235 if(MEASURETEXTPOSITION_NEGATIVE == eVertical)
237 eVertical = MEASURETEXTPOSITION_POSITIVE;
239 else if(MEASURETEXTPOSITION_POSITIVE == eVertical)
241 eVertical = MEASURETEXTPOSITION_NEGATIVE;
245 const double fMainLineOffset(getBelow() ? getDistance() : -getDistance());
246 const basegfx::B2DPoint aMainLeft(0.0, fMainLineOffset);
247 const basegfx::B2DPoint aMainRight(fDistance, fMainLineOffset);
249 // main line
250 if(bArrowsOutside)
252 double fLenLeft(fArrowsOutsideLen);
253 double fLenRight(fArrowsOutsideLen);
255 if(!bMainLineSplitted)
257 if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal)
259 fLenLeft = fStartArrowH + aTextRange.getWidth();
261 else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal)
263 fLenRight = fEndArrowH + aTextRange.getWidth();
267 const basegfx::B2DPoint aMainLeftLeft(aMainLeft.getX() - fLenLeft, aMainLeft.getY());
268 const basegfx::B2DPoint aMainRightRight(aMainRight.getX() + fLenRight, aMainRight.getY());
270 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeftLeft, aMainLeft, false, true));
271 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainRight, aMainRightRight, true, false));
273 if(!bMainLineSplitted || MEASURETEXTPOSITION_CENTERED != eHorizontal)
275 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, false, false));
278 else
280 if(bMainLineSplitted)
282 const double fHalfLength((fDistance - (aTextRange.getWidth() + (fStartArrowH + fEndArrowH) * 0.25)) * 0.5);
283 const basegfx::B2DPoint aMainInnerLeft(aMainLeft.getX() + fHalfLength, aMainLeft.getY());
284 const basegfx::B2DPoint aMainInnerRight(aMainRight.getX() - fHalfLength, aMainRight.getY());
286 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainInnerLeft, true, false));
287 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainInnerRight, aMainRight, false, true));
289 else
291 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, true, true));
295 // left/right help line value preparation
296 const double fTopEdge(getBelow() ? getUpper() + getDistance() : -getUpper() - getDistance());
297 const double fBottomLeft(getBelow() ? getLower() - getLeftDelta() : getLeftDelta() - getLower());
298 const double fBottomRight(getBelow() ? getLower() - getRightDelta() : getRightDelta() - getLower());
300 // left help line
301 const basegfx::B2DPoint aLeftUp(0.0, fTopEdge);
302 const basegfx::B2DPoint aLeftDown(0.0, fBottomLeft);
304 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aLeftDown, aLeftUp, false, false));
306 // right help line
307 const basegfx::B2DPoint aRightUp(fDistance, fTopEdge);
308 const basegfx::B2DPoint aRightDown(fDistance, fBottomRight);
310 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aRightDown, aRightUp, false, false));
312 // text horizontal position
313 if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal)
315 // left
316 const double fSmall(fArrowsOutsideLen * 0.18);
317 fTextX = aMainLeft.getX() - (fStartArrowH + aTextRange.getWidth() + fSmall + fHalfLineWidth);
319 if(bMainLineSplitted)
321 fTextX -= (fArrowsOutsideLen - fStartArrowH);
324 if(!rTextAttribute.isDefault())
326 fTextX -= rTextAttribute.getTextRightDistance();
329 else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal)
331 // right
332 const double fSmall(fArrowsOutsideLen * 0.18);
333 fTextX = aMainRight.getX() + (fEndArrowH + fSmall + fHalfLineWidth);
335 if(bMainLineSplitted)
337 fTextX += (fArrowsOutsideLen - fEndArrowH);
340 if(!rTextAttribute.isDefault())
342 fTextX += rTextAttribute.getTextLeftDistance();
345 else // MEASURETEXTPOSITION_CENTERED
347 // centered
348 fTextX = aMainLeft.getX() + ((fDistance - aTextRange.getWidth()) * 0.5);
350 if(!rTextAttribute.isDefault())
352 fTextX += (rTextAttribute.getTextLeftDistance() - rTextAttribute.getTextRightDistance()) / 2L;
356 // text vertical position
357 if(MEASURETEXTPOSITION_NEGATIVE == eVertical)
359 // top
360 const double fSmall(fArrowsOutsideLen * 0.10);
361 fTextY = aMainLeft.getY() - (aTextRange.getHeight() + fSmall + fHalfLineWidth);
363 if(!rTextAttribute.isDefault())
365 fTextY -= rTextAttribute.getTextLowerDistance();
368 else if(MEASURETEXTPOSITION_POSITIVE == eVertical)
370 // bottom
371 const double fSmall(fArrowsOutsideLen * 0.10);
372 fTextY = aMainLeft.getY() + (fSmall + fHalfLineWidth);
374 if(!rTextAttribute.isDefault())
376 fTextY += rTextAttribute.getTextUpperDistance();
379 else // MEASURETEXTPOSITION_CENTERED
381 // centered
382 fTextY = aMainLeft.getY() - (aTextRange.getHeight() * 0.5);
384 if(!rTextAttribute.isDefault())
386 fTextY += (rTextAttribute.getTextUpperDistance() - rTextAttribute.getTextLowerDistance()) / 2L;
391 if(getSdrLSTAttribute().getLine().isDefault())
393 // embed line geometry to invisible (100% transparent) line group for HitTest
394 aRetval = Primitive2DContainer {
395 new HiddenGeometryPrimitive2D(std::move(aRetval))
399 if(xBlockText.is())
401 // create transformation to text primitive end position
402 basegfx::B2DHomMatrix aChange;
404 // handle auto text rotation
405 if(bAutoUpsideDown)
407 aChange.rotate(M_PI);
410 // move from aTextRange.TopLeft to fTextX, fTextY
411 aChange.translate(fTextX - aTextRange.getMinX(), fTextY - aTextRange.getMinY());
413 // apply object matrix
414 aChange *= aObjectMatrix;
416 // apply to existing text primitive
417 rtl::Reference<SdrTextPrimitive2D> pNewBlockText = xBlockText->createTransformedClone(aChange);
418 OSL_ENSURE(pNewBlockText, "SdrMeasurePrimitive2D::create2DDecomposition: Could not create transformed clone of text primitive (!)");
419 xBlockText.clear();
421 // add to local primitives
422 aRetval.push_back(pNewBlockText);
425 // add shadow
426 if(!getSdrLSTAttribute().getShadow().isDefault())
428 aRetval = createEmbeddedShadowPrimitive(
429 std::move(aRetval),
430 getSdrLSTAttribute().getShadow());
433 return new GroupPrimitive2D(std::move(aRetval));
436 SdrMeasurePrimitive2D::SdrMeasurePrimitive2D(
437 const attribute::SdrLineEffectsTextAttribute& rSdrLSTAttribute,
438 const basegfx::B2DPoint& rStart,
439 const basegfx::B2DPoint& rEnd,
440 MeasureTextPosition eHorizontal,
441 MeasureTextPosition eVertical,
442 double fDistance,
443 double fUpper,
444 double fLower,
445 double fLeftDelta,
446 double fRightDelta,
447 bool bBelow,
448 bool bTextRotation,
449 bool bTextAutoAngle)
450 : maSdrLSTAttribute(rSdrLSTAttribute),
451 maStart(rStart),
452 maEnd(rEnd),
453 meHorizontal(eHorizontal),
454 meVertical(eVertical),
455 mfDistance(fDistance),
456 mfUpper(fUpper),
457 mfLower(fLower),
458 mfLeftDelta(fLeftDelta),
459 mfRightDelta(fRightDelta),
460 mbBelow(bBelow),
461 mbTextRotation(bTextRotation),
462 mbTextAutoAngle(bTextAutoAngle)
466 bool SdrMeasurePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
468 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
470 const SdrMeasurePrimitive2D& rCompare = static_cast<const SdrMeasurePrimitive2D&>(rPrimitive);
472 return (getStart() == rCompare.getStart()
473 && getEnd() == rCompare.getEnd()
474 && getHorizontal() == rCompare.getHorizontal()
475 && getVertical() == rCompare.getVertical()
476 && getDistance() == rCompare.getDistance()
477 && getUpper() == rCompare.getUpper()
478 && getLower() == rCompare.getLower()
479 && getLeftDelta() == rCompare.getLeftDelta()
480 && getRightDelta() == rCompare.getRightDelta()
481 && getBelow() == rCompare.getBelow()
482 && getTextRotation() == rCompare.getTextRotation()
483 && getTextAutoAngle() == rCompare.getTextAutoAngle()
484 && getSdrLSTAttribute() == rCompare.getSdrLSTAttribute());
487 return false;
490 // provide unique ID
491 sal_uInt32 SdrMeasurePrimitive2D::getPrimitive2DID() const
493 return PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D;
496 } // end of namespace
498 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */