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/outdev.hxx>
30 void GradTransformer::GradToVec(GradTransGradient
const & rG
, GradTransVector
& rV
, const SdrObject
* pObj
)
33 rV
.aCol1
= rG
.aGradient
.GetStartColor();
34 if(100 != rG
.aGradient
.GetStartIntens())
36 const double fFact((double)rG
.aGradient
.GetStartIntens() / 100.0);
37 rV
.aCol1
= Color(rV
.aCol1
.getBColor() * fFact
);
41 rV
.aCol2
= rG
.aGradient
.GetEndColor();
42 if(100 != rG
.aGradient
.GetEndIntens())
44 const double fFact((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(aObjectSnapRectangle
.Left(), aObjectSnapRectangle
.Top(), aObjectSnapRectangle
.Right(), aObjectSnapRectangle
.Bottom());
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 - (double)rG
.aGradient
.GetBorder())) / 100.0;
66 aStartPos
= aEndPos
+ (aFullVec
* fLen
);
69 if(rG
.aGradient
.GetAngle())
71 const double fAngle
= (double)rG
.aGradient
.GetAngle() * (F_PI180
/ 10.0);
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 - (double)rG
.aGradient
.GetBorder())) / 100.0;
89 aEndPos
= aStartPos
+ (aFullVec
* fLen
);
92 if(rG
.aGradient
.GetAngle())
94 const double fAngle
= (double)rG
.aGradient
.GetAngle() * (F_PI180
/ 10.0);
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 - (double)rG
.aGradient
.GetBorder())) / 100.0;
112 aFullVec
.normalize();
113 aStartPos
= aEndPos
+ (aFullVec
* fLen
);
116 if(rG
.aGradient
.GetAngle())
118 const double fAngle
= (double)rG
.aGradient
.GetAngle() * (F_PI180
/ 10.0);
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 - (double)rG
.aGradient
.GetBorder())) / 100.0;
147 aFullVec
.normalize();
148 aStartPos
= aEndPos
+ (aFullVec
* fLen
);
151 if(rG
.aGradient
.GetAngle())
153 const double fAngle
= (double)rG
.aGradient
.GetAngle() * (F_PI180
/ 10.0);
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
!= rGOld
.aGradient
.GetStartColor())
191 rG
.aGradient
.SetStartColor(rV
.aCol1
);
192 rG
.aGradient
.SetStartIntens(100);
194 if(rV
.aCol2
!= rGOld
.aGradient
.GetEndColor())
196 rG
.aGradient
.SetEndColor(rV
.aCol2
);
197 rG
.aGradient
.SetEndIntens(100);
200 // calc the basic positions
201 const tools::Rectangle
aObjectSnapRectangle(pObj
->GetSnapRect());
202 const basegfx::B2DRange
aRange(aObjectSnapRectangle
.Left(), aObjectSnapRectangle
.Top(), aObjectSnapRectangle
.Right(), aObjectSnapRectangle
.Bottom());
203 const basegfx::B2DPoint
aCenter(aRange
.getCenter());
204 basegfx::B2DPoint
aStartPos(rV
.maPositionA
);
205 basegfx::B2DPoint
aEndPos(rV
.maPositionB
);
207 switch(rG
.aGradient
.GetGradientStyle())
209 case css::awt::GradientStyle_LINEAR
:
211 if(!bMoveSingle
|| !bMoveFirst
)
213 basegfx::B2DVector
aFullVec(aEndPos
- aStartPos
);
217 aFullVec
= aEndPos
- aCenter
;
220 aFullVec
.normalize();
222 double fNewFullAngle(atan2(aFullVec
.getY(), aFullVec
.getX()));
223 fNewFullAngle
/= F_PI180
;
224 fNewFullAngle
*= -10.0;
225 fNewFullAngle
+= 900.0;
228 while(fNewFullAngle
< 0.0)
230 fNewFullAngle
+= 3600.0;
233 while(fNewFullAngle
>= 3600.0)
235 fNewFullAngle
-= 3600.0;
239 sal_Int32 nNewAngle
= FRound(fNewFullAngle
);
241 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
243 rG
.aGradient
.SetAngle(nNewAngle
);
247 if(!bMoveSingle
|| bMoveFirst
)
249 const basegfx::B2DVector
aFullVec(aEndPos
- aStartPos
);
250 const basegfx::B2DPoint
aBottomLeft(aRange
.getMinX(), aRange
.getMaximum().getY());
251 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
252 const basegfx::B2DVector
aOldVec(aBottomLeft
- aTopLeft
);
253 const double fFullLen(aFullVec
.getLength());
254 const double fOldLen(aOldVec
.getLength());
255 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
256 sal_Int32
nNewBorder(100 - FRound(fNewBorder
));
270 if(nNewBorder
!= rG
.aGradient
.GetBorder())
272 rG
.aGradient
.SetBorder((sal_uInt16
)nNewBorder
);
278 case css::awt::GradientStyle_AXIAL
:
280 if(!bMoveSingle
|| !bMoveFirst
)
282 basegfx::B2DVector
aFullVec(aEndPos
- aCenter
);
283 const basegfx::B2DVector
aOldVec(basegfx::B2DPoint(aCenter
.getX(), aRange
.getMaximum().getY()) - aCenter
);
284 const double fFullLen(aFullVec
.getLength());
285 const double fOldLen(aOldVec
.getLength());
286 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
287 sal_Int32 nNewBorder
= 100 - FRound(fNewBorder
);
301 if(nNewBorder
!= rG
.aGradient
.GetBorder())
303 rG
.aGradient
.SetBorder((sal_uInt16
)nNewBorder
);
306 aFullVec
.normalize();
307 double fNewFullAngle(atan2(aFullVec
.getY(), aFullVec
.getX()));
308 fNewFullAngle
/= F_PI180
;
309 fNewFullAngle
*= -10.0;
310 fNewFullAngle
+= 900.0;
313 while(fNewFullAngle
< 0.0)
315 fNewFullAngle
+= 3600.0;
318 while(fNewFullAngle
>= 3600.0)
320 fNewFullAngle
-= 3600.0;
324 const sal_Int32
nNewAngle(FRound(fNewFullAngle
));
326 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
328 rG
.aGradient
.SetAngle(nNewAngle
);
334 case css::awt::GradientStyle_RADIAL
:
335 case css::awt::GradientStyle_SQUARE
:
337 if(!bMoveSingle
|| !bMoveFirst
)
339 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
340 const basegfx::B2DPoint
aOffset(aEndPos
- aTopLeft
);
341 sal_Int32
nNewXOffset(FRound((aOffset
.getX() * 100.0) / aRange
.getWidth()));
342 sal_Int32
nNewYOffset(FRound((aOffset
.getY() * 100.0) / aRange
.getHeight()));
350 if(nNewXOffset
> 100)
360 if(nNewYOffset
> 100)
365 rG
.aGradient
.SetXOffset((sal_uInt16
)nNewXOffset
);
366 rG
.aGradient
.SetYOffset((sal_uInt16
)nNewYOffset
);
368 aStartPos
-= aOffset
;
372 if(!bMoveSingle
|| bMoveFirst
)
374 basegfx::B2DVector
aFullVec(aStartPos
- aEndPos
);
375 const basegfx::B2DPoint
aBottomLeft(aRange
.getMinX(), aRange
.getMaximum().getY());
376 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
377 const basegfx::B2DVector
aOldVec(aBottomLeft
- aTopLeft
);
378 const double fFullLen(aFullVec
.getLength());
379 const double fOldLen(aOldVec
.getLength());
380 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
381 sal_Int32
nNewBorder(100 - FRound(fNewBorder
));
395 if(nNewBorder
!= rG
.aGradient
.GetBorder())
397 rG
.aGradient
.SetBorder((sal_uInt16
)nNewBorder
);
400 // angle is not definitely necessary for these modes, but it makes
401 // controlling more fun for the user
402 aFullVec
.normalize();
403 double fNewFullAngle(atan2(aFullVec
.getY(), aFullVec
.getX()));
404 fNewFullAngle
/= F_PI180
;
405 fNewFullAngle
*= -10.0;
406 fNewFullAngle
+= 900.0;
409 while(fNewFullAngle
< 0.0)
411 fNewFullAngle
+= 3600.0;
414 while(fNewFullAngle
>= 3600.0)
416 fNewFullAngle
-= 3600.0;
420 const sal_Int32
nNewAngle(FRound(fNewFullAngle
));
422 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
424 rG
.aGradient
.SetAngle(nNewAngle
);
430 case css::awt::GradientStyle_ELLIPTICAL
:
431 case css::awt::GradientStyle_RECT
:
433 if(!bMoveSingle
|| !bMoveFirst
)
435 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
436 const basegfx::B2DPoint
aOffset(aEndPos
- aTopLeft
);
437 sal_Int32
nNewXOffset(FRound((aOffset
.getX() * 100.0) / aRange
.getWidth()));
438 sal_Int32
nNewYOffset(FRound((aOffset
.getY() * 100.0) / aRange
.getHeight()));
446 if(nNewXOffset
> 100)
456 if(nNewYOffset
> 100)
461 rG
.aGradient
.SetXOffset((sal_uInt16
)nNewXOffset
);
462 rG
.aGradient
.SetYOffset((sal_uInt16
)nNewYOffset
);
464 aStartPos
-= aOffset
;
468 if(!bMoveSingle
|| bMoveFirst
)
470 basegfx::B2DVector
aFullVec(aStartPos
- aEndPos
);
471 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
472 const basegfx::B2DPoint
aCenterLeft(aRange
.getMinX(), aCenter
.getY());
473 const basegfx::B2DVector
aOldVec(aCenterLeft
- aTopLeft
);
474 const double fFullLen(aFullVec
.getLength());
475 const double fOldLen(aOldVec
.getLength());
476 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
477 sal_Int32
nNewBorder(100 - FRound(fNewBorder
));
491 if(nNewBorder
!= rG
.aGradient
.GetBorder())
493 rG
.aGradient
.SetBorder((sal_uInt16
)nNewBorder
);
496 // angle is not definitely necessary for these modes, but it makes
497 // controlling more fun for the user
498 aFullVec
.normalize();
499 double fNewFullAngle(atan2(aFullVec
.getY(), aFullVec
.getX()));
500 fNewFullAngle
/= F_PI180
;
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 sal_Int32
nNewAngle(FRound(fNewFullAngle
));
518 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
520 rG
.aGradient
.SetAngle(nNewAngle
);
531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */