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 "RelativePositionHelper.hxx"
22 #include <rtl/math.hxx>
24 using namespace ::com::sun::star
;
29 chart2::RelativePosition
RelativePositionHelper::getReanchoredPosition(
30 const chart2::RelativePosition
& rPosition
,
31 const chart2::RelativeSize
& rObjectSize
,
32 drawing::Alignment aNewAnchor
)
34 chart2::RelativePosition
aResult( rPosition
);
35 if( rPosition
.Anchor
!= aNewAnchor
)
37 sal_Int32 nShiftHalfWidths
= 0;
38 sal_Int32 nShiftHalfHeights
= 0;
40 // normalize to top-left
41 switch( rPosition
.Anchor
)
43 case drawing::Alignment_TOP_LEFT
:
45 case drawing::Alignment_LEFT
:
46 nShiftHalfHeights
-= 1;
48 case drawing::Alignment_BOTTOM_LEFT
:
49 nShiftHalfHeights
-= 2;
51 case drawing::Alignment_TOP
:
52 nShiftHalfWidths
-= 1;
54 case drawing::Alignment_CENTER
:
55 nShiftHalfWidths
-= 1;
56 nShiftHalfHeights
-= 1;
58 case drawing::Alignment_BOTTOM
:
59 nShiftHalfWidths
-= 1;
60 nShiftHalfHeights
-= 2;
62 case drawing::Alignment_TOP_RIGHT
:
63 nShiftHalfWidths
-= 2;
65 case drawing::Alignment_RIGHT
:
66 nShiftHalfWidths
-= 2;
67 nShiftHalfHeights
-= 1;
69 case drawing::Alignment_BOTTOM_RIGHT
:
70 nShiftHalfWidths
-= 2;
71 nShiftHalfHeights
-= 2;
73 case drawing::Alignment_MAKE_FIXED_SIZE
:
80 case drawing::Alignment_TOP_LEFT
:
82 case drawing::Alignment_LEFT
:
83 nShiftHalfHeights
+= 1;
85 case drawing::Alignment_BOTTOM_LEFT
:
86 nShiftHalfHeights
+= 2;
88 case drawing::Alignment_TOP
:
89 nShiftHalfWidths
+= 1;
91 case drawing::Alignment_CENTER
:
92 nShiftHalfWidths
+= 1;
93 nShiftHalfHeights
+= 1;
95 case drawing::Alignment_BOTTOM
:
96 nShiftHalfWidths
+= 1;
97 nShiftHalfHeights
+= 2;
99 case drawing::Alignment_TOP_RIGHT
:
100 nShiftHalfWidths
+= 2;
102 case drawing::Alignment_RIGHT
:
103 nShiftHalfWidths
+= 2;
104 nShiftHalfHeights
+= 1;
106 case drawing::Alignment_BOTTOM_RIGHT
:
107 nShiftHalfWidths
+= 2;
108 nShiftHalfHeights
+= 2;
110 case drawing::Alignment_MAKE_FIXED_SIZE
:
114 if( nShiftHalfWidths
!= 0 )
115 aResult
.Primary
+= (rObjectSize
.Primary
/ 2.0) * nShiftHalfWidths
;
116 if( nShiftHalfHeights
!= 0 )
117 aResult
.Secondary
+= (rObjectSize
.Secondary
/ 2.0) * nShiftHalfHeights
;
124 awt::Point
RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
126 , awt::Size aObjectSize
127 , drawing::Alignment aAnchor
)
129 awt::Point
aResult( aPoint
);
131 double fXDelta
= 0.0;
132 double fYDelta
= 0.0;
137 case drawing::Alignment_TOP
:
138 case drawing::Alignment_CENTER
:
139 case drawing::Alignment_BOTTOM
:
140 fXDelta
-= static_cast< double >( aObjectSize
.Width
) / 2.0;
142 case drawing::Alignment_TOP_RIGHT
:
143 case drawing::Alignment_RIGHT
:
144 case drawing::Alignment_BOTTOM_RIGHT
:
145 fXDelta
-= aObjectSize
.Width
;
147 case drawing::Alignment_TOP_LEFT
:
148 case drawing::Alignment_LEFT
:
149 case drawing::Alignment_BOTTOM_LEFT
:
158 case drawing::Alignment_LEFT
:
159 case drawing::Alignment_CENTER
:
160 case drawing::Alignment_RIGHT
:
161 fYDelta
-= static_cast< double >( aObjectSize
.Height
) / 2.0;
163 case drawing::Alignment_BOTTOM_LEFT
:
164 case drawing::Alignment_BOTTOM
:
165 case drawing::Alignment_BOTTOM_RIGHT
:
166 fYDelta
-= aObjectSize
.Height
;
168 case drawing::Alignment_TOP_LEFT
:
169 case drawing::Alignment_TOP
:
170 case drawing::Alignment_TOP_RIGHT
:
176 aResult
.X
+= static_cast< sal_Int32
>( ::rtl::math::round( fXDelta
));
177 aResult
.Y
+= static_cast< sal_Int32
>( ::rtl::math::round( fYDelta
));
182 awt::Point
RelativePositionHelper::getCenterOfAnchoredObject(
184 , awt::Size aUnrotatedObjectSize
185 , drawing::Alignment aAnchor
188 awt::Point
aResult( aPoint
);
190 double fXDelta
= 0.0;
191 double fYDelta
= 0.0;
196 case drawing::Alignment_TOP
:
197 case drawing::Alignment_CENTER
:
198 case drawing::Alignment_BOTTOM
:
201 case drawing::Alignment_TOP_RIGHT
:
202 case drawing::Alignment_RIGHT
:
203 case drawing::Alignment_BOTTOM_RIGHT
:
204 fXDelta
-= aUnrotatedObjectSize
.Width
/2;
206 case drawing::Alignment_TOP_LEFT
:
207 case drawing::Alignment_LEFT
:
208 case drawing::Alignment_BOTTOM_LEFT
:
210 fXDelta
+= aUnrotatedObjectSize
.Width
/2;
217 case drawing::Alignment_LEFT
:
218 case drawing::Alignment_CENTER
:
219 case drawing::Alignment_RIGHT
:
222 case drawing::Alignment_BOTTOM_LEFT
:
223 case drawing::Alignment_BOTTOM
:
224 case drawing::Alignment_BOTTOM_RIGHT
:
225 fYDelta
-= aUnrotatedObjectSize
.Height
/2;
227 case drawing::Alignment_TOP_LEFT
:
228 case drawing::Alignment_TOP
:
229 case drawing::Alignment_TOP_RIGHT
:
230 fYDelta
+= aUnrotatedObjectSize
.Height
/2;
236 //take rotation into account:
237 aResult
.X
+= static_cast< sal_Int32
>(
238 ::rtl::math::round( fXDelta
* rtl::math::cos( fAnglePi
) + fYDelta
* rtl::math::sin( fAnglePi
) ) );
239 aResult
.Y
+= static_cast< sal_Int32
>(
240 ::rtl::math::round( - fXDelta
* rtl::math::sin( fAnglePi
) + fYDelta
* rtl::math::cos( fAnglePi
) ) );
245 bool RelativePositionHelper::centerGrow(
246 chart2::RelativePosition
& rInOutPosition
,
247 chart2::RelativeSize
& rInOutSize
,
248 double fAmountX
, double fAmountY
,
249 bool bCheck
/* = true */ )
251 chart2::RelativePosition
aPos( rInOutPosition
);
252 chart2::RelativeSize
aSize( rInOutSize
);
253 const double fPosCheckThreshold
= 0.02;
254 const double fSizeCheckThreshold
= 0.1;
256 // grow/shrink, back to relaative
257 aSize
.Primary
+= fAmountX
;
258 aSize
.Secondary
+= fAmountY
;
260 double fShiftAmountX
= fAmountX
/ 2.0;
261 double fShiftAmountY
= fAmountY
/ 2.0;
264 switch( rInOutPosition
.Anchor
)
266 case drawing::Alignment_TOP_LEFT
:
267 case drawing::Alignment_LEFT
:
268 case drawing::Alignment_BOTTOM_LEFT
:
269 aPos
.Primary
-= fShiftAmountX
;
271 case drawing::Alignment_TOP
:
272 case drawing::Alignment_CENTER
:
273 case drawing::Alignment_BOTTOM
:
276 case drawing::Alignment_TOP_RIGHT
:
277 case drawing::Alignment_RIGHT
:
278 case drawing::Alignment_BOTTOM_RIGHT
:
279 aPos
.Primary
+= fShiftAmountX
;
281 case drawing::Alignment_MAKE_FIXED_SIZE
:
286 switch( rInOutPosition
.Anchor
)
288 case drawing::Alignment_TOP
:
289 case drawing::Alignment_TOP_LEFT
:
290 case drawing::Alignment_TOP_RIGHT
:
291 aPos
.Secondary
-= fShiftAmountY
;
293 case drawing::Alignment_CENTER
:
294 case drawing::Alignment_LEFT
:
295 case drawing::Alignment_RIGHT
:
298 case drawing::Alignment_BOTTOM
:
299 case drawing::Alignment_BOTTOM_LEFT
:
300 case drawing::Alignment_BOTTOM_RIGHT
:
301 aPos
.Secondary
+= fShiftAmountY
;
303 case drawing::Alignment_MAKE_FIXED_SIZE
:
307 // anchor must not be changed
308 OSL_ASSERT( rInOutPosition
.Anchor
== aPos
.Anchor
);
310 if( rInOutPosition
.Primary
== aPos
.Primary
&&
311 rInOutPosition
.Secondary
== aPos
.Secondary
&&
312 rInOutSize
.Primary
== aSize
.Primary
&&
313 rInOutSize
.Secondary
== aSize
.Secondary
)
319 // Note: this somewhat complicated check allows the output being
320 // out-of-bounds if the input was also out-of-bounds, and the change is
321 // for "advantage". E.g., you have a chart that laps out on the left
322 // side. If you shrink it, this should be possible, also if it still
323 // laps out on the left side afterwards. But you shouldn't be able to
326 chart2::RelativePosition
aUpperLeft(
327 RelativePositionHelper::getReanchoredPosition( aPos
, aSize
, drawing::Alignment_TOP_LEFT
));
328 chart2::RelativePosition
aLowerRight(
329 RelativePositionHelper::getReanchoredPosition( aPos
, aSize
, drawing::Alignment_BOTTOM_RIGHT
));
331 // Do not grow, if this leads to corners being off-screen
332 if( fAmountX
> 0.0 &&
333 ( (aUpperLeft
.Primary
< fPosCheckThreshold
) ||
334 (aLowerRight
.Primary
> (1.0 - fPosCheckThreshold
)) ))
336 if( fAmountY
> 0.0 &&
337 ( (aUpperLeft
.Secondary
< fPosCheckThreshold
) ||
338 (aLowerRight
.Secondary
> (1.0 - fPosCheckThreshold
)) ))
341 // Do not shrink, if this leads to a size too small
342 if( fAmountX
< 0.0 &&
343 ( aSize
.Primary
< fSizeCheckThreshold
))
345 if( fAmountY
< 0.0 &&
346 ( aSize
.Secondary
< fSizeCheckThreshold
))
350 rInOutPosition
= aPos
;
355 bool RelativePositionHelper::moveObject(
356 chart2::RelativePosition
& rInOutPosition
,
357 const chart2::RelativeSize
& rObjectSize
,
358 double fAmountX
, double fAmountY
,
359 bool bCheck
/* = true */ )
361 chart2::RelativePosition
aPos( rInOutPosition
);
362 aPos
.Primary
+= fAmountX
;
363 aPos
.Secondary
+= fAmountY
;
364 const double fPosCheckThreshold
= 0.02;
368 chart2::RelativePosition
aUpperLeft(
369 RelativePositionHelper::getReanchoredPosition( aPos
, rObjectSize
, drawing::Alignment_TOP_LEFT
));
370 chart2::RelativePosition
aLowerRight( aUpperLeft
);
371 aLowerRight
.Primary
+= rObjectSize
.Primary
;
372 aLowerRight
.Secondary
+= rObjectSize
.Secondary
;
374 const double fFarEdgeThreshold
= 1.0 - fPosCheckThreshold
;
375 if( ( fAmountX
> 0.0 && (aLowerRight
.Primary
> fFarEdgeThreshold
)) ||
376 ( fAmountX
< 0.0 && (aUpperLeft
.Primary
< fPosCheckThreshold
)) ||
377 ( fAmountY
> 0.0 && (aLowerRight
.Secondary
> fFarEdgeThreshold
)) ||
378 ( fAmountY
< 0.0 && (aUpperLeft
.Secondary
< fPosCheckThreshold
)) )
382 rInOutPosition
= aPos
;
388 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */