bump product version to 4.1.6.2
[LibreOffice.git] / chart2 / source / tools / RelativePositionHelper.cxx
blob19506047a876c7da464d32f5b870b241aa8e0407
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include "RelativePositionHelper.hxx"
22 #include <rtl/math.hxx>
24 using namespace ::com::sun::star;
26 namespace chart
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:
44 break;
45 case drawing::Alignment_LEFT:
46 nShiftHalfHeights -= 1;
47 break;
48 case drawing::Alignment_BOTTOM_LEFT:
49 nShiftHalfHeights -= 2;
50 break;
51 case drawing::Alignment_TOP:
52 nShiftHalfWidths -= 1;
53 break;
54 case drawing::Alignment_CENTER:
55 nShiftHalfWidths -= 1;
56 nShiftHalfHeights -= 1;
57 break;
58 case drawing::Alignment_BOTTOM:
59 nShiftHalfWidths -= 1;
60 nShiftHalfHeights -= 2;
61 break;
62 case drawing::Alignment_TOP_RIGHT:
63 nShiftHalfWidths -= 2;
64 break;
65 case drawing::Alignment_RIGHT:
66 nShiftHalfWidths -= 2;
67 nShiftHalfHeights -= 1;
68 break;
69 case drawing::Alignment_BOTTOM_RIGHT:
70 nShiftHalfWidths -= 2;
71 nShiftHalfHeights -= 2;
72 break;
73 case drawing::Alignment_MAKE_FIXED_SIZE:
74 break;
77 // transform
78 switch( aNewAnchor )
80 case drawing::Alignment_TOP_LEFT:
81 break;
82 case drawing::Alignment_LEFT:
83 nShiftHalfHeights += 1;
84 break;
85 case drawing::Alignment_BOTTOM_LEFT:
86 nShiftHalfHeights += 2;
87 break;
88 case drawing::Alignment_TOP:
89 nShiftHalfWidths += 1;
90 break;
91 case drawing::Alignment_CENTER:
92 nShiftHalfWidths += 1;
93 nShiftHalfHeights += 1;
94 break;
95 case drawing::Alignment_BOTTOM:
96 nShiftHalfWidths += 1;
97 nShiftHalfHeights += 2;
98 break;
99 case drawing::Alignment_TOP_RIGHT:
100 nShiftHalfWidths += 2;
101 break;
102 case drawing::Alignment_RIGHT:
103 nShiftHalfWidths += 2;
104 nShiftHalfHeights += 1;
105 break;
106 case drawing::Alignment_BOTTOM_RIGHT:
107 nShiftHalfWidths += 2;
108 nShiftHalfHeights += 2;
109 break;
110 case drawing::Alignment_MAKE_FIXED_SIZE:
111 break;
114 if( nShiftHalfWidths != 0 )
115 aResult.Primary += (rObjectSize.Primary / 2.0) * nShiftHalfWidths;
116 if( nShiftHalfHeights != 0 )
117 aResult.Secondary += (rObjectSize.Secondary / 2.0) * nShiftHalfHeights;
120 return aResult;
124 awt::Point RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
125 awt::Point aPoint
126 , awt::Size aObjectSize
127 , drawing::Alignment aAnchor )
129 awt::Point aResult( aPoint );
131 double fXDelta = 0.0;
132 double fYDelta = 0.0;
134 // adapt x-value
135 switch( aAnchor )
137 case drawing::Alignment_TOP:
138 case drawing::Alignment_CENTER:
139 case drawing::Alignment_BOTTOM:
140 fXDelta -= static_cast< double >( aObjectSize.Width ) / 2.0;
141 break;
142 case drawing::Alignment_TOP_RIGHT:
143 case drawing::Alignment_RIGHT:
144 case drawing::Alignment_BOTTOM_RIGHT:
145 fXDelta -= aObjectSize.Width;
146 break;
147 case drawing::Alignment_TOP_LEFT:
148 case drawing::Alignment_LEFT:
149 case drawing::Alignment_BOTTOM_LEFT:
150 default:
151 // nothing to do
152 break;
155 // adapt y-value
156 switch( aAnchor )
158 case drawing::Alignment_LEFT:
159 case drawing::Alignment_CENTER:
160 case drawing::Alignment_RIGHT:
161 fYDelta -= static_cast< double >( aObjectSize.Height ) / 2.0;
162 break;
163 case drawing::Alignment_BOTTOM_LEFT:
164 case drawing::Alignment_BOTTOM:
165 case drawing::Alignment_BOTTOM_RIGHT:
166 fYDelta -= aObjectSize.Height;
167 break;
168 case drawing::Alignment_TOP_LEFT:
169 case drawing::Alignment_TOP:
170 case drawing::Alignment_TOP_RIGHT:
171 default:
172 // nothing to do
173 break;
176 aResult.X += static_cast< sal_Int32 >( ::rtl::math::round( fXDelta ));
177 aResult.Y += static_cast< sal_Int32 >( ::rtl::math::round( fYDelta ));
179 return aResult;
182 awt::Point RelativePositionHelper::getCenterOfAnchoredObject(
183 awt::Point aPoint
184 , awt::Size aUnrotatedObjectSize
185 , drawing::Alignment aAnchor
186 , double fAnglePi )
188 awt::Point aResult( aPoint );
190 double fXDelta = 0.0;
191 double fYDelta = 0.0;
193 // adapt x-value
194 switch( aAnchor )
196 case drawing::Alignment_TOP:
197 case drawing::Alignment_CENTER:
198 case drawing::Alignment_BOTTOM:
199 // nothing to do
200 break;
201 case drawing::Alignment_TOP_RIGHT:
202 case drawing::Alignment_RIGHT:
203 case drawing::Alignment_BOTTOM_RIGHT:
204 fXDelta -= aUnrotatedObjectSize.Width/2;
205 break;
206 case drawing::Alignment_TOP_LEFT:
207 case drawing::Alignment_LEFT:
208 case drawing::Alignment_BOTTOM_LEFT:
209 default:
210 fXDelta += aUnrotatedObjectSize.Width/2;
211 break;
214 // adapt y-value
215 switch( aAnchor )
217 case drawing::Alignment_LEFT:
218 case drawing::Alignment_CENTER:
219 case drawing::Alignment_RIGHT:
220 // nothing to do
221 break;
222 case drawing::Alignment_BOTTOM_LEFT:
223 case drawing::Alignment_BOTTOM:
224 case drawing::Alignment_BOTTOM_RIGHT:
225 fYDelta -= aUnrotatedObjectSize.Height/2;
226 break;
227 case drawing::Alignment_TOP_LEFT:
228 case drawing::Alignment_TOP:
229 case drawing::Alignment_TOP_RIGHT:
230 fYDelta += aUnrotatedObjectSize.Height/2;
231 default:
232 // nothing to do
233 break;
236 //take rotation into account:
237 aResult.X += static_cast< sal_Int32 >(
238 ::rtl::math::round( fXDelta * rtl::math::cos( fAnglePi ) + fYDelta * rtl::math::sin( fAnglePi ) ) );
239 aResult.Y += static_cast< sal_Int32 >(
240 ::rtl::math::round( - fXDelta * rtl::math::sin( fAnglePi ) + fYDelta * rtl::math::cos( fAnglePi ) ) );
242 return aResult;
245 bool RelativePositionHelper::centerGrow(
246 chart2::RelativePosition & rInOutPosition,
247 chart2::RelativeSize & rInOutSize,
248 double fAmountX, double fAmountY,
249 bool bCheck /* = true */ )
251 chart2::RelativePosition aPos( rInOutPosition );
252 chart2::RelativeSize aSize( rInOutSize );
253 const double fPosCheckThreshold = 0.02;
254 const double fSizeCheckThreshold = 0.1;
256 // grow/shrink, back to relaative
257 aSize.Primary += fAmountX;
258 aSize.Secondary += fAmountY;
260 double fShiftAmountX = fAmountX / 2.0;
261 double fShiftAmountY = fAmountY / 2.0;
263 // shift X
264 switch( rInOutPosition.Anchor )
266 case drawing::Alignment_TOP_LEFT:
267 case drawing::Alignment_LEFT:
268 case drawing::Alignment_BOTTOM_LEFT:
269 aPos.Primary -= fShiftAmountX;
270 break;
271 case drawing::Alignment_TOP:
272 case drawing::Alignment_CENTER:
273 case drawing::Alignment_BOTTOM:
274 // nothing
275 break;
276 case drawing::Alignment_TOP_RIGHT:
277 case drawing::Alignment_RIGHT:
278 case drawing::Alignment_BOTTOM_RIGHT:
279 aPos.Primary += fShiftAmountX;
280 break;
281 case drawing::Alignment_MAKE_FIXED_SIZE:
282 break;
285 // shift Y
286 switch( rInOutPosition.Anchor )
288 case drawing::Alignment_TOP:
289 case drawing::Alignment_TOP_LEFT:
290 case drawing::Alignment_TOP_RIGHT:
291 aPos.Secondary -= fShiftAmountY;
292 break;
293 case drawing::Alignment_CENTER:
294 case drawing::Alignment_LEFT:
295 case drawing::Alignment_RIGHT:
296 // nothing
297 break;
298 case drawing::Alignment_BOTTOM:
299 case drawing::Alignment_BOTTOM_LEFT:
300 case drawing::Alignment_BOTTOM_RIGHT:
301 aPos.Secondary += fShiftAmountY;
302 break;
303 case drawing::Alignment_MAKE_FIXED_SIZE:
304 break;
307 // anchor must not be changed
308 OSL_ASSERT( rInOutPosition.Anchor == aPos.Anchor );
310 if( rInOutPosition.Primary == aPos.Primary &&
311 rInOutPosition.Secondary == aPos.Secondary &&
312 rInOutSize.Primary == aSize.Primary &&
313 rInOutSize.Secondary == aSize.Secondary )
314 return false;
316 // check
317 if( bCheck )
319 // Note: this somewhat complicated check allows the output being
320 // out-of-bounds if the input was also out-of-bounds, and the change is
321 // for "advantage". E.g., you have a chart that laps out on the left
322 // side. If you shrink it, this should be possible, also if it still
323 // laps out on the left side afterwards. But you shouldn't be able to
324 // grow it then.
326 chart2::RelativePosition aUpperLeft(
327 RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_TOP_LEFT ));
328 chart2::RelativePosition aLowerRight(
329 RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_BOTTOM_RIGHT ));
331 // Do not grow, if this leads to corners being off-screen
332 if( fAmountX > 0.0 &&
333 ( (aUpperLeft.Primary < fPosCheckThreshold) ||
334 (aLowerRight.Primary > (1.0 - fPosCheckThreshold)) ))
335 return false;
336 if( fAmountY > 0.0 &&
337 ( (aUpperLeft.Secondary < fPosCheckThreshold) ||
338 (aLowerRight.Secondary > (1.0 - fPosCheckThreshold)) ))
339 return false;
341 // Do not shrink, if this leads to a size too small
342 if( fAmountX < 0.0 &&
343 ( aSize.Primary < fSizeCheckThreshold ))
344 return false;
345 if( fAmountY < 0.0 &&
346 ( aSize.Secondary < fSizeCheckThreshold ))
347 return false;
350 rInOutPosition = aPos;
351 rInOutSize = aSize;
352 return true;
355 bool RelativePositionHelper::moveObject(
356 chart2::RelativePosition & rInOutPosition,
357 const chart2::RelativeSize & rObjectSize,
358 double fAmountX, double fAmountY,
359 bool bCheck /* = true */ )
361 chart2::RelativePosition aPos( rInOutPosition );
362 aPos.Primary += fAmountX;
363 aPos.Secondary += fAmountY;
364 const double fPosCheckThreshold = 0.02;
366 if( bCheck )
368 chart2::RelativePosition aUpperLeft(
369 RelativePositionHelper::getReanchoredPosition( aPos, rObjectSize, drawing::Alignment_TOP_LEFT ));
370 chart2::RelativePosition aLowerRight( aUpperLeft );
371 aLowerRight.Primary += rObjectSize.Primary;
372 aLowerRight.Secondary += rObjectSize.Secondary;
374 const double fFarEdgeThreshold = 1.0 - fPosCheckThreshold;
375 if( ( fAmountX > 0.0 && (aLowerRight.Primary > fFarEdgeThreshold)) ||
376 ( fAmountX < 0.0 && (aUpperLeft.Primary < fPosCheckThreshold)) ||
377 ( fAmountY > 0.0 && (aLowerRight.Secondary > fFarEdgeThreshold)) ||
378 ( fAmountY < 0.0 && (aUpperLeft.Secondary < fPosCheckThreshold)) )
379 return false;
382 rInOutPosition = aPos;
383 return true;
386 } // namespace chart
388 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */