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 "gradtrns.hxx"
22 #include <svx/svdobj.hxx>
23 #include <basegfx/range/b2drange.hxx>
24 #include <basegfx/matrix/b2dhommatrix.hxx>
25 #include <basegfx/matrix/b2dhommatrixtools.hxx>
26 #include <tools/helpers.hxx>
27 #include <vcl/canvastools.hxx>
30 void GradTransformer::GradToVec(GradTransGradient
const & rG
, GradTransVector
& rV
, const SdrObject
* pObj
)
33 rV
.aCol1
= Color(rG
.aGradient
.GetColorStops().front().getStopColor());
34 if(100 != rG
.aGradient
.GetStartIntens())
36 const double fFact(static_cast<double>(rG
.aGradient
.GetStartIntens()) / 100.0);
37 rV
.aCol1
= Color(rV
.aCol1
.getBColor() * fFact
);
41 rV
.aCol2
= Color(rG
.aGradient
.GetColorStops().back().getStopColor());
42 if(100 != rG
.aGradient
.GetEndIntens())
44 const double fFact(static_cast<double>(rG
.aGradient
.GetEndIntens()) / 100.0);
45 rV
.aCol2
= Color(rV
.aCol2
.getBColor() * fFact
);
48 // calc the basic positions
49 const tools::Rectangle
aObjectSnapRectangle(pObj
->GetSnapRect());
50 const basegfx::B2DRange aRange
= vcl::unotools::b2DRectangleFromRectangle(aObjectSnapRectangle
);
51 const basegfx::B2DPoint
aCenter(aRange
.getCenter());
52 basegfx::B2DPoint aStartPos
, aEndPos
;
54 switch(rG
.aGradient
.GetGradientStyle())
56 case css::awt::GradientStyle_LINEAR
:
58 aStartPos
= basegfx::B2DPoint(aCenter
.getX(), aRange
.getMinY());
59 aEndPos
= basegfx::B2DPoint(aCenter
.getX(), aRange
.getMaximum().getY());
61 if(rG
.aGradient
.GetBorder())
63 basegfx::B2DVector
aFullVec(aStartPos
- aEndPos
);
64 const double fLen
= (aFullVec
.getLength() * (100.0 - static_cast<double>(rG
.aGradient
.GetBorder()))) / 100.0;
66 aStartPos
= aEndPos
+ (aFullVec
* fLen
);
69 if(rG
.aGradient
.GetAngle())
71 const double fAngle
= toRadians(rG
.aGradient
.GetAngle());
72 const basegfx::B2DHomMatrix
aTransformation(basegfx::utils::createRotateAroundPoint(aCenter
, -fAngle
));
74 aStartPos
*= aTransformation
;
75 aEndPos
*= aTransformation
;
79 case css::awt::GradientStyle_AXIAL
:
82 aEndPos
= basegfx::B2DPoint(aCenter
.getX(), aRange
.getMaximum().getY());
84 if(rG
.aGradient
.GetBorder())
86 basegfx::B2DVector
aFullVec(aEndPos
- aStartPos
);
87 const double fLen
= (aFullVec
.getLength() * (100.0 - static_cast<double>(rG
.aGradient
.GetBorder()))) / 100.0;
89 aEndPos
= aStartPos
+ (aFullVec
* fLen
);
92 if(rG
.aGradient
.GetAngle())
94 const double fAngle
= toRadians(rG
.aGradient
.GetAngle());
95 const basegfx::B2DHomMatrix
aTransformation(basegfx::utils::createRotateAroundPoint(aCenter
, -fAngle
));
97 aStartPos
*= aTransformation
;
98 aEndPos
*= aTransformation
;
102 case css::awt::GradientStyle_RADIAL
:
103 case css::awt::GradientStyle_SQUARE
:
105 aStartPos
= basegfx::B2DPoint(aRange
.getMinX(), aRange
.getMaximum().getY());
106 aEndPos
= basegfx::B2DPoint(aRange
.getMinX(), aRange
.getMinY());
108 if(rG
.aGradient
.GetBorder())
110 basegfx::B2DVector
aFullVec(aStartPos
- aEndPos
);
111 const double fLen
= (aFullVec
.getLength() * (100.0 - static_cast<double>(rG
.aGradient
.GetBorder()))) / 100.0;
112 aFullVec
.normalize();
113 aStartPos
= aEndPos
+ (aFullVec
* fLen
);
116 if(rG
.aGradient
.GetAngle())
118 const double fAngle
= toRadians(rG
.aGradient
.GetAngle());
119 const basegfx::B2DHomMatrix
aTransformation(basegfx::utils::createRotateAroundPoint(aEndPos
, -fAngle
));
121 aStartPos
*= aTransformation
;
122 aEndPos
*= aTransformation
;
125 if(rG
.aGradient
.GetXOffset() || rG
.aGradient
.GetYOffset())
127 basegfx::B2DPoint
aOffset(
128 (aRange
.getWidth() * rG
.aGradient
.GetXOffset()) / 100.0,
129 (aRange
.getHeight() * rG
.aGradient
.GetYOffset()) / 100.0);
131 aStartPos
+= aOffset
;
137 case css::awt::GradientStyle_ELLIPTICAL
:
138 case css::awt::GradientStyle_RECT
:
140 aStartPos
= basegfx::B2DPoint(aRange
.getMinX(), aCenter
.getY());
141 aEndPos
= basegfx::B2DPoint(aRange
.getMinX(), aRange
.getMinY());
143 if(rG
.aGradient
.GetBorder())
145 basegfx::B2DVector
aFullVec(aStartPos
- aEndPos
);
146 const double fLen
= (aFullVec
.getLength() * (100.0 - static_cast<double>(rG
.aGradient
.GetBorder()))) / 100.0;
147 aFullVec
.normalize();
148 aStartPos
= aEndPos
+ (aFullVec
* fLen
);
151 if(rG
.aGradient
.GetAngle())
153 const double fAngle
= toRadians(rG
.aGradient
.GetAngle());
154 const basegfx::B2DHomMatrix
aTransformation(basegfx::utils::createRotateAroundPoint(aEndPos
, -fAngle
));
156 aStartPos
*= aTransformation
;
157 aEndPos
*= aTransformation
;
160 if(rG
.aGradient
.GetXOffset() || rG
.aGradient
.GetYOffset())
162 basegfx::B2DPoint
aOffset(
163 (aRange
.getWidth() * rG
.aGradient
.GetXOffset()) / 100.0,
164 (aRange
.getHeight() * rG
.aGradient
.GetYOffset()) / 100.0);
166 aStartPos
+= aOffset
;
176 // set values for vector positions now
177 rV
.maPositionA
= aStartPos
;
178 rV
.maPositionB
= aEndPos
;
182 void GradTransformer::VecToGrad(GradTransVector
const & rV
, GradTransGradient
& rG
, GradTransGradient
const & rGOld
, const SdrObject
* pObj
,
183 bool bMoveSingle
, bool bMoveFirst
)
185 // fill old gradient to new gradient to have a base
188 // handle color changes
189 if(rV
.aCol1
!= Color(rGOld
.aGradient
.GetColorStops().front().getStopColor()))
191 basegfx::BColorStops
aNewColorStops(rG
.aGradient
.GetColorStops());
192 aNewColorStops
.replaceStartColor(rV
.aCol1
.getBColor());
193 rG
.aGradient
.SetColorStops(aNewColorStops
);
194 rG
.aGradient
.SetStartIntens(100);
196 if(rV
.aCol2
!= Color(rGOld
.aGradient
.GetColorStops().back().getStopColor()))
198 basegfx::BColorStops
aNewColorStops(rG
.aGradient
.GetColorStops());
199 aNewColorStops
.replaceEndColor(rV
.aCol2
.getBColor());
200 rG
.aGradient
.SetColorStops(aNewColorStops
);
201 rG
.aGradient
.SetEndIntens(100);
204 // calc the basic positions
205 const tools::Rectangle
aObjectSnapRectangle(pObj
->GetSnapRect());
206 const basegfx::B2DRange aRange
= vcl::unotools::b2DRectangleFromRectangle(aObjectSnapRectangle
);
207 const basegfx::B2DPoint
aCenter(aRange
.getCenter());
208 basegfx::B2DPoint
aStartPos(rV
.maPositionA
);
209 basegfx::B2DPoint
aEndPos(rV
.maPositionB
);
211 switch(rG
.aGradient
.GetGradientStyle())
213 case css::awt::GradientStyle_LINEAR
:
215 if(!bMoveSingle
|| !bMoveFirst
)
217 basegfx::B2DVector
aFullVec(aEndPos
- aStartPos
);
221 aFullVec
= aEndPos
- aCenter
;
224 aFullVec
.normalize();
226 double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec
.getY(), aFullVec
.getX())));
227 fNewFullAngle
*= -10.0;
228 fNewFullAngle
+= 900.0;
231 while(fNewFullAngle
< 0.0)
233 fNewFullAngle
+= 3600.0;
236 while(fNewFullAngle
>= 3600.0)
238 fNewFullAngle
-= 3600.0;
242 Degree10
nNewAngle(basegfx::fround
<sal_Int16
>(fNewFullAngle
));
244 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
246 rG
.aGradient
.SetAngle(nNewAngle
);
250 if(!bMoveSingle
|| bMoveFirst
)
252 const basegfx::B2DVector
aFullVec(aEndPos
- aStartPos
);
253 const basegfx::B2DPoint
aBottomLeft(aRange
.getMinX(), aRange
.getMaximum().getY());
254 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
255 const basegfx::B2DVector
aOldVec(aBottomLeft
- aTopLeft
);
256 const double fFullLen(aFullVec
.getLength());
257 const double fOldLen(aOldVec
.getLength());
258 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
259 sal_Int32
nNewBorder(100 - basegfx::fround(fNewBorder
));
273 if(nNewBorder
!= rG
.aGradient
.GetBorder())
275 rG
.aGradient
.SetBorder(static_cast<sal_uInt16
>(nNewBorder
));
281 case css::awt::GradientStyle_AXIAL
:
283 if(!bMoveSingle
|| !bMoveFirst
)
285 basegfx::B2DVector
aFullVec(aEndPos
- aCenter
);
286 const basegfx::B2DVector
aOldVec(basegfx::B2DPoint(aCenter
.getX(), aRange
.getMaximum().getY()) - aCenter
);
287 const double fFullLen(aFullVec
.getLength());
288 const double fOldLen(aOldVec
.getLength());
289 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
290 sal_Int32 nNewBorder
= 100 - basegfx::fround(fNewBorder
);
304 if(nNewBorder
!= rG
.aGradient
.GetBorder())
306 rG
.aGradient
.SetBorder(static_cast<sal_uInt16
>(nNewBorder
));
309 aFullVec
.normalize();
310 double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec
.getY(), aFullVec
.getX())));
311 fNewFullAngle
*= -10.0;
312 fNewFullAngle
+= 900.0;
315 while(fNewFullAngle
< 0.0)
317 fNewFullAngle
+= 3600.0;
320 while(fNewFullAngle
>= 3600.0)
322 fNewFullAngle
-= 3600.0;
326 const Degree10
nNewAngle(basegfx::fround
<sal_Int16
>(fNewFullAngle
));
328 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
330 rG
.aGradient
.SetAngle(nNewAngle
);
336 case css::awt::GradientStyle_RADIAL
:
337 case css::awt::GradientStyle_SQUARE
:
339 if(!bMoveSingle
|| !bMoveFirst
)
341 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
342 const basegfx::B2DPoint
aOffset(aEndPos
- aTopLeft
);
343 sal_Int32
nNewXOffset(basegfx::fround(aOffset
.getX() * 100.0 / aRange
.getWidth()));
344 sal_Int32
nNewYOffset(basegfx::fround(aOffset
.getY() * 100.0 / aRange
.getHeight()));
352 if(nNewXOffset
> 100)
362 if(nNewYOffset
> 100)
367 rG
.aGradient
.SetXOffset(static_cast<sal_uInt16
>(nNewXOffset
));
368 rG
.aGradient
.SetYOffset(static_cast<sal_uInt16
>(nNewYOffset
));
370 aStartPos
-= aOffset
;
374 if(!bMoveSingle
|| bMoveFirst
)
376 basegfx::B2DVector
aFullVec(aStartPos
- aEndPos
);
377 const basegfx::B2DPoint
aBottomLeft(aRange
.getMinX(), aRange
.getMaximum().getY());
378 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
379 const basegfx::B2DVector
aOldVec(aBottomLeft
- aTopLeft
);
380 const double fFullLen(aFullVec
.getLength());
381 const double fOldLen(aOldVec
.getLength());
382 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
383 sal_Int32
nNewBorder(100 - basegfx::fround(fNewBorder
));
397 if(nNewBorder
!= rG
.aGradient
.GetBorder())
399 rG
.aGradient
.SetBorder(static_cast<sal_uInt16
>(nNewBorder
));
402 // angle is not definitely necessary for these modes, but it makes
403 // controlling more fun for the user
404 aFullVec
.normalize();
405 double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec
.getY(), aFullVec
.getX())));
406 fNewFullAngle
*= -10.0;
407 fNewFullAngle
+= 900.0;
410 while(fNewFullAngle
< 0.0)
412 fNewFullAngle
+= 3600.0;
415 while(fNewFullAngle
>= 3600.0)
417 fNewFullAngle
-= 3600.0;
421 const Degree10
nNewAngle(basegfx::fround
<sal_Int16
>(fNewFullAngle
));
423 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
425 rG
.aGradient
.SetAngle(nNewAngle
);
431 case css::awt::GradientStyle_ELLIPTICAL
:
432 case css::awt::GradientStyle_RECT
:
434 if(!bMoveSingle
|| !bMoveFirst
)
436 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
437 const basegfx::B2DPoint
aOffset(aEndPos
- aTopLeft
);
438 sal_Int32
nNewXOffset(basegfx::fround(aOffset
.getX() * 100.0 / aRange
.getWidth()));
439 sal_Int32
nNewYOffset(basegfx::fround(aOffset
.getY() * 100.0 / aRange
.getHeight()));
447 if(nNewXOffset
> 100)
457 if(nNewYOffset
> 100)
462 rG
.aGradient
.SetXOffset(static_cast<sal_uInt16
>(nNewXOffset
));
463 rG
.aGradient
.SetYOffset(static_cast<sal_uInt16
>(nNewYOffset
));
465 aStartPos
-= aOffset
;
469 if(!bMoveSingle
|| bMoveFirst
)
471 basegfx::B2DVector
aFullVec(aStartPos
- aEndPos
);
472 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
473 const basegfx::B2DPoint
aCenterLeft(aRange
.getMinX(), aCenter
.getY());
474 const basegfx::B2DVector
aOldVec(aCenterLeft
- aTopLeft
);
475 const double fFullLen(aFullVec
.getLength());
476 const double fOldLen(aOldVec
.getLength());
477 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
478 sal_Int32
nNewBorder(100 - basegfx::fround(fNewBorder
));
492 if(nNewBorder
!= rG
.aGradient
.GetBorder())
494 rG
.aGradient
.SetBorder(static_cast<sal_uInt16
>(nNewBorder
));
497 // angle is not definitely necessary for these modes, but it makes
498 // controlling more fun for the user
499 aFullVec
.normalize();
500 double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec
.getY(), aFullVec
.getX())));
501 fNewFullAngle
*= -10.0;
502 fNewFullAngle
+= 900.0;
505 while(fNewFullAngle
< 0.0)
507 fNewFullAngle
+= 3600.0;
510 while(fNewFullAngle
>= 3600.0)
512 fNewFullAngle
-= 3600.0;
516 const Degree10
nNewAngle(basegfx::fround
<sal_Int16
>(fNewFullAngle
));
518 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
520 rG
.aGradient
.SetAngle(nNewAngle
);
531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */