LibreOffice Module chart2 (master) 1
RelativePositionHelper.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
21#include <com/sun/star/chart2/RelativeSize.hpp>
22#include <com/sun/star/awt/Size.hpp>
23#include <rtl/math.hxx>
24#include <osl/diagnose.h>
25
26using namespace ::com::sun::star;
27
28namespace chart
29{
30
32 const chart2::RelativePosition & rPosition,
33 const chart2::RelativeSize & rObjectSize,
34 drawing::Alignment aNewAnchor )
35{
36 chart2::RelativePosition aResult( rPosition );
37 if( rPosition.Anchor != aNewAnchor )
38 {
39 sal_Int32 nShiftHalfWidths = 0;
40 sal_Int32 nShiftHalfHeights = 0;
41
42 // normalize to top-left
43 switch( rPosition.Anchor )
44 {
45 case drawing::Alignment_TOP_LEFT:
46 break;
47 case drawing::Alignment_LEFT:
48 nShiftHalfHeights -= 1;
49 break;
50 case drawing::Alignment_BOTTOM_LEFT:
51 nShiftHalfHeights -= 2;
52 break;
53 case drawing::Alignment_TOP:
54 nShiftHalfWidths -= 1;
55 break;
56 case drawing::Alignment_CENTER:
57 nShiftHalfWidths -= 1;
58 nShiftHalfHeights -= 1;
59 break;
60 case drawing::Alignment_BOTTOM:
61 nShiftHalfWidths -= 1;
62 nShiftHalfHeights -= 2;
63 break;
64 case drawing::Alignment_TOP_RIGHT:
65 nShiftHalfWidths -= 2;
66 break;
67 case drawing::Alignment_RIGHT:
68 nShiftHalfWidths -= 2;
69 nShiftHalfHeights -= 1;
70 break;
71 case drawing::Alignment_BOTTOM_RIGHT:
72 nShiftHalfWidths -= 2;
73 nShiftHalfHeights -= 2;
74 break;
75 case drawing::Alignment::Alignment_MAKE_FIXED_SIZE:
76 break;
77 }
78
79 // transform
80 switch( aNewAnchor )
81 {
82 case drawing::Alignment_TOP_LEFT:
83 break;
84 case drawing::Alignment_LEFT:
85 nShiftHalfHeights += 1;
86 break;
87 case drawing::Alignment_BOTTOM_LEFT:
88 nShiftHalfHeights += 2;
89 break;
90 case drawing::Alignment_TOP:
91 nShiftHalfWidths += 1;
92 break;
93 case drawing::Alignment_CENTER:
94 nShiftHalfWidths += 1;
95 nShiftHalfHeights += 1;
96 break;
97 case drawing::Alignment_BOTTOM:
98 nShiftHalfWidths += 1;
99 nShiftHalfHeights += 2;
100 break;
101 case drawing::Alignment_TOP_RIGHT:
102 nShiftHalfWidths += 2;
103 break;
104 case drawing::Alignment_RIGHT:
105 nShiftHalfWidths += 2;
106 nShiftHalfHeights += 1;
107 break;
108 case drawing::Alignment_BOTTOM_RIGHT:
109 nShiftHalfWidths += 2;
110 nShiftHalfHeights += 2;
111 break;
112 case drawing::Alignment::Alignment_MAKE_FIXED_SIZE:
113 break;
114 }
115
116 if( nShiftHalfWidths != 0 )
117 aResult.Primary += (rObjectSize.Primary / 2.0) * nShiftHalfWidths;
118 if( nShiftHalfHeights != 0 )
119 aResult.Secondary += (rObjectSize.Secondary / 2.0) * nShiftHalfHeights;
120 }
121
122 return aResult;
123}
124
126 awt::Point aPoint
127 , awt::Size aObjectSize
128 , drawing::Alignment aAnchor )
129{
130 awt::Point aResult( aPoint );
131
132 double fXDelta = 0.0;
133 double fYDelta = 0.0;
134
135 // adapt x-value
136 switch( aAnchor )
137 {
138 case drawing::Alignment_TOP:
139 case drawing::Alignment_CENTER:
140 case drawing::Alignment_BOTTOM:
141 fXDelta -= static_cast< double >( aObjectSize.Width ) / 2.0;
142 break;
143 case drawing::Alignment_TOP_RIGHT:
144 case drawing::Alignment_RIGHT:
145 case drawing::Alignment_BOTTOM_RIGHT:
146 fXDelta -= aObjectSize.Width;
147 break;
148 case drawing::Alignment_TOP_LEFT:
149 case drawing::Alignment_LEFT:
150 case drawing::Alignment_BOTTOM_LEFT:
151 default:
152 // nothing to do
153 break;
154 }
155
156 // adapt y-value
157 switch( aAnchor )
158 {
159 case drawing::Alignment_LEFT:
160 case drawing::Alignment_CENTER:
161 case drawing::Alignment_RIGHT:
162 fYDelta -= static_cast< double >( aObjectSize.Height ) / 2.0;
163 break;
164 case drawing::Alignment_BOTTOM_LEFT:
165 case drawing::Alignment_BOTTOM:
166 case drawing::Alignment_BOTTOM_RIGHT:
167 fYDelta -= aObjectSize.Height;
168 break;
169 case drawing::Alignment_TOP_LEFT:
170 case drawing::Alignment_TOP:
171 case drawing::Alignment_TOP_RIGHT:
172 default:
173 // nothing to do
174 break;
175 }
176
177 aResult.X += static_cast< sal_Int32 >( ::rtl::math::round( fXDelta ));
178 aResult.Y += static_cast< sal_Int32 >( ::rtl::math::round( fYDelta ));
179
180 return aResult;
181}
182
184 awt::Point aPoint
185 , awt::Size aUnrotatedObjectSize
186 , drawing::Alignment aAnchor
187 , double fAnglePi )
188{
189 awt::Point aResult( aPoint );
190
191 double fXDelta = 0.0;
192 double fYDelta = 0.0;
193
194 // adapt x-value
195 switch( aAnchor )
196 {
197 case drawing::Alignment_TOP:
198 case drawing::Alignment_CENTER:
199 case drawing::Alignment_BOTTOM:
200 // nothing to do
201 break;
202 case drawing::Alignment_TOP_RIGHT:
203 case drawing::Alignment_RIGHT:
204 case drawing::Alignment_BOTTOM_RIGHT:
205 fXDelta -= aUnrotatedObjectSize.Width/2;
206 break;
207 case drawing::Alignment_TOP_LEFT:
208 case drawing::Alignment_LEFT:
209 case drawing::Alignment_BOTTOM_LEFT:
210 default:
211 fXDelta += aUnrotatedObjectSize.Width/2;
212 break;
213 }
214
215 // adapt y-value
216 switch( aAnchor )
217 {
218 case drawing::Alignment_LEFT:
219 case drawing::Alignment_CENTER:
220 case drawing::Alignment_RIGHT:
221 // nothing to do
222 break;
223 case drawing::Alignment_BOTTOM_LEFT:
224 case drawing::Alignment_BOTTOM:
225 case drawing::Alignment_BOTTOM_RIGHT:
226 fYDelta -= aUnrotatedObjectSize.Height/2;
227 break;
228 case drawing::Alignment_TOP_LEFT:
229 case drawing::Alignment_TOP:
230 case drawing::Alignment_TOP_RIGHT:
231 fYDelta += aUnrotatedObjectSize.Height/2;
232 break;
233 default:
234 // nothing to do
235 break;
236 }
237
238 //take rotation into account:
239 aResult.X += static_cast< sal_Int32 >(
240 ::rtl::math::round( fXDelta * std::cos( fAnglePi ) + fYDelta * std::sin( fAnglePi ) ) );
241 aResult.Y += static_cast< sal_Int32 >(
242 ::rtl::math::round( - fXDelta * std::sin( fAnglePi ) + fYDelta * std::cos( fAnglePi ) ) );
243
244 return aResult;
245}
246
248 chart2::RelativePosition & rInOutPosition,
249 chart2::RelativeSize & rInOutSize,
250 double fAmountX, double fAmountY )
251{
252 chart2::RelativePosition aPos( rInOutPosition );
253 chart2::RelativeSize aSize( rInOutSize );
254 const double fPosCheckThreshold = 0.02;
255 const double fSizeCheckThreshold = 0.1;
256
257 // grow/shrink, back to relative
258 aSize.Primary += fAmountX;
259 aSize.Secondary += fAmountY;
260
261 double fShiftAmountX = fAmountX / 2.0;
262 double fShiftAmountY = fAmountY / 2.0;
263
264 // shift X
265 switch( rInOutPosition.Anchor )
266 {
267 case drawing::Alignment_TOP_LEFT:
268 case drawing::Alignment_LEFT:
269 case drawing::Alignment_BOTTOM_LEFT:
270 aPos.Primary -= fShiftAmountX;
271 break;
272 case drawing::Alignment_TOP:
273 case drawing::Alignment_CENTER:
274 case drawing::Alignment_BOTTOM:
275 // nothing
276 break;
277 case drawing::Alignment_TOP_RIGHT:
278 case drawing::Alignment_RIGHT:
279 case drawing::Alignment_BOTTOM_RIGHT:
280 aPos.Primary += fShiftAmountX;
281 break;
282 case drawing::Alignment::Alignment_MAKE_FIXED_SIZE:
283 break;
284 }
285
286 // shift Y
287 switch( rInOutPosition.Anchor )
288 {
289 case drawing::Alignment_TOP:
290 case drawing::Alignment_TOP_LEFT:
291 case drawing::Alignment_TOP_RIGHT:
292 aPos.Secondary -= fShiftAmountY;
293 break;
294 case drawing::Alignment_CENTER:
295 case drawing::Alignment_LEFT:
296 case drawing::Alignment_RIGHT:
297 // nothing
298 break;
299 case drawing::Alignment_BOTTOM:
300 case drawing::Alignment_BOTTOM_LEFT:
301 case drawing::Alignment_BOTTOM_RIGHT:
302 aPos.Secondary += fShiftAmountY;
303 break;
304 case drawing::Alignment::Alignment_MAKE_FIXED_SIZE:
305 break;
306 }
307
308 // anchor must not be changed
309 OSL_ASSERT( rInOutPosition.Anchor == aPos.Anchor );
310
311 if( rInOutPosition.Primary == aPos.Primary &&
312 rInOutPosition.Secondary == aPos.Secondary &&
313 rInOutSize.Primary == aSize.Primary &&
314 rInOutSize.Secondary == aSize.Secondary )
315 return false;
316
317 // Note: this somewhat complicated check allows the output being
318 // out-of-bounds if the input was also out-of-bounds, and the change is
319 // for "advantage". E.g., you have a chart that laps out on the left
320 // side. If you shrink it, this should be possible, also if it still
321 // laps out on the left side afterwards. But you shouldn't be able to
322 // grow it then.
323
324 chart2::RelativePosition aUpperLeft(
325 RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_TOP_LEFT ));
326 chart2::RelativePosition aLowerRight(
327 RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_BOTTOM_RIGHT ));
328
329 // Do not grow, if this leads to corners being off-screen
330 if( fAmountX > 0.0 &&
331 ( (aUpperLeft.Primary < fPosCheckThreshold) ||
332 (aLowerRight.Primary > (1.0 - fPosCheckThreshold)) ))
333 return false;
334 if( fAmountY > 0.0 &&
335 ( (aUpperLeft.Secondary < fPosCheckThreshold) ||
336 (aLowerRight.Secondary > (1.0 - fPosCheckThreshold)) ))
337 return false;
338
339 // Do not shrink, if this leads to a size too small
340 if( fAmountX < 0.0 &&
341 ( aSize.Primary < fSizeCheckThreshold ))
342 return false;
343 if( fAmountY < 0.0 &&
344 ( aSize.Secondary < fSizeCheckThreshold ))
345 return false;
346
347 rInOutPosition = aPos;
348 rInOutSize = aSize;
349 return true;
350}
351
353 chart2::RelativePosition & rInOutPosition,
354 const chart2::RelativeSize & rObjectSize,
355 double fAmountX, double fAmountY )
356{
357 chart2::RelativePosition aPos( rInOutPosition );
358 aPos.Primary += fAmountX;
359 aPos.Secondary += fAmountY;
360 const double fPosCheckThreshold = 0.02;
361
362 chart2::RelativePosition aUpperLeft(
363 RelativePositionHelper::getReanchoredPosition( aPos, rObjectSize, drawing::Alignment_TOP_LEFT ));
364 chart2::RelativePosition aLowerRight( aUpperLeft );
365 aLowerRight.Primary += rObjectSize.Primary;
366 aLowerRight.Secondary += rObjectSize.Secondary;
367
368 const double fFarEdgeThreshold = 1.0 - fPosCheckThreshold;
369 if( ( fAmountX > 0.0 && (aLowerRight.Primary > fFarEdgeThreshold)) ||
370 ( fAmountX < 0.0 && (aUpperLeft.Primary < fPosCheckThreshold)) ||
371 ( fAmountY > 0.0 && (aLowerRight.Secondary > fFarEdgeThreshold)) ||
372 ( fAmountY < 0.0 && (aUpperLeft.Secondary < fPosCheckThreshold)) )
373 return false;
374
375 rInOutPosition = aPos;
376 return true;
377}
378
379} // namespace chart
380
381/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static css::awt::Point getUpperLeftCornerOfAnchoredObject(css::awt::Point aPoint, css::awt::Size aObjectSize, css::drawing::Alignment aAnchor)
returns the upper left corner of an object that has size aObjectSize and where the point indicated by...
static bool centerGrow(css::chart2::RelativePosition &rInOutPosition, css::chart2::RelativeSize &rInOutSize, double fAmountX, double fAmountY)
grows a relative size about the given amount and shifts the given position such that the resize is re...
static css::awt::Point getCenterOfAnchoredObject(css::awt::Point aPoint, css::awt::Size aUnrotatedObjectSize, css::drawing::Alignment aAnchor, double fAnglePi)
returns the center of an object that has size aObjectSize and where the point indicated by aAnchor ha...
static bool moveObject(css::chart2::RelativePosition &rInOutPosition, const css::chart2::RelativeSize &rObjectSize, double fAmountX, double fAmountY)
shifts a relative position about the given amount
static SAL_DLLPRIVATE css::chart2::RelativePosition getReanchoredPosition(const css::chart2::RelativePosition &rPosition, const css::chart2::RelativeSize &rObjectSize, css::drawing::Alignment aNewAnchor)
Returns a relative position that is the same point after the anchor has been changed to the given one...