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 <com/sun/star/chart2/RelativeSize.hpp>
22 #include <com/sun/star/awt/Size.hpp>
23 #include <rtl/math.hxx>
24 #include <osl/diagnose.h>
26 using namespace ::com::sun::star
;
31 chart2::RelativePosition
RelativePositionHelper::getReanchoredPosition(
32 const chart2::RelativePosition
& rPosition
,
33 const chart2::RelativeSize
& rObjectSize
,
34 drawing::Alignment aNewAnchor
)
36 chart2::RelativePosition
aResult( rPosition
);
37 if( rPosition
.Anchor
!= aNewAnchor
)
39 sal_Int32 nShiftHalfWidths
= 0;
40 sal_Int32 nShiftHalfHeights
= 0;
42 // normalize to top-left
43 switch( rPosition
.Anchor
)
45 case drawing::Alignment_TOP_LEFT
:
47 case drawing::Alignment_LEFT
:
48 nShiftHalfHeights
-= 1;
50 case drawing::Alignment_BOTTOM_LEFT
:
51 nShiftHalfHeights
-= 2;
53 case drawing::Alignment_TOP
:
54 nShiftHalfWidths
-= 1;
56 case drawing::Alignment_CENTER
:
57 nShiftHalfWidths
-= 1;
58 nShiftHalfHeights
-= 1;
60 case drawing::Alignment_BOTTOM
:
61 nShiftHalfWidths
-= 1;
62 nShiftHalfHeights
-= 2;
64 case drawing::Alignment_TOP_RIGHT
:
65 nShiftHalfWidths
-= 2;
67 case drawing::Alignment_RIGHT
:
68 nShiftHalfWidths
-= 2;
69 nShiftHalfHeights
-= 1;
71 case drawing::Alignment_BOTTOM_RIGHT
:
72 nShiftHalfWidths
-= 2;
73 nShiftHalfHeights
-= 2;
75 case drawing::Alignment::Alignment_MAKE_FIXED_SIZE
:
82 case drawing::Alignment_TOP_LEFT
:
84 case drawing::Alignment_LEFT
:
85 nShiftHalfHeights
+= 1;
87 case drawing::Alignment_BOTTOM_LEFT
:
88 nShiftHalfHeights
+= 2;
90 case drawing::Alignment_TOP
:
91 nShiftHalfWidths
+= 1;
93 case drawing::Alignment_CENTER
:
94 nShiftHalfWidths
+= 1;
95 nShiftHalfHeights
+= 1;
97 case drawing::Alignment_BOTTOM
:
98 nShiftHalfWidths
+= 1;
99 nShiftHalfHeights
+= 2;
101 case drawing::Alignment_TOP_RIGHT
:
102 nShiftHalfWidths
+= 2;
104 case drawing::Alignment_RIGHT
:
105 nShiftHalfWidths
+= 2;
106 nShiftHalfHeights
+= 1;
108 case drawing::Alignment_BOTTOM_RIGHT
:
109 nShiftHalfWidths
+= 2;
110 nShiftHalfHeights
+= 2;
112 case drawing::Alignment::Alignment_MAKE_FIXED_SIZE
:
116 if( nShiftHalfWidths
!= 0 )
117 aResult
.Primary
+= (rObjectSize
.Primary
/ 2.0) * nShiftHalfWidths
;
118 if( nShiftHalfHeights
!= 0 )
119 aResult
.Secondary
+= (rObjectSize
.Secondary
/ 2.0) * nShiftHalfHeights
;
125 awt::Point
RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
127 , awt::Size aObjectSize
128 , drawing::Alignment aAnchor
)
130 awt::Point
aResult( aPoint
);
132 double fXDelta
= 0.0;
133 double fYDelta
= 0.0;
138 case drawing::Alignment_TOP
:
139 case drawing::Alignment_CENTER
:
140 case drawing::Alignment_BOTTOM
:
141 fXDelta
-= static_cast< double >( aObjectSize
.Width
) / 2.0;
143 case drawing::Alignment_TOP_RIGHT
:
144 case drawing::Alignment_RIGHT
:
145 case drawing::Alignment_BOTTOM_RIGHT
:
146 fXDelta
-= aObjectSize
.Width
;
148 case drawing::Alignment_TOP_LEFT
:
149 case drawing::Alignment_LEFT
:
150 case drawing::Alignment_BOTTOM_LEFT
:
159 case drawing::Alignment_LEFT
:
160 case drawing::Alignment_CENTER
:
161 case drawing::Alignment_RIGHT
:
162 fYDelta
-= static_cast< double >( aObjectSize
.Height
) / 2.0;
164 case drawing::Alignment_BOTTOM_LEFT
:
165 case drawing::Alignment_BOTTOM
:
166 case drawing::Alignment_BOTTOM_RIGHT
:
167 fYDelta
-= aObjectSize
.Height
;
169 case drawing::Alignment_TOP_LEFT
:
170 case drawing::Alignment_TOP
:
171 case drawing::Alignment_TOP_RIGHT
:
177 aResult
.X
+= static_cast< sal_Int32
>( ::rtl::math::round( fXDelta
));
178 aResult
.Y
+= static_cast< sal_Int32
>( ::rtl::math::round( fYDelta
));
183 awt::Point
RelativePositionHelper::getCenterOfAnchoredObject(
185 , awt::Size aUnrotatedObjectSize
186 , drawing::Alignment aAnchor
189 awt::Point
aResult( aPoint
);
191 double fXDelta
= 0.0;
192 double fYDelta
= 0.0;
197 case drawing::Alignment_TOP
:
198 case drawing::Alignment_CENTER
:
199 case drawing::Alignment_BOTTOM
:
202 case drawing::Alignment_TOP_RIGHT
:
203 case drawing::Alignment_RIGHT
:
204 case drawing::Alignment_BOTTOM_RIGHT
:
205 fXDelta
-= aUnrotatedObjectSize
.Width
/2;
207 case drawing::Alignment_TOP_LEFT
:
208 case drawing::Alignment_LEFT
:
209 case drawing::Alignment_BOTTOM_LEFT
:
211 fXDelta
+= aUnrotatedObjectSize
.Width
/2;
218 case drawing::Alignment_LEFT
:
219 case drawing::Alignment_CENTER
:
220 case drawing::Alignment_RIGHT
:
223 case drawing::Alignment_BOTTOM_LEFT
:
224 case drawing::Alignment_BOTTOM
:
225 case drawing::Alignment_BOTTOM_RIGHT
:
226 fYDelta
-= aUnrotatedObjectSize
.Height
/2;
228 case drawing::Alignment_TOP_LEFT
:
229 case drawing::Alignment_TOP
:
230 case drawing::Alignment_TOP_RIGHT
:
231 fYDelta
+= aUnrotatedObjectSize
.Height
/2;
238 //take rotation into account:
239 aResult
.X
+= static_cast< sal_Int32
>(
240 ::rtl::math::round( fXDelta
* std::cos( fAnglePi
) + fYDelta
* std::sin( fAnglePi
) ) );
241 aResult
.Y
+= static_cast< sal_Int32
>(
242 ::rtl::math::round( - fXDelta
* std::sin( fAnglePi
) + fYDelta
* std::cos( fAnglePi
) ) );
247 bool RelativePositionHelper::centerGrow(
248 chart2::RelativePosition
& rInOutPosition
,
249 chart2::RelativeSize
& rInOutSize
,
250 double fAmountX
, double fAmountY
)
252 chart2::RelativePosition
aPos( rInOutPosition
);
253 chart2::RelativeSize
aSize( rInOutSize
);
254 const double fPosCheckThreshold
= 0.02;
255 const double fSizeCheckThreshold
= 0.1;
257 // grow/shrink, back to relative
258 aSize
.Primary
+= fAmountX
;
259 aSize
.Secondary
+= fAmountY
;
261 double fShiftAmountX
= fAmountX
/ 2.0;
262 double fShiftAmountY
= fAmountY
/ 2.0;
265 switch( rInOutPosition
.Anchor
)
267 case drawing::Alignment_TOP_LEFT
:
268 case drawing::Alignment_LEFT
:
269 case drawing::Alignment_BOTTOM_LEFT
:
270 aPos
.Primary
-= fShiftAmountX
;
272 case drawing::Alignment_TOP
:
273 case drawing::Alignment_CENTER
:
274 case drawing::Alignment_BOTTOM
:
277 case drawing::Alignment_TOP_RIGHT
:
278 case drawing::Alignment_RIGHT
:
279 case drawing::Alignment_BOTTOM_RIGHT
:
280 aPos
.Primary
+= fShiftAmountX
;
282 case drawing::Alignment::Alignment_MAKE_FIXED_SIZE
:
287 switch( rInOutPosition
.Anchor
)
289 case drawing::Alignment_TOP
:
290 case drawing::Alignment_TOP_LEFT
:
291 case drawing::Alignment_TOP_RIGHT
:
292 aPos
.Secondary
-= fShiftAmountY
;
294 case drawing::Alignment_CENTER
:
295 case drawing::Alignment_LEFT
:
296 case drawing::Alignment_RIGHT
:
299 case drawing::Alignment_BOTTOM
:
300 case drawing::Alignment_BOTTOM_LEFT
:
301 case drawing::Alignment_BOTTOM_RIGHT
:
302 aPos
.Secondary
+= fShiftAmountY
;
304 case drawing::Alignment::Alignment_MAKE_FIXED_SIZE
:
308 // anchor must not be changed
309 OSL_ASSERT( rInOutPosition
.Anchor
== aPos
.Anchor
);
311 if( rInOutPosition
.Primary
== aPos
.Primary
&&
312 rInOutPosition
.Secondary
== aPos
.Secondary
&&
313 rInOutSize
.Primary
== aSize
.Primary
&&
314 rInOutSize
.Secondary
== aSize
.Secondary
)
317 // Note: this somewhat complicated check allows the output being
318 // out-of-bounds if the input was also out-of-bounds, and the change is
319 // for "advantage". E.g., you have a chart that laps out on the left
320 // side. If you shrink it, this should be possible, also if it still
321 // laps out on the left side afterwards. But you shouldn't be able to
324 chart2::RelativePosition
aUpperLeft(
325 RelativePositionHelper::getReanchoredPosition( aPos
, aSize
, drawing::Alignment_TOP_LEFT
));
326 chart2::RelativePosition
aLowerRight(
327 RelativePositionHelper::getReanchoredPosition( aPos
, aSize
, drawing::Alignment_BOTTOM_RIGHT
));
329 // Do not grow, if this leads to corners being off-screen
330 if( fAmountX
> 0.0 &&
331 ( (aUpperLeft
.Primary
< fPosCheckThreshold
) ||
332 (aLowerRight
.Primary
> (1.0 - fPosCheckThreshold
)) ))
334 if( fAmountY
> 0.0 &&
335 ( (aUpperLeft
.Secondary
< fPosCheckThreshold
) ||
336 (aLowerRight
.Secondary
> (1.0 - fPosCheckThreshold
)) ))
339 // Do not shrink, if this leads to a size too small
340 if( fAmountX
< 0.0 &&
341 ( aSize
.Primary
< fSizeCheckThreshold
))
343 if( fAmountY
< 0.0 &&
344 ( aSize
.Secondary
< fSizeCheckThreshold
))
347 rInOutPosition
= aPos
;
352 bool RelativePositionHelper::moveObject(
353 chart2::RelativePosition
& rInOutPosition
,
354 const chart2::RelativeSize
& rObjectSize
,
355 double fAmountX
, double fAmountY
)
357 chart2::RelativePosition
aPos( rInOutPosition
);
358 aPos
.Primary
+= fAmountX
;
359 aPos
.Secondary
+= fAmountY
;
360 const double fPosCheckThreshold
= 0.02;
362 chart2::RelativePosition
aUpperLeft(
363 RelativePositionHelper::getReanchoredPosition( aPos
, rObjectSize
, drawing::Alignment_TOP_LEFT
));
364 chart2::RelativePosition
aLowerRight( aUpperLeft
);
365 aLowerRight
.Primary
+= rObjectSize
.Primary
;
366 aLowerRight
.Secondary
+= rObjectSize
.Secondary
;
368 const double fFarEdgeThreshold
= 1.0 - fPosCheckThreshold
;
369 if( ( fAmountX
> 0.0 && (aLowerRight
.Primary
> fFarEdgeThreshold
)) ||
370 ( fAmountX
< 0.0 && (aUpperLeft
.Primary
< fPosCheckThreshold
)) ||
371 ( fAmountY
> 0.0 && (aLowerRight
.Secondary
> fFarEdgeThreshold
)) ||
372 ( fAmountY
< 0.0 && (aUpperLeft
.Secondary
< fPosCheckThreshold
)) )
375 rInOutPosition
= aPos
;
381 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */