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