merged tag ooo/OOO330_m14
[LibreOffice.git] / chart2 / source / tools / RelativePositionHelper.cxx
blob4d566b1f7f487c06a9bb44f42a4371867e79f421
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_chart2.hxx"
31 #include "RelativePositionHelper.hxx"
32 #include <rtl/math.hxx>
34 using namespace ::com::sun::star;
36 namespace chart
39 // static
40 chart2::RelativePosition RelativePositionHelper::getReanchoredPosition(
41 const chart2::RelativePosition & rPosition,
42 const chart2::RelativeSize & rObjectSize,
43 drawing::Alignment aNewAnchor )
45 chart2::RelativePosition aResult( rPosition );
46 if( rPosition.Anchor != aNewAnchor )
48 sal_Int32 nShiftHalfWidths = 0;
49 sal_Int32 nShiftHalfHeights = 0;
51 // normalize to top-left
52 switch( rPosition.Anchor )
54 case drawing::Alignment_TOP_LEFT:
55 break;
56 case drawing::Alignment_LEFT:
57 nShiftHalfHeights -= 1;
58 break;
59 case drawing::Alignment_BOTTOM_LEFT:
60 nShiftHalfHeights -= 2;
61 break;
62 case drawing::Alignment_TOP:
63 nShiftHalfWidths -= 1;
64 break;
65 case drawing::Alignment_CENTER:
66 nShiftHalfWidths -= 1;
67 nShiftHalfHeights -= 1;
68 break;
69 case drawing::Alignment_BOTTOM:
70 nShiftHalfWidths -= 1;
71 nShiftHalfHeights -= 2;
72 break;
73 case drawing::Alignment_TOP_RIGHT:
74 nShiftHalfWidths -= 2;
75 break;
76 case drawing::Alignment_RIGHT:
77 nShiftHalfWidths -= 2;
78 nShiftHalfHeights -= 1;
79 break;
80 case drawing::Alignment_BOTTOM_RIGHT:
81 nShiftHalfWidths -= 2;
82 nShiftHalfHeights -= 2;
83 break;
84 case drawing::Alignment_MAKE_FIXED_SIZE:
85 break;
88 // transform
89 switch( aNewAnchor )
91 case drawing::Alignment_TOP_LEFT:
92 break;
93 case drawing::Alignment_LEFT:
94 nShiftHalfHeights += 1;
95 break;
96 case drawing::Alignment_BOTTOM_LEFT:
97 nShiftHalfHeights += 2;
98 break;
99 case drawing::Alignment_TOP:
100 nShiftHalfWidths += 1;
101 break;
102 case drawing::Alignment_CENTER:
103 nShiftHalfWidths += 1;
104 nShiftHalfHeights += 1;
105 break;
106 case drawing::Alignment_BOTTOM:
107 nShiftHalfWidths += 1;
108 nShiftHalfHeights += 2;
109 break;
110 case drawing::Alignment_TOP_RIGHT:
111 nShiftHalfWidths += 2;
112 break;
113 case drawing::Alignment_RIGHT:
114 nShiftHalfWidths += 2;
115 nShiftHalfHeights += 1;
116 break;
117 case drawing::Alignment_BOTTOM_RIGHT:
118 nShiftHalfWidths += 2;
119 nShiftHalfHeights += 2;
120 break;
121 case drawing::Alignment_MAKE_FIXED_SIZE:
122 break;
125 if( nShiftHalfWidths != 0 )
126 aResult.Primary += (rObjectSize.Primary / 2.0) * nShiftHalfWidths;
127 if( nShiftHalfHeights != 0 )
128 aResult.Secondary += (rObjectSize.Secondary / 2.0) * nShiftHalfHeights;
131 return aResult;
135 // static
136 awt::Point RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
137 awt::Point aPoint
138 , awt::Size aObjectSize
139 , drawing::Alignment aAnchor )
141 awt::Point aResult( aPoint );
143 double fXDelta = 0.0;
144 double fYDelta = 0.0;
146 // adapt x-value
147 switch( aAnchor )
149 case drawing::Alignment_TOP:
150 case drawing::Alignment_CENTER:
151 case drawing::Alignment_BOTTOM:
152 fXDelta -= static_cast< double >( aObjectSize.Width ) / 2.0;
153 break;
154 case drawing::Alignment_TOP_RIGHT:
155 case drawing::Alignment_RIGHT:
156 case drawing::Alignment_BOTTOM_RIGHT:
157 fXDelta -= aObjectSize.Width;
158 break;
159 case drawing::Alignment_TOP_LEFT:
160 case drawing::Alignment_LEFT:
161 case drawing::Alignment_BOTTOM_LEFT:
162 default:
163 // nothing to do
164 break;
167 // adapt y-value
168 switch( aAnchor )
170 case drawing::Alignment_LEFT:
171 case drawing::Alignment_CENTER:
172 case drawing::Alignment_RIGHT:
173 fYDelta -= static_cast< double >( aObjectSize.Height ) / 2.0;
174 break;
175 case drawing::Alignment_BOTTOM_LEFT:
176 case drawing::Alignment_BOTTOM:
177 case drawing::Alignment_BOTTOM_RIGHT:
178 fYDelta -= aObjectSize.Height;
179 break;
180 case drawing::Alignment_TOP_LEFT:
181 case drawing::Alignment_TOP:
182 case drawing::Alignment_TOP_RIGHT:
183 default:
184 // nothing to do
185 break;
188 aResult.X += static_cast< sal_Int32 >( ::rtl::math::round( fXDelta ));
189 aResult.Y += static_cast< sal_Int32 >( ::rtl::math::round( fYDelta ));
191 return aResult;
194 // static
195 awt::Point RelativePositionHelper::getCenterOfAnchoredObject(
196 awt::Point aPoint
197 , awt::Size aUnrotatedObjectSize
198 , drawing::Alignment aAnchor
199 , double fAnglePi )
201 awt::Point aResult( aPoint );
203 double fXDelta = 0.0;
204 double fYDelta = 0.0;
206 // adapt x-value
207 switch( aAnchor )
209 case drawing::Alignment_TOP:
210 case drawing::Alignment_CENTER:
211 case drawing::Alignment_BOTTOM:
212 // nothing to do
213 break;
214 case drawing::Alignment_TOP_RIGHT:
215 case drawing::Alignment_RIGHT:
216 case drawing::Alignment_BOTTOM_RIGHT:
217 fXDelta -= aUnrotatedObjectSize.Width/2;
218 break;
219 case drawing::Alignment_TOP_LEFT:
220 case drawing::Alignment_LEFT:
221 case drawing::Alignment_BOTTOM_LEFT:
222 default:
223 fXDelta += aUnrotatedObjectSize.Width/2;
224 break;
227 // adapt y-value
228 switch( aAnchor )
230 case drawing::Alignment_LEFT:
231 case drawing::Alignment_CENTER:
232 case drawing::Alignment_RIGHT:
233 // nothing to do
234 break;
235 case drawing::Alignment_BOTTOM_LEFT:
236 case drawing::Alignment_BOTTOM:
237 case drawing::Alignment_BOTTOM_RIGHT:
238 fYDelta -= aUnrotatedObjectSize.Height/2;
239 break;
240 case drawing::Alignment_TOP_LEFT:
241 case drawing::Alignment_TOP:
242 case drawing::Alignment_TOP_RIGHT:
243 fYDelta += aUnrotatedObjectSize.Height/2;
244 default:
245 // nothing to do
246 break;
249 //take rotation into account:
250 aResult.X += static_cast< sal_Int32 >(
251 ::rtl::math::round( fXDelta * rtl::math::cos( fAnglePi ) + fYDelta * rtl::math::sin( fAnglePi ) ) );
252 aResult.Y += static_cast< sal_Int32 >(
253 ::rtl::math::round( - fXDelta * rtl::math::sin( fAnglePi ) + fYDelta * rtl::math::cos( fAnglePi ) ) );
255 return aResult;
258 bool RelativePositionHelper::centerGrow(
259 chart2::RelativePosition & rInOutPosition,
260 chart2::RelativeSize & rInOutSize,
261 double fAmountX, double fAmountY,
262 bool bCheck /* = true */ )
264 chart2::RelativePosition aPos( rInOutPosition );
265 chart2::RelativeSize aSize( rInOutSize );
266 const double fPosCheckThreshold = 0.02;
267 const double fSizeCheckThreshold = 0.1;
269 // grow/shrink, back to relaative
270 aSize.Primary += fAmountX;
271 aSize.Secondary += fAmountY;
273 double fShiftAmountX = fAmountX / 2.0;
274 double fShiftAmountY = fAmountY / 2.0;
276 // shift X
277 switch( rInOutPosition.Anchor )
279 case drawing::Alignment_TOP_LEFT:
280 case drawing::Alignment_LEFT:
281 case drawing::Alignment_BOTTOM_LEFT:
282 aPos.Primary -= fShiftAmountX;
283 break;
284 case drawing::Alignment_TOP:
285 case drawing::Alignment_CENTER:
286 case drawing::Alignment_BOTTOM:
287 // nothing
288 break;
289 case drawing::Alignment_TOP_RIGHT:
290 case drawing::Alignment_RIGHT:
291 case drawing::Alignment_BOTTOM_RIGHT:
292 aPos.Primary += fShiftAmountX;
293 break;
294 case drawing::Alignment_MAKE_FIXED_SIZE:
295 break;
298 // shift Y
299 switch( rInOutPosition.Anchor )
301 case drawing::Alignment_TOP:
302 case drawing::Alignment_TOP_LEFT:
303 case drawing::Alignment_TOP_RIGHT:
304 aPos.Secondary -= fShiftAmountY;
305 break;
306 case drawing::Alignment_CENTER:
307 case drawing::Alignment_LEFT:
308 case drawing::Alignment_RIGHT:
309 // nothing
310 break;
311 case drawing::Alignment_BOTTOM:
312 case drawing::Alignment_BOTTOM_LEFT:
313 case drawing::Alignment_BOTTOM_RIGHT:
314 aPos.Secondary += fShiftAmountY;
315 break;
316 case drawing::Alignment_MAKE_FIXED_SIZE:
317 break;
320 // anchor must not be changed
321 OSL_ASSERT( rInOutPosition.Anchor == aPos.Anchor );
323 if( rInOutPosition.Primary == aPos.Primary &&
324 rInOutPosition.Secondary == aPos.Secondary &&
325 rInOutSize.Primary == aSize.Primary &&
326 rInOutSize.Secondary == aSize.Secondary )
327 return false;
329 // check
330 if( bCheck )
332 // Note: this somewhat complicated check allows the output being
333 // out-of-bounds if the input was also out-of-bounds, and the change is
334 // for "advantage". E.g., you have a chart that laps out on the left
335 // side. If you shrink it, this should be possible, also if it still
336 // laps out on the left side afterwards. But you shouldn't be able to
337 // grow it then.
339 chart2::RelativePosition aUpperLeft(
340 RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_TOP_LEFT ));
341 chart2::RelativePosition aLowerRight(
342 RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_BOTTOM_RIGHT ));
344 // Do not grow, if this leads to corners being off-screen
345 if( fAmountX > 0.0 &&
346 ( (aUpperLeft.Primary < fPosCheckThreshold) ||
347 (aLowerRight.Primary > (1.0 - fPosCheckThreshold)) ))
348 return false;
349 if( fAmountY > 0.0 &&
350 ( (aUpperLeft.Secondary < fPosCheckThreshold) ||
351 (aLowerRight.Secondary > (1.0 - fPosCheckThreshold)) ))
352 return false;
354 // Do not shrink, if this leads to a size too small
355 if( fAmountX < 0.0 &&
356 ( aSize.Primary < fSizeCheckThreshold ))
357 return false;
358 if( fAmountY < 0.0 &&
359 ( aSize.Secondary < fSizeCheckThreshold ))
360 return false;
363 rInOutPosition = aPos;
364 rInOutSize = aSize;
365 return true;
368 bool RelativePositionHelper::moveObject(
369 chart2::RelativePosition & rInOutPosition,
370 const chart2::RelativeSize & rObjectSize,
371 double fAmountX, double fAmountY,
372 bool bCheck /* = true */ )
374 chart2::RelativePosition aPos( rInOutPosition );
375 aPos.Primary += fAmountX;
376 aPos.Secondary += fAmountY;
377 const double fPosCheckThreshold = 0.02;
379 if( bCheck )
381 chart2::RelativePosition aUpperLeft(
382 RelativePositionHelper::getReanchoredPosition( aPos, rObjectSize, drawing::Alignment_TOP_LEFT ));
383 chart2::RelativePosition aLowerRight( aUpperLeft );
384 aLowerRight.Primary += rObjectSize.Primary;
385 aLowerRight.Secondary += rObjectSize.Secondary;
387 const double fFarEdgeThreshold = 1.0 - fPosCheckThreshold;
388 if( ( fAmountX > 0.0 && (aLowerRight.Primary > fFarEdgeThreshold)) ||
389 ( fAmountX < 0.0 && (aUpperLeft.Primary < fPosCheckThreshold)) ||
390 ( fAmountY > 0.0 && (aLowerRight.Secondary > fFarEdgeThreshold)) ||
391 ( fAmountY < 0.0 && (aUpperLeft.Secondary < fPosCheckThreshold)) )
392 return false;
395 rInOutPosition = aPos;
396 return true;
399 } // namespace chart