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