Line data Source code
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 :
20 : #include "RelativePositionHelper.hxx"
21 : #include <rtl/math.hxx>
22 : #include <osl/diagnose.h>
23 :
24 : using namespace ::com::sun::star;
25 :
26 : namespace chart
27 : {
28 :
29 0 : chart2::RelativePosition RelativePositionHelper::getReanchoredPosition(
30 : const chart2::RelativePosition & rPosition,
31 : const chart2::RelativeSize & rObjectSize,
32 : drawing::Alignment aNewAnchor )
33 : {
34 0 : chart2::RelativePosition aResult( rPosition );
35 0 : if( rPosition.Anchor != aNewAnchor )
36 : {
37 0 : sal_Int32 nShiftHalfWidths = 0;
38 0 : sal_Int32 nShiftHalfHeights = 0;
39 :
40 : // normalize to top-left
41 0 : switch( rPosition.Anchor )
42 : {
43 : case drawing::Alignment_TOP_LEFT:
44 0 : break;
45 : case drawing::Alignment_LEFT:
46 0 : nShiftHalfHeights -= 1;
47 0 : break;
48 : case drawing::Alignment_BOTTOM_LEFT:
49 0 : nShiftHalfHeights -= 2;
50 0 : break;
51 : case drawing::Alignment_TOP:
52 0 : nShiftHalfWidths -= 1;
53 0 : break;
54 : case drawing::Alignment_CENTER:
55 0 : nShiftHalfWidths -= 1;
56 0 : nShiftHalfHeights -= 1;
57 0 : break;
58 : case drawing::Alignment_BOTTOM:
59 0 : nShiftHalfWidths -= 1;
60 0 : nShiftHalfHeights -= 2;
61 0 : break;
62 : case drawing::Alignment_TOP_RIGHT:
63 0 : nShiftHalfWidths -= 2;
64 0 : break;
65 : case drawing::Alignment_RIGHT:
66 0 : nShiftHalfWidths -= 2;
67 0 : nShiftHalfHeights -= 1;
68 0 : break;
69 : case drawing::Alignment_BOTTOM_RIGHT:
70 0 : nShiftHalfWidths -= 2;
71 0 : nShiftHalfHeights -= 2;
72 0 : break;
73 : case drawing::Alignment_MAKE_FIXED_SIZE:
74 0 : break;
75 : }
76 :
77 : // transform
78 0 : switch( aNewAnchor )
79 : {
80 : case drawing::Alignment_TOP_LEFT:
81 0 : break;
82 : case drawing::Alignment_LEFT:
83 0 : nShiftHalfHeights += 1;
84 0 : break;
85 : case drawing::Alignment_BOTTOM_LEFT:
86 0 : nShiftHalfHeights += 2;
87 0 : break;
88 : case drawing::Alignment_TOP:
89 0 : nShiftHalfWidths += 1;
90 0 : break;
91 : case drawing::Alignment_CENTER:
92 0 : nShiftHalfWidths += 1;
93 0 : nShiftHalfHeights += 1;
94 0 : break;
95 : case drawing::Alignment_BOTTOM:
96 0 : nShiftHalfWidths += 1;
97 0 : nShiftHalfHeights += 2;
98 0 : break;
99 : case drawing::Alignment_TOP_RIGHT:
100 0 : nShiftHalfWidths += 2;
101 0 : break;
102 : case drawing::Alignment_RIGHT:
103 0 : nShiftHalfWidths += 2;
104 0 : nShiftHalfHeights += 1;
105 0 : break;
106 : case drawing::Alignment_BOTTOM_RIGHT:
107 0 : nShiftHalfWidths += 2;
108 0 : nShiftHalfHeights += 2;
109 0 : break;
110 : case drawing::Alignment_MAKE_FIXED_SIZE:
111 0 : break;
112 : }
113 :
114 0 : if( nShiftHalfWidths != 0 )
115 0 : aResult.Primary += (rObjectSize.Primary / 2.0) * nShiftHalfWidths;
116 0 : if( nShiftHalfHeights != 0 )
117 0 : aResult.Secondary += (rObjectSize.Secondary / 2.0) * nShiftHalfHeights;
118 : }
119 :
120 0 : return aResult;
121 : }
122 :
123 1538 : awt::Point RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
124 : awt::Point aPoint
125 : , awt::Size aObjectSize
126 : , drawing::Alignment aAnchor )
127 : {
128 1538 : awt::Point aResult( aPoint );
129 :
130 1538 : double fXDelta = 0.0;
131 1538 : double fYDelta = 0.0;
132 :
133 : // adapt x-value
134 1538 : switch( aAnchor )
135 : {
136 : case drawing::Alignment_TOP:
137 : case drawing::Alignment_CENTER:
138 : case drawing::Alignment_BOTTOM:
139 40 : fXDelta -= static_cast< double >( aObjectSize.Width ) / 2.0;
140 40 : break;
141 : case drawing::Alignment_TOP_RIGHT:
142 : case drawing::Alignment_RIGHT:
143 : case drawing::Alignment_BOTTOM_RIGHT:
144 886 : fXDelta -= aObjectSize.Width;
145 886 : 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 612 : break;
152 : }
153 :
154 : // adapt y-value
155 1538 : switch( aAnchor )
156 : {
157 : case drawing::Alignment_LEFT:
158 : case drawing::Alignment_CENTER:
159 : case drawing::Alignment_RIGHT:
160 889 : fYDelta -= static_cast< double >( aObjectSize.Height ) / 2.0;
161 889 : break;
162 : case drawing::Alignment_BOTTOM_LEFT:
163 : case drawing::Alignment_BOTTOM:
164 : case drawing::Alignment_BOTTOM_RIGHT:
165 37 : fYDelta -= aObjectSize.Height;
166 37 : 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 612 : break;
173 : }
174 :
175 1538 : aResult.X += static_cast< sal_Int32 >( ::rtl::math::round( fXDelta ));
176 1538 : aResult.Y += static_cast< sal_Int32 >( ::rtl::math::round( fYDelta ));
177 :
178 1538 : return aResult;
179 : }
180 :
181 593 : awt::Point RelativePositionHelper::getCenterOfAnchoredObject(
182 : awt::Point aPoint
183 : , awt::Size aUnrotatedObjectSize
184 : , drawing::Alignment aAnchor
185 : , double fAnglePi )
186 : {
187 593 : awt::Point aResult( aPoint );
188 :
189 593 : double fXDelta = 0.0;
190 593 : double fYDelta = 0.0;
191 :
192 : // adapt x-value
193 593 : switch( aAnchor )
194 : {
195 : case drawing::Alignment_TOP:
196 : case drawing::Alignment_CENTER:
197 : case drawing::Alignment_BOTTOM:
198 : // nothing to do
199 0 : break;
200 : case drawing::Alignment_TOP_RIGHT:
201 : case drawing::Alignment_RIGHT:
202 : case drawing::Alignment_BOTTOM_RIGHT:
203 0 : fXDelta -= aUnrotatedObjectSize.Width/2;
204 0 : break;
205 : case drawing::Alignment_TOP_LEFT:
206 : case drawing::Alignment_LEFT:
207 : case drawing::Alignment_BOTTOM_LEFT:
208 : default:
209 593 : fXDelta += aUnrotatedObjectSize.Width/2;
210 593 : break;
211 : }
212 :
213 : // adapt y-value
214 593 : switch( aAnchor )
215 : {
216 : case drawing::Alignment_LEFT:
217 : case drawing::Alignment_CENTER:
218 : case drawing::Alignment_RIGHT:
219 : // nothing to do
220 0 : break;
221 : case drawing::Alignment_BOTTOM_LEFT:
222 : case drawing::Alignment_BOTTOM:
223 : case drawing::Alignment_BOTTOM_RIGHT:
224 0 : fYDelta -= aUnrotatedObjectSize.Height/2;
225 0 : break;
226 : case drawing::Alignment_TOP_LEFT:
227 : case drawing::Alignment_TOP:
228 : case drawing::Alignment_TOP_RIGHT:
229 593 : fYDelta += aUnrotatedObjectSize.Height/2;
230 : default:
231 : // nothing to do
232 593 : break;
233 : }
234 :
235 : //take rotation into account:
236 : aResult.X += static_cast< sal_Int32 >(
237 593 : ::rtl::math::round( fXDelta * rtl::math::cos( fAnglePi ) + fYDelta * rtl::math::sin( fAnglePi ) ) );
238 : aResult.Y += static_cast< sal_Int32 >(
239 593 : ::rtl::math::round( - fXDelta * rtl::math::sin( fAnglePi ) + fYDelta * rtl::math::cos( fAnglePi ) ) );
240 :
241 593 : return aResult;
242 : }
243 :
244 0 : bool RelativePositionHelper::centerGrow(
245 : chart2::RelativePosition & rInOutPosition,
246 : chart2::RelativeSize & rInOutSize,
247 : double fAmountX, double fAmountY,
248 : bool bCheck /* = true */ )
249 : {
250 0 : chart2::RelativePosition aPos( rInOutPosition );
251 0 : chart2::RelativeSize aSize( rInOutSize );
252 0 : const double fPosCheckThreshold = 0.02;
253 0 : const double fSizeCheckThreshold = 0.1;
254 :
255 : // grow/shrink, back to relaative
256 0 : aSize.Primary += fAmountX;
257 0 : aSize.Secondary += fAmountY;
258 :
259 0 : double fShiftAmountX = fAmountX / 2.0;
260 0 : double fShiftAmountY = fAmountY / 2.0;
261 :
262 : // shift X
263 0 : switch( rInOutPosition.Anchor )
264 : {
265 : case drawing::Alignment_TOP_LEFT:
266 : case drawing::Alignment_LEFT:
267 : case drawing::Alignment_BOTTOM_LEFT:
268 0 : aPos.Primary -= fShiftAmountX;
269 0 : break;
270 : case drawing::Alignment_TOP:
271 : case drawing::Alignment_CENTER:
272 : case drawing::Alignment_BOTTOM:
273 : // nothing
274 0 : break;
275 : case drawing::Alignment_TOP_RIGHT:
276 : case drawing::Alignment_RIGHT:
277 : case drawing::Alignment_BOTTOM_RIGHT:
278 0 : aPos.Primary += fShiftAmountX;
279 0 : break;
280 : case drawing::Alignment_MAKE_FIXED_SIZE:
281 0 : break;
282 : }
283 :
284 : // shift Y
285 0 : switch( rInOutPosition.Anchor )
286 : {
287 : case drawing::Alignment_TOP:
288 : case drawing::Alignment_TOP_LEFT:
289 : case drawing::Alignment_TOP_RIGHT:
290 0 : aPos.Secondary -= fShiftAmountY;
291 0 : break;
292 : case drawing::Alignment_CENTER:
293 : case drawing::Alignment_LEFT:
294 : case drawing::Alignment_RIGHT:
295 : // nothing
296 0 : break;
297 : case drawing::Alignment_BOTTOM:
298 : case drawing::Alignment_BOTTOM_LEFT:
299 : case drawing::Alignment_BOTTOM_RIGHT:
300 0 : aPos.Secondary += fShiftAmountY;
301 0 : break;
302 : case drawing::Alignment_MAKE_FIXED_SIZE:
303 0 : break;
304 : }
305 :
306 : // anchor must not be changed
307 : OSL_ASSERT( rInOutPosition.Anchor == aPos.Anchor );
308 :
309 0 : if( rInOutPosition.Primary == aPos.Primary &&
310 0 : rInOutPosition.Secondary == aPos.Secondary &&
311 0 : rInOutSize.Primary == aSize.Primary &&
312 0 : rInOutSize.Secondary == aSize.Secondary )
313 0 : return false;
314 :
315 : // check
316 0 : if( bCheck )
317 : {
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.
324 :
325 : chart2::RelativePosition aUpperLeft(
326 0 : RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_TOP_LEFT ));
327 : chart2::RelativePosition aLowerRight(
328 0 : RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_BOTTOM_RIGHT ));
329 :
330 : // Do not grow, if this leads to corners being off-screen
331 0 : if( fAmountX > 0.0 &&
332 0 : ( (aUpperLeft.Primary < fPosCheckThreshold) ||
333 0 : (aLowerRight.Primary > (1.0 - fPosCheckThreshold)) ))
334 0 : return false;
335 0 : if( fAmountY > 0.0 &&
336 0 : ( (aUpperLeft.Secondary < fPosCheckThreshold) ||
337 0 : (aLowerRight.Secondary > (1.0 - fPosCheckThreshold)) ))
338 0 : return false;
339 :
340 : // Do not shrink, if this leads to a size too small
341 0 : if( fAmountX < 0.0 &&
342 0 : ( aSize.Primary < fSizeCheckThreshold ))
343 0 : return false;
344 0 : if( fAmountY < 0.0 &&
345 0 : ( aSize.Secondary < fSizeCheckThreshold ))
346 0 : return false;
347 : }
348 :
349 0 : rInOutPosition = aPos;
350 0 : rInOutSize = aSize;
351 0 : return true;
352 : }
353 :
354 0 : bool RelativePositionHelper::moveObject(
355 : chart2::RelativePosition & rInOutPosition,
356 : const chart2::RelativeSize & rObjectSize,
357 : double fAmountX, double fAmountY,
358 : bool bCheck /* = true */ )
359 : {
360 0 : chart2::RelativePosition aPos( rInOutPosition );
361 0 : aPos.Primary += fAmountX;
362 0 : aPos.Secondary += fAmountY;
363 0 : const double fPosCheckThreshold = 0.02;
364 :
365 0 : if( bCheck )
366 : {
367 : chart2::RelativePosition aUpperLeft(
368 0 : RelativePositionHelper::getReanchoredPosition( aPos, rObjectSize, drawing::Alignment_TOP_LEFT ));
369 0 : chart2::RelativePosition aLowerRight( aUpperLeft );
370 0 : aLowerRight.Primary += rObjectSize.Primary;
371 0 : aLowerRight.Secondary += rObjectSize.Secondary;
372 :
373 0 : const double fFarEdgeThreshold = 1.0 - fPosCheckThreshold;
374 0 : if( ( fAmountX > 0.0 && (aLowerRight.Primary > fFarEdgeThreshold)) ||
375 0 : ( fAmountX < 0.0 && (aUpperLeft.Primary < fPosCheckThreshold)) ||
376 0 : ( fAmountY > 0.0 && (aLowerRight.Secondary > fFarEdgeThreshold)) ||
377 0 : ( fAmountY < 0.0 && (aUpperLeft.Secondary < fPosCheckThreshold)) )
378 0 : return false;
379 : }
380 :
381 0 : rInOutPosition = aPos;
382 0 : return true;
383 : }
384 :
385 : } // namespace chart
386 :
387 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|