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 .
21 #include <sdr/overlay/overlaytools.hxx>
22 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
23 #include <basegfx/matrix/b2dhommatrix.hxx>
24 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
25 #include <basegfx/polygon/b2dpolygon.hxx>
26 #include <basegfx/polygon/b2dpolygontools.hxx>
27 #include <drawinglayer/primitive2d/PolygonMarkerPrimitive2D.hxx>
28 #include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
29 #include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
30 #include <drawinglayer/primitive2d/PolygonStrokePrimitive2D.hxx>
31 #include <drawinglayer/geometry/viewinformation2d.hxx>
32 #include <basegfx/matrix/b2dhommatrixtools.hxx>
33 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
34 #include <drawinglayer/primitive2d/PolyPolygonRGBAPrimitive2D.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/settings.hxx>
39 namespace drawinglayer::primitive2d
42 OverlayStaticRectanglePrimitive::OverlayStaticRectanglePrimitive(
43 const basegfx::B2DPoint
& rPosition
,
44 const basegfx::B2DSize
& rSize
,
45 const basegfx::BColor
& rStrokeColor
,
46 const basegfx::BColor
& rFillColor
,
49 : maPosition(rPosition
)
51 , maStrokeColor(rStrokeColor
)
52 , maFillColor(rFillColor
)
53 , mfTransparence(fTransparence
)
54 , mfRotation(fRotation
)
57 Primitive2DReference
OverlayStaticRectanglePrimitive::create2DDecomposition(const geometry::ViewInformation2D
& /*rViewInformation*/) const
59 const double fHalfWidth
= maSize
.getWidth() * getDiscreteUnit() / 2.0;
60 const double fHalfHeight
= maSize
.getHeight() * getDiscreteUnit() / 2.0;
62 basegfx::B2DRange
aRange(
63 maPosition
.getX() - fHalfWidth
, maPosition
.getY() - fHalfHeight
,
64 maPosition
.getX() + fHalfWidth
, maPosition
.getY() + fHalfHeight
);
66 if (getDiscreteUnit() <= 0.0 || mfTransparence
> 1.0)
69 basegfx::B2DPolygon
aPolygon(
70 basegfx::utils::createPolygonFromRect(aRange
));
72 // create filled primitive
73 basegfx::B2DPolyPolygon aPolyPolygon
;
74 aPolyPolygon
.append(aPolygon
);
76 const attribute::LineAttribute
aLineAttribute(maStrokeColor
, 1.0);
79 const Primitive2DReference
aStroke(
80 new PolyPolygonStrokePrimitive2D(aPolyPolygon
, aLineAttribute
));
82 // create fill primitive
83 const Primitive2DReference
aFill(
84 new PolyPolygonColorPrimitive2D(std::move(aPolyPolygon
), maFillColor
));
86 Primitive2DContainer aPrimitive2DSequence
{ aFill
, aStroke
};
88 // embed filled to transparency (if used)
89 if (mfTransparence
> 0.0)
91 return new UnifiedTransparencePrimitive2D(
92 std::move(aPrimitive2DSequence
),
96 return new GroupPrimitive2D(std::move(aPrimitive2DSequence
));
99 bool OverlayStaticRectanglePrimitive::operator==(const BasePrimitive2D
& rPrimitive
) const
101 if (DiscreteMetricDependentPrimitive2D::operator==(rPrimitive
))
103 const OverlayStaticRectanglePrimitive
& rCompare
= static_cast<const OverlayStaticRectanglePrimitive
&>(rPrimitive
);
105 return (maPosition
== rCompare
.maPosition
106 && maSize
== rCompare
.maSize
107 && maStrokeColor
== rCompare
.maStrokeColor
108 && maFillColor
== rCompare
.maFillColor
109 && mfTransparence
== rCompare
.mfTransparence
110 && mfRotation
== rCompare
.mfRotation
);
116 sal_uInt32
OverlayStaticRectanglePrimitive::getPrimitive2DID() const
118 return PRIMITIVE2D_ID_OVERLAYRECTANGLEPRIMITIVE
;
123 OverlayBitmapExPrimitive::OverlayBitmapExPrimitive(
124 const BitmapEx
& rBitmapEx
,
125 const basegfx::B2DPoint
& rBasePosition
,
130 : maBitmapEx(rBitmapEx
),
131 maBasePosition(rBasePosition
),
135 mfRotation(fRotation
)
138 Primitive2DReference
OverlayBitmapExPrimitive::create2DDecomposition(const geometry::ViewInformation2D
& /*rViewInformation*/) const
140 const Size
aBitmapSize(getBitmapEx().GetSizePixel());
142 if(!aBitmapSize
.Width() || !aBitmapSize
.Height() || getDiscreteUnit() <= 0.0)
145 // calculate back from internal bitmap's extreme coordinates (the edges)
146 // to logical coordinates. Only use a unified scaling value (getDiscreteUnit(),
147 // the prepared one which expresses how many logic units form a discrete unit)
148 // for this step. This primitive is to be displayed always unscaled (in its pixel size)
149 // and unrotated, more like a marker
150 const double fLeft((0.0 - getCenterX()) * getDiscreteUnit());
151 const double fTop((0.0 - getCenterY()) * getDiscreteUnit());
152 const double fRight((aBitmapSize
.getWidth() - getCenterX()) * getDiscreteUnit());
153 const double fBottom((aBitmapSize
.getHeight() - getCenterY()) * getDiscreteUnit());
155 // create a BitmapPrimitive2D using those positions
156 basegfx::B2DHomMatrix aTransform
;
158 aTransform
.set(0, 0, fRight
- fLeft
);
159 aTransform
.set(1, 1, fBottom
- fTop
);
160 aTransform
.set(0, 2, fLeft
);
161 aTransform
.set(1, 2, fTop
);
163 // if shearX is used, apply it, too
164 if(!basegfx::fTools::equalZero(getShearX()))
166 aTransform
.shearX(getShearX());
169 // if rotation is used, apply it, too
170 if(!basegfx::fTools::equalZero(getRotation()))
172 aTransform
.rotate(getRotation());
176 aTransform
.translate(getBasePosition().getX(), getBasePosition().getY());
178 return new BitmapPrimitive2D(getBitmapEx(), aTransform
);
181 bool OverlayBitmapExPrimitive::operator==( const BasePrimitive2D
& rPrimitive
) const
183 if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive
))
185 const OverlayBitmapExPrimitive
& rCompare
= static_cast< const OverlayBitmapExPrimitive
& >(rPrimitive
);
187 return (getBitmapEx() == rCompare
.getBitmapEx()
188 && getBasePosition() == rCompare
.getBasePosition()
189 && getCenterX() == rCompare
.getCenterX()
190 && getCenterY() == rCompare
.getCenterY()
191 && getShearX() == rCompare
.getShearX()
192 && getRotation() == rCompare
.getRotation());
198 sal_uInt32
OverlayBitmapExPrimitive::getPrimitive2DID() const
200 return PRIMITIVE2D_ID_OVERLAYBITMAPEXPRIMITIVE
;
205 OverlayCrosshairPrimitive::OverlayCrosshairPrimitive(
206 const basegfx::B2DPoint
& rBasePosition
,
207 const basegfx::BColor
& rRGBColorA
,
208 const basegfx::BColor
& rRGBColorB
,
209 double fDiscreteDashLength
)
210 : maBasePosition(rBasePosition
),
211 maRGBColorA(rRGBColorA
),
212 maRGBColorB(rRGBColorB
),
213 mfDiscreteDashLength(fDiscreteDashLength
)
216 Primitive2DReference
OverlayCrosshairPrimitive::create2DDecomposition(const geometry::ViewInformation2D
& /*rViewInformation*/) const
218 // use the prepared Viewport information accessible using getViewport()
220 if(getViewport().isEmpty())
223 basegfx::B2DPolygon aPolygon
;
225 aPolygon
.append(basegfx::B2DPoint(getViewport().getMinX(), getBasePosition().getY()));
226 aPolygon
.append(basegfx::B2DPoint(getViewport().getMaxX(), getBasePosition().getY()));
228 Primitive2DReference xMarker1
=
229 new PolygonMarkerPrimitive2D(
233 getDiscreteDashLength());
236 aPolygon
.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMinY()));
237 aPolygon
.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMaxY()));
239 Primitive2DReference xMarker2
=
240 new PolygonMarkerPrimitive2D(
244 getDiscreteDashLength());
246 return new GroupPrimitive2D(Primitive2DContainer
{ xMarker1
, xMarker2
});
249 bool OverlayCrosshairPrimitive::operator==( const BasePrimitive2D
& rPrimitive
) const
251 if(ViewportDependentPrimitive2D::operator==(rPrimitive
))
253 const OverlayCrosshairPrimitive
& rCompare
= static_cast< const OverlayCrosshairPrimitive
& >(rPrimitive
);
255 return (getBasePosition() == rCompare
.getBasePosition()
256 && getRGBColorA() == rCompare
.getRGBColorA()
257 && getRGBColorB() == rCompare
.getRGBColorB()
258 && getDiscreteDashLength() == rCompare
.getDiscreteDashLength());
264 sal_uInt32
OverlayCrosshairPrimitive::getPrimitive2DID() const
266 return PRIMITIVE2D_ID_OVERLAYCROSSHAIRPRIMITIVE
;
271 OverlayRectanglePrimitive::OverlayRectanglePrimitive(
272 const basegfx::B2DRange
& rObjectRange
,
273 const basegfx::BColor
& rColor
,
274 double fTransparence
,
275 double fDiscreteGrow
,
276 double fDiscreteShrink
,
278 : maObjectRange(rObjectRange
),
280 mfTransparence(fTransparence
),
281 mfDiscreteGrow(fDiscreteGrow
),
282 mfDiscreteShrink(fDiscreteShrink
),
283 mfRotation(fRotation
)
286 Primitive2DReference
OverlayRectanglePrimitive::create2DDecomposition(const geometry::ViewInformation2D
& /*rViewInformation*/) const
288 Primitive2DReference aRetval
;
289 basegfx::B2DRange
aInnerRange(getObjectRange());
291 if(aInnerRange
.isEmpty() || getDiscreteUnit() <= 0.0 || getTransparence() > 1.0)
294 if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
296 basegfx::B2DRange
aOuterRange(aInnerRange
);
297 // grow/shrink inner/outer polygons
298 aOuterRange
.grow(getDiscreteUnit() * getDiscreteGrow());
299 aInnerRange
.grow(getDiscreteUnit() * -getDiscreteShrink());
301 // convert to polygons
302 const double fFullGrow(getDiscreteGrow() + getDiscreteShrink());
303 const double fRelativeRadiusX(fFullGrow
/ aOuterRange
.getWidth());
304 const double fRelativeRadiusY(fFullGrow
/ aOuterRange
.getHeight());
305 basegfx::B2DPolygon
aOuterPolygon(
306 basegfx::utils::createPolygonFromRect(
310 basegfx::B2DPolygon
aInnerPolygon(
311 basegfx::utils::createPolygonFromRect(
314 // apply evtl. existing rotation
315 if(!basegfx::fTools::equalZero(getRotation()))
317 const basegfx::B2DHomMatrix
aTransform(basegfx::utils::createRotateAroundPoint(
318 getObjectRange().getMinX(), getObjectRange().getMinY(), getRotation()));
320 aOuterPolygon
.transform(aTransform
);
321 aInnerPolygon
.transform(aTransform
);
324 // create filled primitive
325 basegfx::B2DPolyPolygon aPolyPolygon
;
327 aPolyPolygon
.append(aOuterPolygon
);
328 aPolyPolygon
.append(aInnerPolygon
);
330 // create fill primitive
331 if (getTransparence() <= 0.0)
334 aRetval
= new PolyPolygonColorPrimitive2D(
335 std::move(aPolyPolygon
),
341 aRetval
= new PolyPolygonRGBAPrimitive2D(
342 std::move(aPolyPolygon
),
349 basegfx::B2DPolygon
aInnerPolygon(
350 basegfx::utils::createPolygonFromRect(
353 // apply evtl. existing rotation
354 if(!basegfx::fTools::equalZero(getRotation()))
356 const basegfx::B2DHomMatrix
aTransform(basegfx::utils::createRotateAroundPoint(
357 getObjectRange().getMinX(), getObjectRange().getMinY(), getRotation()));
359 aInnerPolygon
.transform(aTransform
);
362 // for high contrast, use a thick stroke
363 const basegfx::BColor
aHighContrastLineColor(Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor());
364 const attribute::LineAttribute
aLineAttribute(aHighContrastLineColor
, getDiscreteUnit() * getDiscreteGrow());
366 aRetval
= new PolygonStrokePrimitive2D(std::move(aInnerPolygon
), aLineAttribute
);
372 bool OverlayRectanglePrimitive::operator==( const BasePrimitive2D
& rPrimitive
) const
374 if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive
))
376 const OverlayRectanglePrimitive
& rCompare
= static_cast< const OverlayRectanglePrimitive
& >(rPrimitive
);
378 return (getObjectRange() == rCompare
.getObjectRange()
379 && getColor() == rCompare
.getColor()
380 && getTransparence() == rCompare
.getTransparence()
381 && getDiscreteGrow() == rCompare
.getDiscreteGrow()
382 && getDiscreteShrink() == rCompare
.getDiscreteShrink()
383 && getRotation() == rCompare
.getRotation());
389 sal_uInt32
OverlayRectanglePrimitive::getPrimitive2DID() const
391 return PRIMITIVE2D_ID_OVERLAYRECTANGLEPRIMITIVE
;
396 OverlayHelplineStripedPrimitive::OverlayHelplineStripedPrimitive(
397 const basegfx::B2DPoint
& rBasePosition
,
398 HelplineStyle eStyle
,
399 const basegfx::BColor
& rRGBColorA
,
400 const basegfx::BColor
& rRGBColorB
,
401 double fDiscreteDashLength
)
402 : maBasePosition(rBasePosition
),
404 maRGBColorA(rRGBColorA
),
405 maRGBColorB(rRGBColorB
),
406 mfDiscreteDashLength(fDiscreteDashLength
)
409 Primitive2DReference
OverlayHelplineStripedPrimitive::create2DDecomposition(const geometry::ViewInformation2D
& rViewInformation
) const
411 // use the prepared Viewport information accessible using getViewport()
413 if(getViewport().isEmpty())
416 Primitive2DReference xRetVal
;
419 case HELPLINESTYLE_VERTICAL
:
421 basegfx::B2DPolygon aLine
;
423 aLine
.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMinY()));
424 aLine
.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMaxY()));
427 new PolygonMarkerPrimitive2D(
431 getDiscreteDashLength());
435 case HELPLINESTYLE_HORIZONTAL
:
437 basegfx::B2DPolygon aLine
;
439 aLine
.append(basegfx::B2DPoint(getViewport().getMinX(), getBasePosition().getY()));
440 aLine
.append(basegfx::B2DPoint(getViewport().getMaxX(), getBasePosition().getY()));
443 new PolygonMarkerPrimitive2D(
447 getDiscreteDashLength());
451 default: // case HELPLINESTYLE_POINT :
453 const double fDiscreteUnit((rViewInformation
.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength());
454 basegfx::B2DPolygon aLineA
, aLineB
;
456 aLineA
.append(basegfx::B2DPoint(getBasePosition().getX(), getBasePosition().getY() - fDiscreteUnit
));
457 aLineA
.append(basegfx::B2DPoint(getBasePosition().getX(), getBasePosition().getY() + fDiscreteUnit
));
459 Primitive2DReference xMarker1
=
460 new PolygonMarkerPrimitive2D(
464 getDiscreteDashLength());
466 aLineB
.append(basegfx::B2DPoint(getBasePosition().getX() - fDiscreteUnit
, getBasePosition().getY()));
467 aLineB
.append(basegfx::B2DPoint(getBasePosition().getX() + fDiscreteUnit
, getBasePosition().getY()));
469 Primitive2DReference xMarker2
=
470 new PolygonMarkerPrimitive2D(
474 getDiscreteDashLength());
476 xRetVal
= new GroupPrimitive2D(Primitive2DContainer
{ xMarker1
, xMarker2
});
483 bool OverlayHelplineStripedPrimitive::operator==( const BasePrimitive2D
& rPrimitive
) const
485 if(ViewportDependentPrimitive2D::operator==(rPrimitive
))
487 const OverlayHelplineStripedPrimitive
& rCompare
= static_cast< const OverlayHelplineStripedPrimitive
& >(rPrimitive
);
489 return (getBasePosition() == rCompare
.getBasePosition()
490 && getStyle() == rCompare
.getStyle()
491 && getRGBColorA() == rCompare
.getRGBColorA()
492 && getRGBColorB() == rCompare
.getRGBColorB()
493 && getDiscreteDashLength() == rCompare
.getDiscreteDashLength());
499 sal_uInt32
OverlayHelplineStripedPrimitive::getPrimitive2DID() const
501 return PRIMITIVE2D_ID_OVERLAYHELPLINESTRIPEDPRIMITIVE
;
506 OverlayRollingRectanglePrimitive::OverlayRollingRectanglePrimitive(
507 const basegfx::B2DRange
& aRollingRectangle
,
508 const basegfx::BColor
& rRGBColorA
,
509 const basegfx::BColor
& rRGBColorB
,
510 double fDiscreteDashLength
)
511 : maRollingRectangle(aRollingRectangle
),
512 maRGBColorA(rRGBColorA
),
513 maRGBColorB(rRGBColorB
),
514 mfDiscreteDashLength(fDiscreteDashLength
)
517 Primitive2DReference
OverlayRollingRectanglePrimitive::create2DDecomposition(const geometry::ViewInformation2D
& /*rViewInformation*/) const
519 // use the prepared Viewport information accessible using getViewport()
521 if(getViewport().isEmpty())
524 Primitive2DContainer aContainer
;
526 basegfx::B2DPolygon aLine1
;
527 aLine1
.append(basegfx::B2DPoint(getViewport().getMinX(), getRollingRectangle().getMinY()));
528 aLine1
.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMinY()));
529 aContainer
.push_back(new PolygonMarkerPrimitive2D(std::move(aLine1
), getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
531 basegfx::B2DPolygon aLine2
;
532 aLine2
.append(basegfx::B2DPoint(getViewport().getMinX(), getRollingRectangle().getMaxY()));
533 aLine2
.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMaxY()));
534 aContainer
.push_back(new PolygonMarkerPrimitive2D(std::move(aLine2
), getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
537 basegfx::B2DPolygon aLine3
;
538 aLine3
.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMinY()));
539 aLine3
.append(basegfx::B2DPoint(getViewport().getMaxX(), getRollingRectangle().getMinY()));
540 aContainer
.push_back(new PolygonMarkerPrimitive2D(std::move(aLine3
), getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
542 basegfx::B2DPolygon aLine4
;
543 aLine4
.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMaxY()));
544 aLine4
.append(basegfx::B2DPoint(getViewport().getMaxX(), getRollingRectangle().getMaxY()));
545 aContainer
.push_back(new PolygonMarkerPrimitive2D(std::move(aLine4
), getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
548 basegfx::B2DPolygon aLine5
;
549 aLine5
.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getViewport().getMinY()));
550 aLine5
.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMinY()));
551 aContainer
.push_back(new PolygonMarkerPrimitive2D(std::move(aLine5
), getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
553 basegfx::B2DPolygon aLine6
;
554 aLine6
.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getViewport().getMinY()));
555 aLine6
.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMinY()));
556 aContainer
.push_back(new PolygonMarkerPrimitive2D(std::move(aLine6
), getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
559 basegfx::B2DPolygon aLine7
;
560 aLine7
.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMaxY()));
561 aLine7
.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getViewport().getMaxY()));
562 aContainer
.push_back(new PolygonMarkerPrimitive2D(std::move(aLine7
), getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
564 basegfx::B2DPolygon aLine8
;
565 aLine8
.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMaxY()));
566 aLine8
.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getViewport().getMaxY()));
567 aContainer
.push_back(new PolygonMarkerPrimitive2D(std::move(aLine8
), getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
569 return new GroupPrimitive2D(std::move(aContainer
));
572 bool OverlayRollingRectanglePrimitive::operator==( const BasePrimitive2D
& rPrimitive
) const
574 if(ViewportDependentPrimitive2D::operator==(rPrimitive
))
576 const OverlayRollingRectanglePrimitive
& rCompare
= static_cast< const OverlayRollingRectanglePrimitive
& >(rPrimitive
);
578 return (getRollingRectangle() == rCompare
.getRollingRectangle()
579 && getRGBColorA() == rCompare
.getRGBColorA()
580 && getRGBColorB() == rCompare
.getRGBColorB()
581 && getDiscreteDashLength() == rCompare
.getDiscreteDashLength());
587 sal_uInt32
OverlayRollingRectanglePrimitive::getPrimitive2DID() const
589 return PRIMITIVE2D_ID_OVERLAYROLLINGRECTANGLEPRIMITIVE
;
592 } // end of namespace
594 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */