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 <drawinglayer/primitive2d/polygonprimitive2d.hxx>
27 #include <basegfx/polygon/b2dpolygontools.hxx>
28 #include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
29 #include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
30 #include <drawinglayer/primitive2d/PolyPolygonHatchPrimitive2D.hxx>
31 #include <drawinglayer/geometry/viewinformation2d.hxx>
32 #include <basegfx/matrix/b2dhommatrixtools.hxx>
33 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/settings.hxx>
36 #include <toolkit/helper/vclunohelper.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 : DiscreteMetricDependentPrimitive2D()
50 , maPosition(rPosition
)
52 , maStrokeColor(rStrokeColor
)
53 , maFillColor(rFillColor
)
54 , mfTransparence(fTransparence
)
55 , mfRotation(fRotation
)
58 void OverlayStaticRectanglePrimitive::create2DDecomposition(Primitive2DContainer
& rContainer
, const geometry::ViewInformation2D
& /*rViewInformation*/) const
60 Primitive2DContainer aPrimitive2DSequence
;
61 const double fHalfWidth
= maSize
.getX() * getDiscreteUnit() / 2.0;
62 const double fHalfHeight
= maSize
.getY() * getDiscreteUnit() / 2.0;
64 basegfx::B2DRange
aRange(
65 maPosition
.getX() - fHalfWidth
, maPosition
.getY() - fHalfHeight
,
66 maPosition
.getX() + fHalfWidth
, maPosition
.getY() + fHalfHeight
);
68 if (basegfx::fTools::more(getDiscreteUnit(), 0.0) && mfTransparence
<= 1.0)
70 basegfx::B2DPolygon
aPolygon(
71 basegfx::utils::createPolygonFromRect(aRange
));
73 // create filled primitive
74 basegfx::B2DPolyPolygon aPolyPolygon
;
75 aPolyPolygon
.append(aPolygon
);
77 const attribute::LineAttribute
aLineAttribute(maStrokeColor
, 1.0);
80 const Primitive2DReference
aStroke(
81 new PolyPolygonStrokePrimitive2D(aPolyPolygon
, aLineAttribute
));
83 // create fill primitive
84 const Primitive2DReference
aFill(
85 new PolyPolygonColorPrimitive2D(aPolyPolygon
, maFillColor
));
87 aPrimitive2DSequence
= Primitive2DContainer(2);
88 aPrimitive2DSequence
[0] = aFill
;
89 aPrimitive2DSequence
[1] = aStroke
;
91 // embed filled to transparency (if used)
92 if (mfTransparence
> 0.0)
94 const Primitive2DReference
aFillTransparent(
95 new UnifiedTransparencePrimitive2D(
99 aPrimitive2DSequence
= Primitive2DContainer
{ aFillTransparent
};
103 rContainer
.insert(rContainer
.end(), aPrimitive2DSequence
.begin(), aPrimitive2DSequence
.end());
106 bool OverlayStaticRectanglePrimitive::operator==(const BasePrimitive2D
& rPrimitive
) const
108 if (DiscreteMetricDependentPrimitive2D::operator==(rPrimitive
))
110 const OverlayStaticRectanglePrimitive
& rCompare
= static_cast<const OverlayStaticRectanglePrimitive
&>(rPrimitive
);
112 return (maPosition
== rCompare
.maPosition
113 && maSize
== rCompare
.maSize
114 && maStrokeColor
== rCompare
.maStrokeColor
115 && maFillColor
== rCompare
.maFillColor
116 && mfTransparence
== rCompare
.mfTransparence
117 && mfRotation
== rCompare
.mfRotation
);
123 ImplPrimitive2DIDBlock(OverlayStaticRectanglePrimitive
, PRIMITIVE2D_ID_OVERLAYRECTANGLEPRIMITIVE
)
127 OverlayBitmapExPrimitive::OverlayBitmapExPrimitive(
128 const BitmapEx
& rBitmapEx
,
129 const basegfx::B2DPoint
& rBasePosition
,
134 : DiscreteMetricDependentPrimitive2D(),
135 maBitmapEx(rBitmapEx
),
136 maBasePosition(rBasePosition
),
140 mfRotation(fRotation
)
143 void OverlayBitmapExPrimitive::create2DDecomposition(Primitive2DContainer
& rContainer
, const geometry::ViewInformation2D
& /*rViewInformation*/) const
145 const Size
aBitmapSize(getBitmapEx().GetSizePixel());
147 if(!aBitmapSize
.Width() || !aBitmapSize
.Height() || !basegfx::fTools::more(getDiscreteUnit(), 0.0))
150 // calculate back from internal bitmap's extreme coordinates (the edges)
151 // to logical coordinates. Only use a unified scaling value (getDiscreteUnit(),
152 // the prepared one which expresses how many logic units form a discrete unit)
153 // for this step. This primitive is to be displayed always unscaled (in its pixel size)
154 // and unrotated, more like a marker
155 const double fLeft((0.0 - getCenterX()) * getDiscreteUnit());
156 const double fTop((0.0 - getCenterY()) * getDiscreteUnit());
157 const double fRight((aBitmapSize
.getWidth() - getCenterX()) * getDiscreteUnit());
158 const double fBottom((aBitmapSize
.getHeight() - getCenterY()) * getDiscreteUnit());
160 // create a BitmapPrimitive2D using those positions
161 basegfx::B2DHomMatrix aTransform
;
163 aTransform
.set(0, 0, fRight
- fLeft
);
164 aTransform
.set(1, 1, fBottom
- fTop
);
165 aTransform
.set(0, 2, fLeft
);
166 aTransform
.set(1, 2, fTop
);
168 // if shearX is used, apply it, too
169 if(!basegfx::fTools::equalZero(getShearX()))
171 aTransform
.shearX(getShearX());
174 // if rotation is used, apply it, too
175 if(!basegfx::fTools::equalZero(getRotation()))
177 aTransform
.rotate(getRotation());
181 aTransform
.translate(getBasePosition().getX(), getBasePosition().getY());
183 rContainer
.push_back(
184 new BitmapPrimitive2D(
185 VCLUnoHelper::CreateVCLXBitmap(getBitmapEx()),
189 bool OverlayBitmapExPrimitive::operator==( const BasePrimitive2D
& rPrimitive
) const
191 if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive
))
193 const OverlayBitmapExPrimitive
& rCompare
= static_cast< const OverlayBitmapExPrimitive
& >(rPrimitive
);
195 return (getBitmapEx() == rCompare
.getBitmapEx()
196 && getBasePosition() == rCompare
.getBasePosition()
197 && getCenterX() == rCompare
.getCenterX()
198 && getCenterY() == rCompare
.getCenterY()
199 && getShearX() == rCompare
.getShearX()
200 && getRotation() == rCompare
.getRotation());
206 ImplPrimitive2DIDBlock(OverlayBitmapExPrimitive
, PRIMITIVE2D_ID_OVERLAYBITMAPEXPRIMITIVE
)
210 OverlayCrosshairPrimitive::OverlayCrosshairPrimitive(
211 const basegfx::B2DPoint
& rBasePosition
,
212 const basegfx::BColor
& rRGBColorA
,
213 const basegfx::BColor
& rRGBColorB
,
214 double fDiscreteDashLength
)
215 : ViewportDependentPrimitive2D(),
216 maBasePosition(rBasePosition
),
217 maRGBColorA(rRGBColorA
),
218 maRGBColorB(rRGBColorB
),
219 mfDiscreteDashLength(fDiscreteDashLength
)
222 void OverlayCrosshairPrimitive::create2DDecomposition(Primitive2DContainer
& rContainer
, const geometry::ViewInformation2D
& /*rViewInformation*/) const
224 // use the prepared Viewport information accessible using getViewport()
226 if(getViewport().isEmpty())
229 basegfx::B2DPolygon aPolygon
;
231 aPolygon
.append(basegfx::B2DPoint(getViewport().getMinX(), getBasePosition().getY()));
232 aPolygon
.append(basegfx::B2DPoint(getViewport().getMaxX(), getBasePosition().getY()));
234 rContainer
.push_back(
235 new PolygonMarkerPrimitive2D(
239 getDiscreteDashLength()));
242 aPolygon
.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMinY()));
243 aPolygon
.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMaxY()));
245 rContainer
.push_back(
246 new PolygonMarkerPrimitive2D(
250 getDiscreteDashLength()));
253 bool OverlayCrosshairPrimitive::operator==( const BasePrimitive2D
& rPrimitive
) const
255 if(ViewportDependentPrimitive2D::operator==(rPrimitive
))
257 const OverlayCrosshairPrimitive
& rCompare
= static_cast< const OverlayCrosshairPrimitive
& >(rPrimitive
);
259 return (getBasePosition() == rCompare
.getBasePosition()
260 && getRGBColorA() == rCompare
.getRGBColorA()
261 && getRGBColorB() == rCompare
.getRGBColorB()
262 && getDiscreteDashLength() == rCompare
.getDiscreteDashLength());
268 ImplPrimitive2DIDBlock(OverlayCrosshairPrimitive
, PRIMITIVE2D_ID_OVERLAYCROSSHAIRPRIMITIVE
)
272 OverlayRectanglePrimitive::OverlayRectanglePrimitive(
273 const basegfx::B2DRange
& rObjectRange
,
274 const basegfx::BColor
& rColor
,
275 double fTransparence
,
276 double fDiscreteGrow
,
277 double fDiscreteShrink
,
279 : DiscreteMetricDependentPrimitive2D(),
280 maObjectRange(rObjectRange
),
282 mfTransparence(fTransparence
),
283 mfDiscreteGrow(fDiscreteGrow
),
284 mfDiscreteShrink(fDiscreteShrink
),
285 mfRotation(fRotation
)
288 void OverlayRectanglePrimitive::create2DDecomposition(Primitive2DContainer
& rContainer
, const geometry::ViewInformation2D
& /*rViewInformation*/) const
290 Primitive2DContainer aRetval
;
291 basegfx::B2DRange
aInnerRange(getObjectRange());
293 if(!aInnerRange
.isEmpty() && basegfx::fTools::more(getDiscreteUnit(), 0.0) && getTransparence() <= 1.0)
295 basegfx::B2DRange
aOuterRange(getObjectRange());
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 if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
332 // for high contrast, use hatch
333 const basegfx::BColor
aHighContrastLineColor(Application::GetSettings().GetStyleSettings().GetFontColor().getBColor());
334 const basegfx::BColor
aEmptyColor(0.0, 0.0, 0.0);
335 const double fHatchRotation(basegfx::deg2rad(45));
336 const double fDiscreteHatchDistance(3.0);
337 const drawinglayer::attribute::FillHatchAttribute
aFillHatchAttribute(
338 drawinglayer::attribute::HatchStyle::Single
,
339 fDiscreteHatchDistance
* getDiscreteUnit(),
340 fHatchRotation
- getRotation(),
341 aHighContrastLineColor
,
342 3, // same default as VCL, a minimum of three discrete units (pixels) offset
344 const Primitive2DReference
aHatch(
345 new PolyPolygonHatchPrimitive2D(
348 aFillHatchAttribute
));
350 aRetval
= Primitive2DContainer
{ aHatch
};
354 // create fill primitive
355 const Primitive2DReference
aFill(
356 new PolyPolygonColorPrimitive2D(
360 aRetval
= Primitive2DContainer
{ aFill
};
362 // embed filled to transparency (if used)
363 if(getTransparence() > 0.0)
365 const Primitive2DReference
aFillTransparent(
366 new UnifiedTransparencePrimitive2D(
370 aRetval
= Primitive2DContainer
{ aFillTransparent
};
375 rContainer
.insert(rContainer
.end(), aRetval
.begin(), aRetval
.end());
378 bool OverlayRectanglePrimitive::operator==( const BasePrimitive2D
& rPrimitive
) const
380 if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive
))
382 const OverlayRectanglePrimitive
& rCompare
= static_cast< const OverlayRectanglePrimitive
& >(rPrimitive
);
384 return (getObjectRange() == rCompare
.getObjectRange()
385 && getColor() == rCompare
.getColor()
386 && getTransparence() == rCompare
.getTransparence()
387 && getDiscreteGrow() == rCompare
.getDiscreteGrow()
388 && getDiscreteShrink() == rCompare
.getDiscreteShrink()
389 && getRotation() == rCompare
.getRotation());
395 ImplPrimitive2DIDBlock(OverlayRectanglePrimitive
, PRIMITIVE2D_ID_OVERLAYRECTANGLEPRIMITIVE
)
399 OverlayHelplineStripedPrimitive::OverlayHelplineStripedPrimitive(
400 const basegfx::B2DPoint
& rBasePosition
,
401 HelplineStyle eStyle
,
402 const basegfx::BColor
& rRGBColorA
,
403 const basegfx::BColor
& rRGBColorB
,
404 double fDiscreteDashLength
)
405 : ViewportDependentPrimitive2D(),
406 maBasePosition(rBasePosition
),
408 maRGBColorA(rRGBColorA
),
409 maRGBColorB(rRGBColorB
),
410 mfDiscreteDashLength(fDiscreteDashLength
)
413 void OverlayHelplineStripedPrimitive::create2DDecomposition(Primitive2DContainer
& rContainer
, const geometry::ViewInformation2D
& rViewInformation
) const
415 // use the prepared Viewport information accessible using getViewport()
417 if(getViewport().isEmpty())
422 case HELPLINESTYLE_VERTICAL
:
424 basegfx::B2DPolygon aLine
;
426 aLine
.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMinY()));
427 aLine
.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMaxY()));
429 rContainer
.push_back(
430 new PolygonMarkerPrimitive2D(
434 getDiscreteDashLength()));
438 case HELPLINESTYLE_HORIZONTAL
:
440 basegfx::B2DPolygon aLine
;
442 aLine
.append(basegfx::B2DPoint(getViewport().getMinX(), getBasePosition().getY()));
443 aLine
.append(basegfx::B2DPoint(getViewport().getMaxX(), getBasePosition().getY()));
445 rContainer
.push_back(
446 new PolygonMarkerPrimitive2D(
450 getDiscreteDashLength()));
454 default: // case HELPLINESTYLE_POINT :
456 const double fDiscreteUnit((rViewInformation
.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength());
457 basegfx::B2DPolygon aLineA
, aLineB
;
459 aLineA
.append(basegfx::B2DPoint(getBasePosition().getX(), getBasePosition().getY() - fDiscreteUnit
));
460 aLineA
.append(basegfx::B2DPoint(getBasePosition().getX(), getBasePosition().getY() + fDiscreteUnit
));
462 rContainer
.push_back(
463 new PolygonMarkerPrimitive2D(
467 getDiscreteDashLength()));
469 aLineB
.append(basegfx::B2DPoint(getBasePosition().getX() - fDiscreteUnit
, getBasePosition().getY()));
470 aLineB
.append(basegfx::B2DPoint(getBasePosition().getX() + fDiscreteUnit
, getBasePosition().getY()));
472 rContainer
.push_back(
473 new PolygonMarkerPrimitive2D(
477 getDiscreteDashLength()));
484 bool OverlayHelplineStripedPrimitive::operator==( const BasePrimitive2D
& rPrimitive
) const
486 if(ViewportDependentPrimitive2D::operator==(rPrimitive
))
488 const OverlayHelplineStripedPrimitive
& rCompare
= static_cast< const OverlayHelplineStripedPrimitive
& >(rPrimitive
);
490 return (getBasePosition() == rCompare
.getBasePosition()
491 && getStyle() == rCompare
.getStyle()
492 && getRGBColorA() == rCompare
.getRGBColorA()
493 && getRGBColorB() == rCompare
.getRGBColorB()
494 && getDiscreteDashLength() == rCompare
.getDiscreteDashLength());
500 ImplPrimitive2DIDBlock(OverlayHelplineStripedPrimitive
, PRIMITIVE2D_ID_OVERLAYHELPLINESTRIPEDPRIMITIVE
)
504 OverlayRollingRectanglePrimitive::OverlayRollingRectanglePrimitive(
505 const basegfx::B2DRange
& aRollingRectangle
,
506 const basegfx::BColor
& rRGBColorA
,
507 const basegfx::BColor
& rRGBColorB
,
508 double fDiscreteDashLength
)
509 : ViewportDependentPrimitive2D(),
510 maRollingRectangle(aRollingRectangle
),
511 maRGBColorA(rRGBColorA
),
512 maRGBColorB(rRGBColorB
),
513 mfDiscreteDashLength(fDiscreteDashLength
)
516 void OverlayRollingRectanglePrimitive::create2DDecomposition(Primitive2DContainer
& rContainer
, const geometry::ViewInformation2D
& /*rViewInformation*/) const
518 // use the prepared Viewport information accessible using getViewport()
520 if(getViewport().isEmpty())
523 basegfx::B2DPolygon aLine
;
526 aLine
.append(basegfx::B2DPoint(getViewport().getMinX(), getRollingRectangle().getMinY()));
527 aLine
.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMinY()));
528 rContainer
.push_back(new PolygonMarkerPrimitive2D(aLine
, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
531 aLine
.append(basegfx::B2DPoint(getViewport().getMinX(), getRollingRectangle().getMaxY()));
532 aLine
.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMaxY()));
533 rContainer
.push_back(new PolygonMarkerPrimitive2D(aLine
, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
537 aLine
.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMinY()));
538 aLine
.append(basegfx::B2DPoint(getViewport().getMaxX(), getRollingRectangle().getMinY()));
539 rContainer
.push_back(new PolygonMarkerPrimitive2D(aLine
, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
542 aLine
.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMaxY()));
543 aLine
.append(basegfx::B2DPoint(getViewport().getMaxX(), getRollingRectangle().getMaxY()));
544 rContainer
.push_back(new PolygonMarkerPrimitive2D(aLine
, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
548 aLine
.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getViewport().getMinY()));
549 aLine
.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMinY()));
550 rContainer
.push_back(new PolygonMarkerPrimitive2D(aLine
, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
553 aLine
.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getViewport().getMinY()));
554 aLine
.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMinY()));
555 rContainer
.push_back(new PolygonMarkerPrimitive2D(aLine
, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
559 aLine
.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMaxY()));
560 aLine
.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getViewport().getMaxY()));
561 rContainer
.push_back(new PolygonMarkerPrimitive2D(aLine
, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
564 aLine
.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMaxY()));
565 aLine
.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getViewport().getMaxY()));
566 rContainer
.push_back(new PolygonMarkerPrimitive2D(aLine
, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
570 bool OverlayRollingRectanglePrimitive::operator==( const BasePrimitive2D
& rPrimitive
) const
572 if(ViewportDependentPrimitive2D::operator==(rPrimitive
))
574 const OverlayRollingRectanglePrimitive
& rCompare
= static_cast< const OverlayRollingRectanglePrimitive
& >(rPrimitive
);
576 return (getRollingRectangle() == rCompare
.getRollingRectangle()
577 && getRGBColorA() == rCompare
.getRGBColorA()
578 && getRGBColorB() == rCompare
.getRGBColorB()
579 && getDiscreteDashLength() == rCompare
.getDiscreteDashLength());
585 ImplPrimitive2DIDBlock(OverlayRollingRectanglePrimitive
, PRIMITIVE2D_ID_OVERLAYROLLINGRECTANGLEPRIMITIVE
)
587 } // end of namespace
589 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */