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 #include <vcl/outdev.hxx>
29 
30 
32 {
33  // handle start color
34  rV.aCol1 = rG.aGradient.GetStartColor();
35  if(100 != rG.aGradient.GetStartIntens())
36  {
37  const double fFact(static_cast<double>(rG.aGradient.GetStartIntens()) / 100.0);
38  rV.aCol1 = Color(rV.aCol1.getBColor() * fFact);
39  }
40 
41  // handle end color
42  rV.aCol2 = rG.aGradient.GetEndColor();
43  if(100 != rG.aGradient.GetEndIntens())
44  {
45  const double fFact(static_cast<double>(rG.aGradient.GetEndIntens()) / 100.0);
46  rV.aCol2 = Color(rV.aCol2.getBColor() * fFact);
47  }
48 
49  // calc the basic positions
50  const tools::Rectangle aObjectSnapRectangle(pObj->GetSnapRect());
51  const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aObjectSnapRectangle);
52  const basegfx::B2DPoint aCenter(aRange.getCenter());
53  basegfx::B2DPoint aStartPos, aEndPos;
54 
55  switch(rG.aGradient.GetGradientStyle())
56  {
57  case css::awt::GradientStyle_LINEAR :
58  {
59  aStartPos = basegfx::B2DPoint(aCenter.getX(), aRange.getMinY());
60  aEndPos = basegfx::B2DPoint(aCenter.getX(), aRange.getMaximum().getY());
61 
62  if(rG.aGradient.GetBorder())
63  {
64  basegfx::B2DVector aFullVec(aStartPos - aEndPos);
65  const double fLen = (aFullVec.getLength() * (100.0 - static_cast<double>(rG.aGradient.GetBorder()))) / 100.0;
66  aFullVec.normalize();
67  aStartPos = aEndPos + (aFullVec * fLen);
68  }
69 
70  if(rG.aGradient.GetAngle())
71  {
72  const double fAngle = basegfx::deg2rad(rG.aGradient.GetAngle() / 10.0);
73  const basegfx::B2DHomMatrix aTransformation(basegfx::utils::createRotateAroundPoint(aCenter, -fAngle));
74 
75  aStartPos *= aTransformation;
76  aEndPos *= aTransformation;
77  }
78  break;
79  }
80  case css::awt::GradientStyle_AXIAL :
81  {
82  aStartPos = aCenter;
83  aEndPos = basegfx::B2DPoint(aCenter.getX(), aRange.getMaximum().getY());
84 
85  if(rG.aGradient.GetBorder())
86  {
87  basegfx::B2DVector aFullVec(aEndPos - aStartPos);
88  const double fLen = (aFullVec.getLength() * (100.0 - static_cast<double>(rG.aGradient.GetBorder()))) / 100.0;
89  aFullVec.normalize();
90  aEndPos = aStartPos + (aFullVec * fLen);
91  }
92 
93  if(rG.aGradient.GetAngle())
94  {
95  const double fAngle = basegfx::deg2rad(rG.aGradient.GetAngle() / 10.0);
96  const basegfx::B2DHomMatrix aTransformation(basegfx::utils::createRotateAroundPoint(aCenter, -fAngle));
97 
98  aStartPos *= aTransformation;
99  aEndPos *= aTransformation;
100  }
101  break;
102  }
103  case css::awt::GradientStyle_RADIAL :
104  case css::awt::GradientStyle_SQUARE :
105  {
106  aStartPos = basegfx::B2DPoint(aRange.getMinX(), aRange.getMaximum().getY());
107  aEndPos = basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY());
108 
109  if(rG.aGradient.GetBorder())
110  {
111  basegfx::B2DVector aFullVec(aStartPos - aEndPos);
112  const double fLen = (aFullVec.getLength() * (100.0 - static_cast<double>(rG.aGradient.GetBorder()))) / 100.0;
113  aFullVec.normalize();
114  aStartPos = aEndPos + (aFullVec * fLen);
115  }
116 
117  if(rG.aGradient.GetAngle())
118  {
119  const double fAngle = basegfx::deg2rad(rG.aGradient.GetAngle() / 10.0);
120  const basegfx::B2DHomMatrix aTransformation(basegfx::utils::createRotateAroundPoint(aEndPos, -fAngle));
121 
122  aStartPos *= aTransformation;
123  aEndPos *= aTransformation;
124  }
125 
126  if(rG.aGradient.GetXOffset() || rG.aGradient.GetYOffset())
127  {
128  basegfx::B2DPoint aOffset(
129  (aRange.getWidth() * rG.aGradient.GetXOffset()) / 100.0,
130  (aRange.getHeight() * rG.aGradient.GetYOffset()) / 100.0);
131 
132  aStartPos += aOffset;
133  aEndPos += aOffset;
134  }
135 
136  break;
137  }
138  case css::awt::GradientStyle_ELLIPTICAL :
139  case css::awt::GradientStyle_RECT :
140  {
141  aStartPos = basegfx::B2DPoint(aRange.getMinX(), aCenter.getY());
142  aEndPos = basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY());
143 
144  if(rG.aGradient.GetBorder())
145  {
146  basegfx::B2DVector aFullVec(aStartPos - aEndPos);
147  const double fLen = (aFullVec.getLength() * (100.0 - static_cast<double>(rG.aGradient.GetBorder()))) / 100.0;
148  aFullVec.normalize();
149  aStartPos = aEndPos + (aFullVec * fLen);
150  }
151 
152  if(rG.aGradient.GetAngle())
153  {
154  const double fAngle = basegfx::deg2rad(rG.aGradient.GetAngle() / 10.0);
155  const basegfx::B2DHomMatrix aTransformation(basegfx::utils::createRotateAroundPoint(aEndPos, -fAngle));
156 
157  aStartPos *= aTransformation;
158  aEndPos *= aTransformation;
159  }
160 
161  if(rG.aGradient.GetXOffset() || rG.aGradient.GetYOffset())
162  {
163  basegfx::B2DPoint aOffset(
164  (aRange.getWidth() * rG.aGradient.GetXOffset()) / 100.0,
165  (aRange.getHeight() * rG.aGradient.GetYOffset()) / 100.0);
166 
167  aStartPos += aOffset;
168  aEndPos += aOffset;
169  }
170 
171  break;
172  }
173  default:
174  break;
175  }
176 
177  // set values for vector positions now
178  rV.maPositionA = aStartPos;
179  rV.maPositionB = aEndPos;
180 }
181 
182 
184  bool bMoveSingle, bool bMoveFirst)
185 {
186  // fill old gradient to new gradient to have a base
187  rG = rGOld;
188 
189  // handle color changes
190  if(rV.aCol1 != rGOld.aGradient.GetStartColor())
191  {
193  rG.aGradient.SetStartIntens(100);
194  }
195  if(rV.aCol2 != rGOld.aGradient.GetEndColor())
196  {
197  rG.aGradient.SetEndColor(rV.aCol2);
198  rG.aGradient.SetEndIntens(100);
199  }
200 
201  // calc the basic positions
202  const tools::Rectangle aObjectSnapRectangle(pObj->GetSnapRect());
203  const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aObjectSnapRectangle);
204  const basegfx::B2DPoint aCenter(aRange.getCenter());
205  basegfx::B2DPoint aStartPos(rV.maPositionA);
206  basegfx::B2DPoint aEndPos(rV.maPositionB);
207 
208  switch(rG.aGradient.GetGradientStyle())
209  {
210  case css::awt::GradientStyle_LINEAR :
211  {
212  if(!bMoveSingle || !bMoveFirst)
213  {
214  basegfx::B2DVector aFullVec(aEndPos - aStartPos);
215 
216  if(bMoveSingle)
217  {
218  aFullVec = aEndPos - aCenter;
219  }
220 
221  aFullVec.normalize();
222 
223  double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec.getY(), aFullVec.getX())));
224  fNewFullAngle *= -10.0;
225  fNewFullAngle += 900.0;
226 
227  // clip
228  while(fNewFullAngle < 0.0)
229  {
230  fNewFullAngle += 3600.0;
231  }
232 
233  while(fNewFullAngle >= 3600.0)
234  {
235  fNewFullAngle -= 3600.0;
236  }
237 
238  // to int and set
239  sal_Int32 nNewAngle = FRound(fNewFullAngle);
240 
241  if(nNewAngle != rGOld.aGradient.GetAngle())
242  {
243  rG.aGradient.SetAngle(nNewAngle);
244  }
245  }
246 
247  if(!bMoveSingle || bMoveFirst)
248  {
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));
257 
258  // clip
259  if(nNewBorder < 0)
260  {
261  nNewBorder = 0;
262  }
263 
264  if(nNewBorder > 100)
265  {
266  nNewBorder = 100;
267  }
268 
269  // set
270  if(nNewBorder != rG.aGradient.GetBorder())
271  {
272  rG.aGradient.SetBorder(static_cast<sal_uInt16>(nNewBorder));
273  }
274  }
275 
276  break;
277  }
278  case css::awt::GradientStyle_AXIAL :
279  {
280  if(!bMoveSingle || !bMoveFirst)
281  {
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);
288 
289  // clip
290  if(nNewBorder < 0)
291  {
292  nNewBorder = 0;
293  }
294 
295  if(nNewBorder > 100)
296  {
297  nNewBorder = 100;
298  }
299 
300  // set
301  if(nNewBorder != rG.aGradient.GetBorder())
302  {
303  rG.aGradient.SetBorder(static_cast<sal_uInt16>(nNewBorder));
304  }
305 
306  aFullVec.normalize();
307  double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec.getY(), aFullVec.getX())));
308  fNewFullAngle *= -10.0;
309  fNewFullAngle += 900.0;
310 
311  // clip
312  while(fNewFullAngle < 0.0)
313  {
314  fNewFullAngle += 3600.0;
315  }
316 
317  while(fNewFullAngle >= 3600.0)
318  {
319  fNewFullAngle -= 3600.0;
320  }
321 
322  // to int and set
323  const sal_Int32 nNewAngle(FRound(fNewFullAngle));
324 
325  if(nNewAngle != rGOld.aGradient.GetAngle())
326  {
327  rG.aGradient.SetAngle(nNewAngle);
328  }
329  }
330 
331  break;
332  }
333  case css::awt::GradientStyle_RADIAL :
334  case css::awt::GradientStyle_SQUARE :
335  {
336  if(!bMoveSingle || !bMoveFirst)
337  {
338  const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
339  const basegfx::B2DPoint aOffset(aEndPos - aTopLeft);
340  sal_Int32 nNewXOffset(FRound((aOffset.getX() * 100.0) / aRange.getWidth()));
341  sal_Int32 nNewYOffset(FRound((aOffset.getY() * 100.0) / aRange.getHeight()));
342 
343  // clip
344  if(nNewXOffset < 0)
345  {
346  nNewXOffset = 0;
347  }
348 
349  if(nNewXOffset > 100)
350  {
351  nNewXOffset = 100;
352  }
353 
354  if(nNewYOffset < 0)
355  {
356  nNewYOffset = 0;
357  }
358 
359  if(nNewYOffset > 100)
360  {
361  nNewYOffset = 100;
362  }
363 
364  rG.aGradient.SetXOffset(static_cast<sal_uInt16>(nNewXOffset));
365  rG.aGradient.SetYOffset(static_cast<sal_uInt16>(nNewYOffset));
366 
367  aStartPos -= aOffset;
368  aEndPos -= aOffset;
369  }
370 
371  if(!bMoveSingle || bMoveFirst)
372  {
373  basegfx::B2DVector aFullVec(aStartPos - aEndPos);
374  const basegfx::B2DPoint aBottomLeft(aRange.getMinX(), aRange.getMaximum().getY());
375  const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
376  const basegfx::B2DVector aOldVec(aBottomLeft - aTopLeft);
377  const double fFullLen(aFullVec.getLength());
378  const double fOldLen(aOldVec.getLength());
379  const double fNewBorder((fFullLen * 100.0) / fOldLen);
380  sal_Int32 nNewBorder(100 - FRound(fNewBorder));
381 
382  // clip
383  if(nNewBorder < 0)
384  {
385  nNewBorder = 0;
386  }
387 
388  if(nNewBorder > 100)
389  {
390  nNewBorder = 100;
391  }
392 
393  // set
394  if(nNewBorder != rG.aGradient.GetBorder())
395  {
396  rG.aGradient.SetBorder(static_cast<sal_uInt16>(nNewBorder));
397  }
398 
399  // angle is not definitely necessary for these modes, but it makes
400  // controlling more fun for the user
401  aFullVec.normalize();
402  double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec.getY(), aFullVec.getX())));
403  fNewFullAngle *= -10.0;
404  fNewFullAngle += 900.0;
405 
406  // clip
407  while(fNewFullAngle < 0.0)
408  {
409  fNewFullAngle += 3600.0;
410  }
411 
412  while(fNewFullAngle >= 3600.0)
413  {
414  fNewFullAngle -= 3600.0;
415  }
416 
417  // to int and set
418  const sal_Int32 nNewAngle(FRound(fNewFullAngle));
419 
420  if(nNewAngle != rGOld.aGradient.GetAngle())
421  {
422  rG.aGradient.SetAngle(nNewAngle);
423  }
424  }
425 
426  break;
427  }
428  case css::awt::GradientStyle_ELLIPTICAL :
429  case css::awt::GradientStyle_RECT :
430  {
431  if(!bMoveSingle || !bMoveFirst)
432  {
433  const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
434  const basegfx::B2DPoint aOffset(aEndPos - aTopLeft);
435  sal_Int32 nNewXOffset(FRound((aOffset.getX() * 100.0) / aRange.getWidth()));
436  sal_Int32 nNewYOffset(FRound((aOffset.getY() * 100.0) / aRange.getHeight()));
437 
438  // clip
439  if(nNewXOffset < 0)
440  {
441  nNewXOffset = 0;
442  }
443 
444  if(nNewXOffset > 100)
445  {
446  nNewXOffset = 100;
447  }
448 
449  if(nNewYOffset < 0)
450  {
451  nNewYOffset = 0;
452  }
453 
454  if(nNewYOffset > 100)
455  {
456  nNewYOffset = 100;
457  }
458 
459  rG.aGradient.SetXOffset(static_cast<sal_uInt16>(nNewXOffset));
460  rG.aGradient.SetYOffset(static_cast<sal_uInt16>(nNewYOffset));
461 
462  aStartPos -= aOffset;
463  aEndPos -= aOffset;
464  }
465 
466  if(!bMoveSingle || bMoveFirst)
467  {
468  basegfx::B2DVector aFullVec(aStartPos - aEndPos);
469  const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
470  const basegfx::B2DPoint aCenterLeft(aRange.getMinX(), aCenter.getY());
471  const basegfx::B2DVector aOldVec(aCenterLeft - aTopLeft);
472  const double fFullLen(aFullVec.getLength());
473  const double fOldLen(aOldVec.getLength());
474  const double fNewBorder((fFullLen * 100.0) / fOldLen);
475  sal_Int32 nNewBorder(100 - FRound(fNewBorder));
476 
477  // clip
478  if(nNewBorder < 0)
479  {
480  nNewBorder = 0;
481  }
482 
483  if(nNewBorder > 100)
484  {
485  nNewBorder = 100;
486  }
487 
488  // set
489  if(nNewBorder != rG.aGradient.GetBorder())
490  {
491  rG.aGradient.SetBorder(static_cast<sal_uInt16>(nNewBorder));
492  }
493 
494  // angle is not definitely necessary for these modes, but it makes
495  // controlling more fun for the user
496  aFullVec.normalize();
497  double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec.getY(), aFullVec.getX())));
498  fNewFullAngle *= -10.0;
499  fNewFullAngle += 900.0;
500 
501  // clip
502  while(fNewFullAngle < 0.0)
503  {
504  fNewFullAngle += 3600.0;
505  }
506 
507  while(fNewFullAngle >= 3600.0)
508  {
509  fNewFullAngle -= 3600.0;
510  }
511 
512  // to int and set
513  const sal_Int32 nNewAngle(FRound(fNewFullAngle));
514 
515  if(nNewAngle != rGOld.aGradient.GetAngle())
516  {
517  rG.aGradient.SetAngle(nNewAngle);
518  }
519  }
520 
521  break;
522  }
523  default:
524  break;
525  }
526 }
527 
528 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XGradient aGradient
Definition: gradtrns.hxx:40
long FRound(double fVal)
basegfx::B2DPoint maPositionB
Definition: gradtrns.hxx:32
void SetBorder(sal_uInt16 nNewBorder)
Definition: xgrad.hxx:59
double getX() const
static void VecToGrad(GradTransVector const &rV, GradTransGradient &rG, GradTransGradient const &rGOld, const SdrObject *pObj, bool bMoveSingle, bool bMoveFirst)
Definition: gradtrns.cxx:183
void SetEndColor(const Color &rColor)
Definition: xgrad.hxx:57
double getY() const
constexpr double rad2deg(double v)
sal_uInt16 GetStartIntens() const
Definition: xgrad.hxx:73
virtual const tools::Rectangle & GetSnapRect() const
Definition: svdobj.cxx:1624
const Color & GetStartColor() const
Definition: xgrad.hxx:67
sal_uInt16 GetYOffset() const
Definition: xgrad.hxx:72
B2DVector & normalize()
sal_uInt16 GetXOffset() const
Definition: xgrad.hxx:71
void SetAngle(long nNewAngle)
Definition: xgrad.hxx:58
void SetEndIntens(sal_uInt16 nNewIntens)
Definition: xgrad.hxx:63
sal_uInt16 GetBorder() const
Definition: xgrad.hxx:70
void SetStartColor(const Color &rColor)
Definition: xgrad.hxx:56
basegfx::B2DPoint maPositionA
Definition: gradtrns.hxx:31
void SetYOffset(sal_uInt16 nNewOffset)
Definition: xgrad.hxx:61
long GetAngle() const
Definition: xgrad.hxx:69
constexpr double deg2rad(double v)
Abstract DrawObject.
Definition: svdobj.hxx:312
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
void SetStartIntens(sal_uInt16 nNewIntens)
Definition: xgrad.hxx:62
css::awt::GradientStyle GetGradientStyle() const
Definition: xgrad.hxx:66
void SetXOffset(sal_uInt16 nNewOffset)
Definition: xgrad.hxx:60
B2DHomMatrix createRotateAroundPoint(double fPointX, double fPointY, double fRadiant)
basegfx::BColor getBColor() const
double getLength() const
static void GradToVec(GradTransGradient const &rG, GradTransVector &rV, const SdrObject *pObj)
Definition: gradtrns.cxx:31
sal_uInt16 GetEndIntens() const
Definition: xgrad.hxx:74
const Color & GetEndColor() const
Definition: xgrad.hxx:68