LibreOffice Module svx (master) 1
gradtrns.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21#include "gradtrns.hxx"
22#include <svx/svdobj.hxx>
26#include <tools/helpers.hxx>
27#include <vcl/canvastools.hxx>
28
29
31{
32 // handle start color
33 rV.aCol1 = Color(rG.aGradient.GetColorStops().front().getStopColor());
34 if(100 != rG.aGradient.GetStartIntens())
35 {
36 const double fFact(static_cast<double>(rG.aGradient.GetStartIntens()) / 100.0);
37 rV.aCol1 = Color(rV.aCol1.getBColor() * fFact);
38 }
39
40 // handle end color
41 rV.aCol2 = Color(rG.aGradient.GetColorStops().back().getStopColor());
42 if(100 != rG.aGradient.GetEndIntens())
43 {
44 const double fFact(static_cast<double>(rG.aGradient.GetEndIntens()) / 100.0);
45 rV.aCol2 = Color(rV.aCol2.getBColor() * fFact);
46 }
47
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;
53
54 switch(rG.aGradient.GetGradientStyle())
55 {
56 case css::awt::GradientStyle_LINEAR :
57 {
58 aStartPos = basegfx::B2DPoint(aCenter.getX(), aRange.getMinY());
59 aEndPos = basegfx::B2DPoint(aCenter.getX(), aRange.getMaximum().getY());
60
61 if(rG.aGradient.GetBorder())
62 {
63 basegfx::B2DVector aFullVec(aStartPos - aEndPos);
64 const double fLen = (aFullVec.getLength() * (100.0 - static_cast<double>(rG.aGradient.GetBorder()))) / 100.0;
65 aFullVec.normalize();
66 aStartPos = aEndPos + (aFullVec * fLen);
67 }
68
69 if(rG.aGradient.GetAngle())
70 {
71 const double fAngle = toRadians(rG.aGradient.GetAngle());
72 const basegfx::B2DHomMatrix aTransformation(basegfx::utils::createRotateAroundPoint(aCenter, -fAngle));
73
74 aStartPos *= aTransformation;
75 aEndPos *= aTransformation;
76 }
77 break;
78 }
79 case css::awt::GradientStyle_AXIAL :
80 {
81 aStartPos = aCenter;
82 aEndPos = basegfx::B2DPoint(aCenter.getX(), aRange.getMaximum().getY());
83
84 if(rG.aGradient.GetBorder())
85 {
86 basegfx::B2DVector aFullVec(aEndPos - aStartPos);
87 const double fLen = (aFullVec.getLength() * (100.0 - static_cast<double>(rG.aGradient.GetBorder()))) / 100.0;
88 aFullVec.normalize();
89 aEndPos = aStartPos + (aFullVec * fLen);
90 }
91
92 if(rG.aGradient.GetAngle())
93 {
94 const double fAngle = toRadians(rG.aGradient.GetAngle());
95 const basegfx::B2DHomMatrix aTransformation(basegfx::utils::createRotateAroundPoint(aCenter, -fAngle));
96
97 aStartPos *= aTransformation;
98 aEndPos *= aTransformation;
99 }
100 break;
101 }
102 case css::awt::GradientStyle_RADIAL :
103 case css::awt::GradientStyle_SQUARE :
104 {
105 aStartPos = basegfx::B2DPoint(aRange.getMinX(), aRange.getMaximum().getY());
106 aEndPos = basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY());
107
108 if(rG.aGradient.GetBorder())
109 {
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);
114 }
115
116 if(rG.aGradient.GetAngle())
117 {
118 const double fAngle = toRadians(rG.aGradient.GetAngle());
119 const basegfx::B2DHomMatrix aTransformation(basegfx::utils::createRotateAroundPoint(aEndPos, -fAngle));
120
121 aStartPos *= aTransformation;
122 aEndPos *= aTransformation;
123 }
124
126 {
127 basegfx::B2DPoint aOffset(
128 (aRange.getWidth() * rG.aGradient.GetXOffset()) / 100.0,
129 (aRange.getHeight() * rG.aGradient.GetYOffset()) / 100.0);
130
131 aStartPos += aOffset;
132 aEndPos += aOffset;
133 }
134
135 break;
136 }
137 case css::awt::GradientStyle_ELLIPTICAL :
138 case css::awt::GradientStyle_RECT :
139 {
140 aStartPos = basegfx::B2DPoint(aRange.getMinX(), aCenter.getY());
141 aEndPos = basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY());
142
143 if(rG.aGradient.GetBorder())
144 {
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);
149 }
150
151 if(rG.aGradient.GetAngle())
152 {
153 const double fAngle = toRadians(rG.aGradient.GetAngle());
154 const basegfx::B2DHomMatrix aTransformation(basegfx::utils::createRotateAroundPoint(aEndPos, -fAngle));
155
156 aStartPos *= aTransformation;
157 aEndPos *= aTransformation;
158 }
159
161 {
162 basegfx::B2DPoint aOffset(
163 (aRange.getWidth() * rG.aGradient.GetXOffset()) / 100.0,
164 (aRange.getHeight() * rG.aGradient.GetYOffset()) / 100.0);
165
166 aStartPos += aOffset;
167 aEndPos += aOffset;
168 }
169
170 break;
171 }
172 default:
173 break;
174 }
175
176 // set values for vector positions now
177 rV.maPositionA = aStartPos;
178 rV.maPositionB = aEndPos;
179}
180
181
183 bool bMoveSingle, bool bMoveFirst)
184{
185 // fill old gradient to new gradient to have a base
186 rG = rGOld;
187
188 // handle color changes
189 if(rV.aCol1 != Color(rGOld.aGradient.GetColorStops().front().getStopColor()))
190 {
191 basegfx::BColorStops aNewColorStops(rG.aGradient.GetColorStops());
192 aNewColorStops.replaceStartColor(rV.aCol1.getBColor());
193 rG.aGradient.SetColorStops(aNewColorStops);
195 }
196 if(rV.aCol2 != Color(rGOld.aGradient.GetColorStops().back().getStopColor()))
197 {
198 basegfx::BColorStops aNewColorStops(rG.aGradient.GetColorStops());
199 aNewColorStops.replaceEndColor(rV.aCol2.getBColor());
200 rG.aGradient.SetColorStops(aNewColorStops);
201 rG.aGradient.SetEndIntens(100);
202 }
203
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);
210
211 switch(rG.aGradient.GetGradientStyle())
212 {
213 case css::awt::GradientStyle_LINEAR :
214 {
215 if(!bMoveSingle || !bMoveFirst)
216 {
217 basegfx::B2DVector aFullVec(aEndPos - aStartPos);
218
219 if(bMoveSingle)
220 {
221 aFullVec = aEndPos - aCenter;
222 }
223
224 aFullVec.normalize();
225
226 double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec.getY(), aFullVec.getX())));
227 fNewFullAngle *= -10.0;
228 fNewFullAngle += 900.0;
229
230 // clip
231 while(fNewFullAngle < 0.0)
232 {
233 fNewFullAngle += 3600.0;
234 }
235
236 while(fNewFullAngle >= 3600.0)
237 {
238 fNewFullAngle -= 3600.0;
239 }
240
241 // to int and set
242 Degree10 nNewAngle( FRound(fNewFullAngle));
243
244 if(nNewAngle != rGOld.aGradient.GetAngle())
245 {
246 rG.aGradient.SetAngle(nNewAngle);
247 }
248 }
249
250 if(!bMoveSingle || bMoveFirst)
251 {
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 - FRound(fNewBorder));
260
261 // clip
262 if(nNewBorder < 0)
263 {
264 nNewBorder = 0;
265 }
266
267 if(nNewBorder > 100)
268 {
269 nNewBorder = 100;
270 }
271
272 // set
273 if(nNewBorder != rG.aGradient.GetBorder())
274 {
275 rG.aGradient.SetBorder(static_cast<sal_uInt16>(nNewBorder));
276 }
277 }
278
279 break;
280 }
281 case css::awt::GradientStyle_AXIAL :
282 {
283 if(!bMoveSingle || !bMoveFirst)
284 {
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 - FRound(fNewBorder);
291
292 // clip
293 if(nNewBorder < 0)
294 {
295 nNewBorder = 0;
296 }
297
298 if(nNewBorder > 100)
299 {
300 nNewBorder = 100;
301 }
302
303 // set
304 if(nNewBorder != rG.aGradient.GetBorder())
305 {
306 rG.aGradient.SetBorder(static_cast<sal_uInt16>(nNewBorder));
307 }
308
309 aFullVec.normalize();
310 double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec.getY(), aFullVec.getX())));
311 fNewFullAngle *= -10.0;
312 fNewFullAngle += 900.0;
313
314 // clip
315 while(fNewFullAngle < 0.0)
316 {
317 fNewFullAngle += 3600.0;
318 }
319
320 while(fNewFullAngle >= 3600.0)
321 {
322 fNewFullAngle -= 3600.0;
323 }
324
325 // to int and set
326 const Degree10 nNewAngle(FRound(fNewFullAngle));
327
328 if(nNewAngle != rGOld.aGradient.GetAngle())
329 {
330 rG.aGradient.SetAngle(nNewAngle);
331 }
332 }
333
334 break;
335 }
336 case css::awt::GradientStyle_RADIAL :
337 case css::awt::GradientStyle_SQUARE :
338 {
339 if(!bMoveSingle || !bMoveFirst)
340 {
341 const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
342 const basegfx::B2DPoint aOffset(aEndPos - aTopLeft);
343 sal_Int32 nNewXOffset(FRound((aOffset.getX() * 100.0) / aRange.getWidth()));
344 sal_Int32 nNewYOffset(FRound((aOffset.getY() * 100.0) / aRange.getHeight()));
345
346 // clip
347 if(nNewXOffset < 0)
348 {
349 nNewXOffset = 0;
350 }
351
352 if(nNewXOffset > 100)
353 {
354 nNewXOffset = 100;
355 }
356
357 if(nNewYOffset < 0)
358 {
359 nNewYOffset = 0;
360 }
361
362 if(nNewYOffset > 100)
363 {
364 nNewYOffset = 100;
365 }
366
367 rG.aGradient.SetXOffset(static_cast<sal_uInt16>(nNewXOffset));
368 rG.aGradient.SetYOffset(static_cast<sal_uInt16>(nNewYOffset));
369
370 aStartPos -= aOffset;
371 aEndPos -= aOffset;
372 }
373
374 if(!bMoveSingle || bMoveFirst)
375 {
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 - FRound(fNewBorder));
384
385 // clip
386 if(nNewBorder < 0)
387 {
388 nNewBorder = 0;
389 }
390
391 if(nNewBorder > 100)
392 {
393 nNewBorder = 100;
394 }
395
396 // set
397 if(nNewBorder != rG.aGradient.GetBorder())
398 {
399 rG.aGradient.SetBorder(static_cast<sal_uInt16>(nNewBorder));
400 }
401
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;
408
409 // clip
410 while(fNewFullAngle < 0.0)
411 {
412 fNewFullAngle += 3600.0;
413 }
414
415 while(fNewFullAngle >= 3600.0)
416 {
417 fNewFullAngle -= 3600.0;
418 }
419
420 // to int and set
421 const Degree10 nNewAngle(FRound(fNewFullAngle));
422
423 if(nNewAngle != rGOld.aGradient.GetAngle())
424 {
425 rG.aGradient.SetAngle(nNewAngle);
426 }
427 }
428
429 break;
430 }
431 case css::awt::GradientStyle_ELLIPTICAL :
432 case css::awt::GradientStyle_RECT :
433 {
434 if(!bMoveSingle || !bMoveFirst)
435 {
436 const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
437 const basegfx::B2DPoint aOffset(aEndPos - aTopLeft);
438 sal_Int32 nNewXOffset(FRound((aOffset.getX() * 100.0) / aRange.getWidth()));
439 sal_Int32 nNewYOffset(FRound((aOffset.getY() * 100.0) / aRange.getHeight()));
440
441 // clip
442 if(nNewXOffset < 0)
443 {
444 nNewXOffset = 0;
445 }
446
447 if(nNewXOffset > 100)
448 {
449 nNewXOffset = 100;
450 }
451
452 if(nNewYOffset < 0)
453 {
454 nNewYOffset = 0;
455 }
456
457 if(nNewYOffset > 100)
458 {
459 nNewYOffset = 100;
460 }
461
462 rG.aGradient.SetXOffset(static_cast<sal_uInt16>(nNewXOffset));
463 rG.aGradient.SetYOffset(static_cast<sal_uInt16>(nNewYOffset));
464
465 aStartPos -= aOffset;
466 aEndPos -= aOffset;
467 }
468
469 if(!bMoveSingle || bMoveFirst)
470 {
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 - FRound(fNewBorder));
479
480 // clip
481 if(nNewBorder < 0)
482 {
483 nNewBorder = 0;
484 }
485
486 if(nNewBorder > 100)
487 {
488 nNewBorder = 100;
489 }
490
491 // set
492 if(nNewBorder != rG.aGradient.GetBorder())
493 {
494 rG.aGradient.SetBorder(static_cast<sal_uInt16>(nNewBorder));
495 }
496
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;
503
504 // clip
505 while(fNewFullAngle < 0.0)
506 {
507 fNewFullAngle += 3600.0;
508 }
509
510 while(fNewFullAngle >= 3600.0)
511 {
512 fNewFullAngle -= 3600.0;
513 }
514
515 // to int and set
516 const Degree10 nNewAngle(FRound(fNewFullAngle));
517
518 if(nNewAngle != rGOld.aGradient.GetAngle())
519 {
520 rG.aGradient.SetAngle(nNewAngle);
521 }
522 }
523
524 break;
525 }
526 default:
527 break;
528 }
529}
530
531/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
basegfx::BColor getBColor() const
basegfx::BGradient aGradient
Definition: gradtrns.hxx:41
basegfx::B2DPoint maPositionA
Definition: gradtrns.hxx:32
basegfx::B2DPoint maPositionB
Definition: gradtrns.hxx:33
Abstract DrawObject.
Definition: svdobj.hxx:260
virtual const tools::Rectangle & GetSnapRect() const
Definition: svdobj.cxx:1662
B2DPoint getMaximum() const
B2DPoint getCenter() const
B2DVector & normalize()
double getLength() const
void replaceEndColor(const BColor &rEnd)
void replaceStartColor(const BColor &rStart)
sal_uInt16 GetBorder() const
sal_uInt16 GetStartIntens() const
void SetColorStops(const basegfx::BColorStops &rSteps)
void SetEndIntens(sal_uInt16 nNewIntens)
void SetYOffset(sal_uInt16 nNewOffset)
void SetXOffset(sal_uInt16 nNewOffset)
sal_uInt16 GetXOffset() const
void SetBorder(sal_uInt16 nNewBorder)
const basegfx::BColorStops & GetColorStops() const
sal_uInt16 GetEndIntens() const
Degree10 GetAngle() const
css::awt::GradientStyle GetGradientStyle() const
void SetStartIntens(sal_uInt16 nNewIntens)
void SetAngle(Degree10 nNewAngle)
sal_uInt16 GetYOffset() const
TYPE getWidth() const
TYPE getMinX() const
TYPE getMinY() const
TYPE getHeight() const
TYPE getX() const
TYPE getY() const
double toRadians(D x)
tools::Long FRound(double fVal)
B2DHomMatrix createRotateAroundPoint(double fPointX, double fPointY, double fRadiant)
constexpr double rad2deg(double v)
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
static void GradToVec(GradTransGradient const &rG, GradTransVector &rV, const SdrObject *pObj)
Definition: gradtrns.cxx:30
static void VecToGrad(GradTransVector const &rV, GradTransGradient &rG, GradTransGradient const &rGOld, const SdrObject *pObj, bool bMoveSingle, bool bMoveFirst)
Definition: gradtrns.cxx:182