bump product version to 5.0.4.1
[LibreOffice.git] / chart2 / source / tools / RelativePositionHelper.cxx
blob233bc986346e201f1ea633c7c151122c83145d0e
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 .
20 #include "RelativePositionHelper.hxx"
21 #include <rtl/math.hxx>
22 #include <osl/diagnose.h>
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;
123 awt::Point RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
124 awt::Point aPoint
125 , awt::Size aObjectSize
126 , drawing::Alignment aAnchor )
128 awt::Point aResult( aPoint );
130 double fXDelta = 0.0;
131 double fYDelta = 0.0;
133 // adapt x-value
134 switch( aAnchor )
136 case drawing::Alignment_TOP:
137 case drawing::Alignment_CENTER:
138 case drawing::Alignment_BOTTOM:
139 fXDelta -= static_cast< double >( aObjectSize.Width ) / 2.0;
140 break;
141 case drawing::Alignment_TOP_RIGHT:
142 case drawing::Alignment_RIGHT:
143 case drawing::Alignment_BOTTOM_RIGHT:
144 fXDelta -= aObjectSize.Width;
145 break;
146 case drawing::Alignment_TOP_LEFT:
147 case drawing::Alignment_LEFT:
148 case drawing::Alignment_BOTTOM_LEFT:
149 default:
150 // nothing to do
151 break;
154 // adapt y-value
155 switch( aAnchor )
157 case drawing::Alignment_LEFT:
158 case drawing::Alignment_CENTER:
159 case drawing::Alignment_RIGHT:
160 fYDelta -= static_cast< double >( aObjectSize.Height ) / 2.0;
161 break;
162 case drawing::Alignment_BOTTOM_LEFT:
163 case drawing::Alignment_BOTTOM:
164 case drawing::Alignment_BOTTOM_RIGHT:
165 fYDelta -= aObjectSize.Height;
166 break;
167 case drawing::Alignment_TOP_LEFT:
168 case drawing::Alignment_TOP:
169 case drawing::Alignment_TOP_RIGHT:
170 default:
171 // nothing to do
172 break;
175 aResult.X += static_cast< sal_Int32 >( ::rtl::math::round( fXDelta ));
176 aResult.Y += static_cast< sal_Int32 >( ::rtl::math::round( fYDelta ));
178 return aResult;
181 awt::Point RelativePositionHelper::getCenterOfAnchoredObject(
182 awt::Point aPoint
183 , awt::Size aUnrotatedObjectSize
184 , drawing::Alignment aAnchor
185 , double fAnglePi )
187 awt::Point aResult( aPoint );
189 double fXDelta = 0.0;
190 double fYDelta = 0.0;
192 // adapt x-value
193 switch( aAnchor )
195 case drawing::Alignment_TOP:
196 case drawing::Alignment_CENTER:
197 case drawing::Alignment_BOTTOM:
198 // nothing to do
199 break;
200 case drawing::Alignment_TOP_RIGHT:
201 case drawing::Alignment_RIGHT:
202 case drawing::Alignment_BOTTOM_RIGHT:
203 fXDelta -= aUnrotatedObjectSize.Width/2;
204 break;
205 case drawing::Alignment_TOP_LEFT:
206 case drawing::Alignment_LEFT:
207 case drawing::Alignment_BOTTOM_LEFT:
208 default:
209 fXDelta += aUnrotatedObjectSize.Width/2;
210 break;
213 // adapt y-value
214 switch( aAnchor )
216 case drawing::Alignment_LEFT:
217 case drawing::Alignment_CENTER:
218 case drawing::Alignment_RIGHT:
219 // nothing to do
220 break;
221 case drawing::Alignment_BOTTOM_LEFT:
222 case drawing::Alignment_BOTTOM:
223 case drawing::Alignment_BOTTOM_RIGHT:
224 fYDelta -= aUnrotatedObjectSize.Height/2;
225 break;
226 case drawing::Alignment_TOP_LEFT:
227 case drawing::Alignment_TOP:
228 case drawing::Alignment_TOP_RIGHT:
229 fYDelta += aUnrotatedObjectSize.Height/2;
230 default:
231 // nothing to do
232 break;
235 //take rotation into account:
236 aResult.X += static_cast< sal_Int32 >(
237 ::rtl::math::round( fXDelta * rtl::math::cos( fAnglePi ) + fYDelta * rtl::math::sin( fAnglePi ) ) );
238 aResult.Y += static_cast< sal_Int32 >(
239 ::rtl::math::round( - fXDelta * rtl::math::sin( fAnglePi ) + fYDelta * rtl::math::cos( fAnglePi ) ) );
241 return aResult;
244 bool RelativePositionHelper::centerGrow(
245 chart2::RelativePosition & rInOutPosition,
246 chart2::RelativeSize & rInOutSize,
247 double fAmountX, double fAmountY,
248 bool bCheck /* = true */ )
250 chart2::RelativePosition aPos( rInOutPosition );
251 chart2::RelativeSize aSize( rInOutSize );
252 const double fPosCheckThreshold = 0.02;
253 const double fSizeCheckThreshold = 0.1;
255 // grow/shrink, back to relaative
256 aSize.Primary += fAmountX;
257 aSize.Secondary += fAmountY;
259 double fShiftAmountX = fAmountX / 2.0;
260 double fShiftAmountY = fAmountY / 2.0;
262 // shift X
263 switch( rInOutPosition.Anchor )
265 case drawing::Alignment_TOP_LEFT:
266 case drawing::Alignment_LEFT:
267 case drawing::Alignment_BOTTOM_LEFT:
268 aPos.Primary -= fShiftAmountX;
269 break;
270 case drawing::Alignment_TOP:
271 case drawing::Alignment_CENTER:
272 case drawing::Alignment_BOTTOM:
273 // nothing
274 break;
275 case drawing::Alignment_TOP_RIGHT:
276 case drawing::Alignment_RIGHT:
277 case drawing::Alignment_BOTTOM_RIGHT:
278 aPos.Primary += fShiftAmountX;
279 break;
280 case drawing::Alignment_MAKE_FIXED_SIZE:
281 break;
284 // shift Y
285 switch( rInOutPosition.Anchor )
287 case drawing::Alignment_TOP:
288 case drawing::Alignment_TOP_LEFT:
289 case drawing::Alignment_TOP_RIGHT:
290 aPos.Secondary -= fShiftAmountY;
291 break;
292 case drawing::Alignment_CENTER:
293 case drawing::Alignment_LEFT:
294 case drawing::Alignment_RIGHT:
295 // nothing
296 break;
297 case drawing::Alignment_BOTTOM:
298 case drawing::Alignment_BOTTOM_LEFT:
299 case drawing::Alignment_BOTTOM_RIGHT:
300 aPos.Secondary += fShiftAmountY;
301 break;
302 case drawing::Alignment_MAKE_FIXED_SIZE:
303 break;
306 // anchor must not be changed
307 OSL_ASSERT( rInOutPosition.Anchor == aPos.Anchor );
309 if( rInOutPosition.Primary == aPos.Primary &&
310 rInOutPosition.Secondary == aPos.Secondary &&
311 rInOutSize.Primary == aSize.Primary &&
312 rInOutSize.Secondary == aSize.Secondary )
313 return false;
315 // check
316 if( bCheck )
318 // Note: this somewhat complicated check allows the output being
319 // out-of-bounds if the input was also out-of-bounds, and the change is
320 // for "advantage". E.g., you have a chart that laps out on the left
321 // side. If you shrink it, this should be possible, also if it still
322 // laps out on the left side afterwards. But you shouldn't be able to
323 // grow it then.
325 chart2::RelativePosition aUpperLeft(
326 RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_TOP_LEFT ));
327 chart2::RelativePosition aLowerRight(
328 RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_BOTTOM_RIGHT ));
330 // Do not grow, if this leads to corners being off-screen
331 if( fAmountX > 0.0 &&
332 ( (aUpperLeft.Primary < fPosCheckThreshold) ||
333 (aLowerRight.Primary > (1.0 - fPosCheckThreshold)) ))
334 return false;
335 if( fAmountY > 0.0 &&
336 ( (aUpperLeft.Secondary < fPosCheckThreshold) ||
337 (aLowerRight.Secondary > (1.0 - fPosCheckThreshold)) ))
338 return false;
340 // Do not shrink, if this leads to a size too small
341 if( fAmountX < 0.0 &&
342 ( aSize.Primary < fSizeCheckThreshold ))
343 return false;
344 if( fAmountY < 0.0 &&
345 ( aSize.Secondary < fSizeCheckThreshold ))
346 return false;
349 rInOutPosition = aPos;
350 rInOutSize = aSize;
351 return true;
354 bool RelativePositionHelper::moveObject(
355 chart2::RelativePosition & rInOutPosition,
356 const chart2::RelativeSize & rObjectSize,
357 double fAmountX, double fAmountY,
358 bool bCheck /* = true */ )
360 chart2::RelativePosition aPos( rInOutPosition );
361 aPos.Primary += fAmountX;
362 aPos.Secondary += fAmountY;
363 const double fPosCheckThreshold = 0.02;
365 if( bCheck )
367 chart2::RelativePosition aUpperLeft(
368 RelativePositionHelper::getReanchoredPosition( aPos, rObjectSize, drawing::Alignment_TOP_LEFT ));
369 chart2::RelativePosition aLowerRight( aUpperLeft );
370 aLowerRight.Primary += rObjectSize.Primary;
371 aLowerRight.Secondary += rObjectSize.Secondary;
373 const double fFarEdgeThreshold = 1.0 - fPosCheckThreshold;
374 if( ( fAmountX > 0.0 && (aLowerRight.Primary > fFarEdgeThreshold)) ||
375 ( fAmountX < 0.0 && (aUpperLeft.Primary < fPosCheckThreshold)) ||
376 ( fAmountY > 0.0 && (aLowerRight.Secondary > fFarEdgeThreshold)) ||
377 ( fAmountY < 0.0 && (aUpperLeft.Secondary < fPosCheckThreshold)) )
378 return false;
381 rInOutPosition = aPos;
382 return true;
385 } // namespace chart
387 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */