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 .
20 #include "RelativePositionHelper.hxx"
21 #include <rtl/math.hxx>
22 #include <osl/diagnose.h>
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
;
123 awt::Point
RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
125 , awt::Size aObjectSize
126 , drawing::Alignment aAnchor
)
128 awt::Point
aResult( aPoint
);
130 double fXDelta
= 0.0;
131 double fYDelta
= 0.0;
136 case drawing::Alignment_TOP
:
137 case drawing::Alignment_CENTER
:
138 case drawing::Alignment_BOTTOM
:
139 fXDelta
-= static_cast< double >( aObjectSize
.Width
) / 2.0;
141 case drawing::Alignment_TOP_RIGHT
:
142 case drawing::Alignment_RIGHT
:
143 case drawing::Alignment_BOTTOM_RIGHT
:
144 fXDelta
-= aObjectSize
.Width
;
146 case drawing::Alignment_TOP_LEFT
:
147 case drawing::Alignment_LEFT
:
148 case drawing::Alignment_BOTTOM_LEFT
:
157 case drawing::Alignment_LEFT
:
158 case drawing::Alignment_CENTER
:
159 case drawing::Alignment_RIGHT
:
160 fYDelta
-= static_cast< double >( aObjectSize
.Height
) / 2.0;
162 case drawing::Alignment_BOTTOM_LEFT
:
163 case drawing::Alignment_BOTTOM
:
164 case drawing::Alignment_BOTTOM_RIGHT
:
165 fYDelta
-= aObjectSize
.Height
;
167 case drawing::Alignment_TOP_LEFT
:
168 case drawing::Alignment_TOP
:
169 case drawing::Alignment_TOP_RIGHT
:
175 aResult
.X
+= static_cast< sal_Int32
>( ::rtl::math::round( fXDelta
));
176 aResult
.Y
+= static_cast< sal_Int32
>( ::rtl::math::round( fYDelta
));
181 awt::Point
RelativePositionHelper::getCenterOfAnchoredObject(
183 , awt::Size aUnrotatedObjectSize
184 , drawing::Alignment aAnchor
187 awt::Point
aResult( aPoint
);
189 double fXDelta
= 0.0;
190 double fYDelta
= 0.0;
195 case drawing::Alignment_TOP
:
196 case drawing::Alignment_CENTER
:
197 case drawing::Alignment_BOTTOM
:
200 case drawing::Alignment_TOP_RIGHT
:
201 case drawing::Alignment_RIGHT
:
202 case drawing::Alignment_BOTTOM_RIGHT
:
203 fXDelta
-= aUnrotatedObjectSize
.Width
/2;
205 case drawing::Alignment_TOP_LEFT
:
206 case drawing::Alignment_LEFT
:
207 case drawing::Alignment_BOTTOM_LEFT
:
209 fXDelta
+= aUnrotatedObjectSize
.Width
/2;
216 case drawing::Alignment_LEFT
:
217 case drawing::Alignment_CENTER
:
218 case drawing::Alignment_RIGHT
:
221 case drawing::Alignment_BOTTOM_LEFT
:
222 case drawing::Alignment_BOTTOM
:
223 case drawing::Alignment_BOTTOM_RIGHT
:
224 fYDelta
-= aUnrotatedObjectSize
.Height
/2;
226 case drawing::Alignment_TOP_LEFT
:
227 case drawing::Alignment_TOP
:
228 case drawing::Alignment_TOP_RIGHT
:
229 fYDelta
+= aUnrotatedObjectSize
.Height
/2;
235 //take rotation into account:
236 aResult
.X
+= static_cast< sal_Int32
>(
237 ::rtl::math::round( fXDelta
* rtl::math::cos( fAnglePi
) + fYDelta
* rtl::math::sin( fAnglePi
) ) );
238 aResult
.Y
+= static_cast< sal_Int32
>(
239 ::rtl::math::round( - fXDelta
* rtl::math::sin( fAnglePi
) + fYDelta
* rtl::math::cos( fAnglePi
) ) );
244 bool RelativePositionHelper::centerGrow(
245 chart2::RelativePosition
& rInOutPosition
,
246 chart2::RelativeSize
& rInOutSize
,
247 double fAmountX
, double fAmountY
,
248 bool bCheck
/* = true */ )
250 chart2::RelativePosition
aPos( rInOutPosition
);
251 chart2::RelativeSize
aSize( rInOutSize
);
252 const double fPosCheckThreshold
= 0.02;
253 const double fSizeCheckThreshold
= 0.1;
255 // grow/shrink, back to relaative
256 aSize
.Primary
+= fAmountX
;
257 aSize
.Secondary
+= fAmountY
;
259 double fShiftAmountX
= fAmountX
/ 2.0;
260 double fShiftAmountY
= fAmountY
/ 2.0;
263 switch( rInOutPosition
.Anchor
)
265 case drawing::Alignment_TOP_LEFT
:
266 case drawing::Alignment_LEFT
:
267 case drawing::Alignment_BOTTOM_LEFT
:
268 aPos
.Primary
-= fShiftAmountX
;
270 case drawing::Alignment_TOP
:
271 case drawing::Alignment_CENTER
:
272 case drawing::Alignment_BOTTOM
:
275 case drawing::Alignment_TOP_RIGHT
:
276 case drawing::Alignment_RIGHT
:
277 case drawing::Alignment_BOTTOM_RIGHT
:
278 aPos
.Primary
+= fShiftAmountX
;
280 case drawing::Alignment_MAKE_FIXED_SIZE
:
285 switch( rInOutPosition
.Anchor
)
287 case drawing::Alignment_TOP
:
288 case drawing::Alignment_TOP_LEFT
:
289 case drawing::Alignment_TOP_RIGHT
:
290 aPos
.Secondary
-= fShiftAmountY
;
292 case drawing::Alignment_CENTER
:
293 case drawing::Alignment_LEFT
:
294 case drawing::Alignment_RIGHT
:
297 case drawing::Alignment_BOTTOM
:
298 case drawing::Alignment_BOTTOM_LEFT
:
299 case drawing::Alignment_BOTTOM_RIGHT
:
300 aPos
.Secondary
+= fShiftAmountY
;
302 case drawing::Alignment_MAKE_FIXED_SIZE
:
306 // anchor must not be changed
307 OSL_ASSERT( rInOutPosition
.Anchor
== aPos
.Anchor
);
309 if( rInOutPosition
.Primary
== aPos
.Primary
&&
310 rInOutPosition
.Secondary
== aPos
.Secondary
&&
311 rInOutSize
.Primary
== aSize
.Primary
&&
312 rInOutSize
.Secondary
== aSize
.Secondary
)
318 // Note: this somewhat complicated check allows the output being
319 // out-of-bounds if the input was also out-of-bounds, and the change is
320 // for "advantage". E.g., you have a chart that laps out on the left
321 // side. If you shrink it, this should be possible, also if it still
322 // laps out on the left side afterwards. But you shouldn't be able to
325 chart2::RelativePosition
aUpperLeft(
326 RelativePositionHelper::getReanchoredPosition( aPos
, aSize
, drawing::Alignment_TOP_LEFT
));
327 chart2::RelativePosition
aLowerRight(
328 RelativePositionHelper::getReanchoredPosition( aPos
, aSize
, drawing::Alignment_BOTTOM_RIGHT
));
330 // Do not grow, if this leads to corners being off-screen
331 if( fAmountX
> 0.0 &&
332 ( (aUpperLeft
.Primary
< fPosCheckThreshold
) ||
333 (aLowerRight
.Primary
> (1.0 - fPosCheckThreshold
)) ))
335 if( fAmountY
> 0.0 &&
336 ( (aUpperLeft
.Secondary
< fPosCheckThreshold
) ||
337 (aLowerRight
.Secondary
> (1.0 - fPosCheckThreshold
)) ))
340 // Do not shrink, if this leads to a size too small
341 if( fAmountX
< 0.0 &&
342 ( aSize
.Primary
< fSizeCheckThreshold
))
344 if( fAmountY
< 0.0 &&
345 ( aSize
.Secondary
< fSizeCheckThreshold
))
349 rInOutPosition
= aPos
;
354 bool RelativePositionHelper::moveObject(
355 chart2::RelativePosition
& rInOutPosition
,
356 const chart2::RelativeSize
& rObjectSize
,
357 double fAmountX
, double fAmountY
,
358 bool bCheck
/* = true */ )
360 chart2::RelativePosition
aPos( rInOutPosition
);
361 aPos
.Primary
+= fAmountX
;
362 aPos
.Secondary
+= fAmountY
;
363 const double fPosCheckThreshold
= 0.02;
367 chart2::RelativePosition
aUpperLeft(
368 RelativePositionHelper::getReanchoredPosition( aPos
, rObjectSize
, drawing::Alignment_TOP_LEFT
));
369 chart2::RelativePosition
aLowerRight( aUpperLeft
);
370 aLowerRight
.Primary
+= rObjectSize
.Primary
;
371 aLowerRight
.Secondary
+= rObjectSize
.Secondary
;
373 const double fFarEdgeThreshold
= 1.0 - fPosCheckThreshold
;
374 if( ( fAmountX
> 0.0 && (aLowerRight
.Primary
> fFarEdgeThreshold
)) ||
375 ( fAmountX
< 0.0 && (aUpperLeft
.Primary
< fPosCheckThreshold
)) ||
376 ( fAmountY
> 0.0 && (aLowerRight
.Secondary
> fFarEdgeThreshold
)) ||
377 ( fAmountY
< 0.0 && (aUpperLeft
.Secondary
< fPosCheckThreshold
)) )
381 rInOutPosition
= aPos
;
387 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */