Bump for 3.6-28
[LibreOffice.git] / chart2 / source / tools / RelativePositionHelper.cxx
blob11dc1ffad8b168fc0eb3c70eb08612809e71de0a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "RelativePositionHelper.hxx"
31 #include <rtl/math.hxx>
33 using namespace ::com::sun::star;
35 namespace chart
38 chart2::RelativePosition RelativePositionHelper::getReanchoredPosition(
39 const chart2::RelativePosition & rPosition,
40 const chart2::RelativeSize & rObjectSize,
41 drawing::Alignment aNewAnchor )
43 chart2::RelativePosition aResult( rPosition );
44 if( rPosition.Anchor != aNewAnchor )
46 sal_Int32 nShiftHalfWidths = 0;
47 sal_Int32 nShiftHalfHeights = 0;
49 // normalize to top-left
50 switch( rPosition.Anchor )
52 case drawing::Alignment_TOP_LEFT:
53 break;
54 case drawing::Alignment_LEFT:
55 nShiftHalfHeights -= 1;
56 break;
57 case drawing::Alignment_BOTTOM_LEFT:
58 nShiftHalfHeights -= 2;
59 break;
60 case drawing::Alignment_TOP:
61 nShiftHalfWidths -= 1;
62 break;
63 case drawing::Alignment_CENTER:
64 nShiftHalfWidths -= 1;
65 nShiftHalfHeights -= 1;
66 break;
67 case drawing::Alignment_BOTTOM:
68 nShiftHalfWidths -= 1;
69 nShiftHalfHeights -= 2;
70 break;
71 case drawing::Alignment_TOP_RIGHT:
72 nShiftHalfWidths -= 2;
73 break;
74 case drawing::Alignment_RIGHT:
75 nShiftHalfWidths -= 2;
76 nShiftHalfHeights -= 1;
77 break;
78 case drawing::Alignment_BOTTOM_RIGHT:
79 nShiftHalfWidths -= 2;
80 nShiftHalfHeights -= 2;
81 break;
82 case drawing::Alignment_MAKE_FIXED_SIZE:
83 break;
86 // transform
87 switch( aNewAnchor )
89 case drawing::Alignment_TOP_LEFT:
90 break;
91 case drawing::Alignment_LEFT:
92 nShiftHalfHeights += 1;
93 break;
94 case drawing::Alignment_BOTTOM_LEFT:
95 nShiftHalfHeights += 2;
96 break;
97 case drawing::Alignment_TOP:
98 nShiftHalfWidths += 1;
99 break;
100 case drawing::Alignment_CENTER:
101 nShiftHalfWidths += 1;
102 nShiftHalfHeights += 1;
103 break;
104 case drawing::Alignment_BOTTOM:
105 nShiftHalfWidths += 1;
106 nShiftHalfHeights += 2;
107 break;
108 case drawing::Alignment_TOP_RIGHT:
109 nShiftHalfWidths += 2;
110 break;
111 case drawing::Alignment_RIGHT:
112 nShiftHalfWidths += 2;
113 nShiftHalfHeights += 1;
114 break;
115 case drawing::Alignment_BOTTOM_RIGHT:
116 nShiftHalfWidths += 2;
117 nShiftHalfHeights += 2;
118 break;
119 case drawing::Alignment_MAKE_FIXED_SIZE:
120 break;
123 if( nShiftHalfWidths != 0 )
124 aResult.Primary += (rObjectSize.Primary / 2.0) * nShiftHalfWidths;
125 if( nShiftHalfHeights != 0 )
126 aResult.Secondary += (rObjectSize.Secondary / 2.0) * nShiftHalfHeights;
129 return aResult;
133 awt::Point RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
134 awt::Point aPoint
135 , awt::Size aObjectSize
136 , drawing::Alignment aAnchor )
138 awt::Point aResult( aPoint );
140 double fXDelta = 0.0;
141 double fYDelta = 0.0;
143 // adapt x-value
144 switch( aAnchor )
146 case drawing::Alignment_TOP:
147 case drawing::Alignment_CENTER:
148 case drawing::Alignment_BOTTOM:
149 fXDelta -= static_cast< double >( aObjectSize.Width ) / 2.0;
150 break;
151 case drawing::Alignment_TOP_RIGHT:
152 case drawing::Alignment_RIGHT:
153 case drawing::Alignment_BOTTOM_RIGHT:
154 fXDelta -= aObjectSize.Width;
155 break;
156 case drawing::Alignment_TOP_LEFT:
157 case drawing::Alignment_LEFT:
158 case drawing::Alignment_BOTTOM_LEFT:
159 default:
160 // nothing to do
161 break;
164 // adapt y-value
165 switch( aAnchor )
167 case drawing::Alignment_LEFT:
168 case drawing::Alignment_CENTER:
169 case drawing::Alignment_RIGHT:
170 fYDelta -= static_cast< double >( aObjectSize.Height ) / 2.0;
171 break;
172 case drawing::Alignment_BOTTOM_LEFT:
173 case drawing::Alignment_BOTTOM:
174 case drawing::Alignment_BOTTOM_RIGHT:
175 fYDelta -= aObjectSize.Height;
176 break;
177 case drawing::Alignment_TOP_LEFT:
178 case drawing::Alignment_TOP:
179 case drawing::Alignment_TOP_RIGHT:
180 default:
181 // nothing to do
182 break;
185 aResult.X += static_cast< sal_Int32 >( ::rtl::math::round( fXDelta ));
186 aResult.Y += static_cast< sal_Int32 >( ::rtl::math::round( fYDelta ));
188 return aResult;
191 awt::Point RelativePositionHelper::getCenterOfAnchoredObject(
192 awt::Point aPoint
193 , awt::Size aUnrotatedObjectSize
194 , drawing::Alignment aAnchor
195 , double fAnglePi )
197 awt::Point aResult( aPoint );
199 double fXDelta = 0.0;
200 double fYDelta = 0.0;
202 // adapt x-value
203 switch( aAnchor )
205 case drawing::Alignment_TOP:
206 case drawing::Alignment_CENTER:
207 case drawing::Alignment_BOTTOM:
208 // nothing to do
209 break;
210 case drawing::Alignment_TOP_RIGHT:
211 case drawing::Alignment_RIGHT:
212 case drawing::Alignment_BOTTOM_RIGHT:
213 fXDelta -= aUnrotatedObjectSize.Width/2;
214 break;
215 case drawing::Alignment_TOP_LEFT:
216 case drawing::Alignment_LEFT:
217 case drawing::Alignment_BOTTOM_LEFT:
218 default:
219 fXDelta += aUnrotatedObjectSize.Width/2;
220 break;
223 // adapt y-value
224 switch( aAnchor )
226 case drawing::Alignment_LEFT:
227 case drawing::Alignment_CENTER:
228 case drawing::Alignment_RIGHT:
229 // nothing to do
230 break;
231 case drawing::Alignment_BOTTOM_LEFT:
232 case drawing::Alignment_BOTTOM:
233 case drawing::Alignment_BOTTOM_RIGHT:
234 fYDelta -= aUnrotatedObjectSize.Height/2;
235 break;
236 case drawing::Alignment_TOP_LEFT:
237 case drawing::Alignment_TOP:
238 case drawing::Alignment_TOP_RIGHT:
239 fYDelta += aUnrotatedObjectSize.Height/2;
240 default:
241 // nothing to do
242 break;
245 //take rotation into account:
246 aResult.X += static_cast< sal_Int32 >(
247 ::rtl::math::round( fXDelta * rtl::math::cos( fAnglePi ) + fYDelta * rtl::math::sin( fAnglePi ) ) );
248 aResult.Y += static_cast< sal_Int32 >(
249 ::rtl::math::round( - fXDelta * rtl::math::sin( fAnglePi ) + fYDelta * rtl::math::cos( fAnglePi ) ) );
251 return aResult;
254 bool RelativePositionHelper::centerGrow(
255 chart2::RelativePosition & rInOutPosition,
256 chart2::RelativeSize & rInOutSize,
257 double fAmountX, double fAmountY,
258 bool bCheck /* = true */ )
260 chart2::RelativePosition aPos( rInOutPosition );
261 chart2::RelativeSize aSize( rInOutSize );
262 const double fPosCheckThreshold = 0.02;
263 const double fSizeCheckThreshold = 0.1;
265 // grow/shrink, back to relaative
266 aSize.Primary += fAmountX;
267 aSize.Secondary += fAmountY;
269 double fShiftAmountX = fAmountX / 2.0;
270 double fShiftAmountY = fAmountY / 2.0;
272 // shift X
273 switch( rInOutPosition.Anchor )
275 case drawing::Alignment_TOP_LEFT:
276 case drawing::Alignment_LEFT:
277 case drawing::Alignment_BOTTOM_LEFT:
278 aPos.Primary -= fShiftAmountX;
279 break;
280 case drawing::Alignment_TOP:
281 case drawing::Alignment_CENTER:
282 case drawing::Alignment_BOTTOM:
283 // nothing
284 break;
285 case drawing::Alignment_TOP_RIGHT:
286 case drawing::Alignment_RIGHT:
287 case drawing::Alignment_BOTTOM_RIGHT:
288 aPos.Primary += fShiftAmountX;
289 break;
290 case drawing::Alignment_MAKE_FIXED_SIZE:
291 break;
294 // shift Y
295 switch( rInOutPosition.Anchor )
297 case drawing::Alignment_TOP:
298 case drawing::Alignment_TOP_LEFT:
299 case drawing::Alignment_TOP_RIGHT:
300 aPos.Secondary -= fShiftAmountY;
301 break;
302 case drawing::Alignment_CENTER:
303 case drawing::Alignment_LEFT:
304 case drawing::Alignment_RIGHT:
305 // nothing
306 break;
307 case drawing::Alignment_BOTTOM:
308 case drawing::Alignment_BOTTOM_LEFT:
309 case drawing::Alignment_BOTTOM_RIGHT:
310 aPos.Secondary += fShiftAmountY;
311 break;
312 case drawing::Alignment_MAKE_FIXED_SIZE:
313 break;
316 // anchor must not be changed
317 OSL_ASSERT( rInOutPosition.Anchor == aPos.Anchor );
319 if( rInOutPosition.Primary == aPos.Primary &&
320 rInOutPosition.Secondary == aPos.Secondary &&
321 rInOutSize.Primary == aSize.Primary &&
322 rInOutSize.Secondary == aSize.Secondary )
323 return false;
325 // check
326 if( bCheck )
328 // Note: this somewhat complicated check allows the output being
329 // out-of-bounds if the input was also out-of-bounds, and the change is
330 // for "advantage". E.g., you have a chart that laps out on the left
331 // side. If you shrink it, this should be possible, also if it still
332 // laps out on the left side afterwards. But you shouldn't be able to
333 // grow it then.
335 chart2::RelativePosition aUpperLeft(
336 RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_TOP_LEFT ));
337 chart2::RelativePosition aLowerRight(
338 RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_BOTTOM_RIGHT ));
340 // Do not grow, if this leads to corners being off-screen
341 if( fAmountX > 0.0 &&
342 ( (aUpperLeft.Primary < fPosCheckThreshold) ||
343 (aLowerRight.Primary > (1.0 - fPosCheckThreshold)) ))
344 return false;
345 if( fAmountY > 0.0 &&
346 ( (aUpperLeft.Secondary < fPosCheckThreshold) ||
347 (aLowerRight.Secondary > (1.0 - fPosCheckThreshold)) ))
348 return false;
350 // Do not shrink, if this leads to a size too small
351 if( fAmountX < 0.0 &&
352 ( aSize.Primary < fSizeCheckThreshold ))
353 return false;
354 if( fAmountY < 0.0 &&
355 ( aSize.Secondary < fSizeCheckThreshold ))
356 return false;
359 rInOutPosition = aPos;
360 rInOutSize = aSize;
361 return true;
364 bool RelativePositionHelper::moveObject(
365 chart2::RelativePosition & rInOutPosition,
366 const chart2::RelativeSize & rObjectSize,
367 double fAmountX, double fAmountY,
368 bool bCheck /* = true */ )
370 chart2::RelativePosition aPos( rInOutPosition );
371 aPos.Primary += fAmountX;
372 aPos.Secondary += fAmountY;
373 const double fPosCheckThreshold = 0.02;
375 if( bCheck )
377 chart2::RelativePosition aUpperLeft(
378 RelativePositionHelper::getReanchoredPosition( aPos, rObjectSize, drawing::Alignment_TOP_LEFT ));
379 chart2::RelativePosition aLowerRight( aUpperLeft );
380 aLowerRight.Primary += rObjectSize.Primary;
381 aLowerRight.Secondary += rObjectSize.Secondary;
383 const double fFarEdgeThreshold = 1.0 - fPosCheckThreshold;
384 if( ( fAmountX > 0.0 && (aLowerRight.Primary > fFarEdgeThreshold)) ||
385 ( fAmountX < 0.0 && (aUpperLeft.Primary < fPosCheckThreshold)) ||
386 ( fAmountY > 0.0 && (aLowerRight.Secondary > fFarEdgeThreshold)) ||
387 ( fAmountY < 0.0 && (aUpperLeft.Secondary < fPosCheckThreshold)) )
388 return false;
391 rInOutPosition = aPos;
392 return true;
395 } // namespace chart
397 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */