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 :
21 : #include "RelativePositionHelper.hxx"
22 : #include <rtl/math.hxx>
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 :
124 41 : awt::Point RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
125 : awt::Point aPoint
126 : , awt::Size aObjectSize
127 : , drawing::Alignment aAnchor )
128 : {
129 41 : awt::Point aResult( aPoint );
130 :
131 41 : double fXDelta = 0.0;
132 41 : double fYDelta = 0.0;
133 :
134 : // adapt x-value
135 41 : switch( aAnchor )
136 : {
137 : case drawing::Alignment_TOP:
138 : case drawing::Alignment_CENTER:
139 : case drawing::Alignment_BOTTOM:
140 0 : fXDelta -= static_cast< double >( aObjectSize.Width ) / 2.0;
141 0 : break;
142 : case drawing::Alignment_TOP_RIGHT:
143 : case drawing::Alignment_RIGHT:
144 : case drawing::Alignment_BOTTOM_RIGHT:
145 41 : fXDelta -= aObjectSize.Width;
146 41 : 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 0 : break;
153 : }
154 :
155 : // adapt y-value
156 41 : switch( aAnchor )
157 : {
158 : case drawing::Alignment_LEFT:
159 : case drawing::Alignment_CENTER:
160 : case drawing::Alignment_RIGHT:
161 41 : fYDelta -= static_cast< double >( aObjectSize.Height ) / 2.0;
162 41 : break;
163 : case drawing::Alignment_BOTTOM_LEFT:
164 : case drawing::Alignment_BOTTOM:
165 : case drawing::Alignment_BOTTOM_RIGHT:
166 0 : fYDelta -= aObjectSize.Height;
167 0 : 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 0 : break;
174 : }
175 :
176 41 : aResult.X += static_cast< sal_Int32 >( ::rtl::math::round( fXDelta ));
177 41 : aResult.Y += static_cast< sal_Int32 >( ::rtl::math::round( fYDelta ));
178 :
179 41 : return aResult;
180 : }
181 :
182 0 : awt::Point RelativePositionHelper::getCenterOfAnchoredObject(
183 : awt::Point aPoint
184 : , awt::Size aUnrotatedObjectSize
185 : , drawing::Alignment aAnchor
186 : , double fAnglePi )
187 : {
188 0 : awt::Point aResult( aPoint );
189 :
190 0 : double fXDelta = 0.0;
191 0 : double fYDelta = 0.0;
192 :
193 : // adapt x-value
194 0 : switch( aAnchor )
195 : {
196 : case drawing::Alignment_TOP:
197 : case drawing::Alignment_CENTER:
198 : case drawing::Alignment_BOTTOM:
199 : // nothing to do
200 0 : break;
201 : case drawing::Alignment_TOP_RIGHT:
202 : case drawing::Alignment_RIGHT:
203 : case drawing::Alignment_BOTTOM_RIGHT:
204 0 : fXDelta -= aUnrotatedObjectSize.Width/2;
205 0 : break;
206 : case drawing::Alignment_TOP_LEFT:
207 : case drawing::Alignment_LEFT:
208 : case drawing::Alignment_BOTTOM_LEFT:
209 : default:
210 0 : fXDelta += aUnrotatedObjectSize.Width/2;
211 0 : break;
212 : }
213 :
214 : // adapt y-value
215 0 : switch( aAnchor )
216 : {
217 : case drawing::Alignment_LEFT:
218 : case drawing::Alignment_CENTER:
219 : case drawing::Alignment_RIGHT:
220 : // nothing to do
221 0 : break;
222 : case drawing::Alignment_BOTTOM_LEFT:
223 : case drawing::Alignment_BOTTOM:
224 : case drawing::Alignment_BOTTOM_RIGHT:
225 0 : fYDelta -= aUnrotatedObjectSize.Height/2;
226 0 : break;
227 : case drawing::Alignment_TOP_LEFT:
228 : case drawing::Alignment_TOP:
229 : case drawing::Alignment_TOP_RIGHT:
230 0 : fYDelta += aUnrotatedObjectSize.Height/2;
231 : default:
232 : // nothing to do
233 0 : break;
234 : }
235 :
236 : //take rotation into account:
237 : aResult.X += static_cast< sal_Int32 >(
238 0 : ::rtl::math::round( fXDelta * rtl::math::cos( fAnglePi ) + fYDelta * rtl::math::sin( fAnglePi ) ) );
239 : aResult.Y += static_cast< sal_Int32 >(
240 0 : ::rtl::math::round( - fXDelta * rtl::math::sin( fAnglePi ) + fYDelta * rtl::math::cos( fAnglePi ) ) );
241 :
242 0 : return aResult;
243 : }
244 :
245 0 : bool RelativePositionHelper::centerGrow(
246 : chart2::RelativePosition & rInOutPosition,
247 : chart2::RelativeSize & rInOutSize,
248 : double fAmountX, double fAmountY,
249 : bool bCheck /* = true */ )
250 : {
251 0 : chart2::RelativePosition aPos( rInOutPosition );
252 0 : chart2::RelativeSize aSize( rInOutSize );
253 0 : const double fPosCheckThreshold = 0.02;
254 0 : const double fSizeCheckThreshold = 0.1;
255 :
256 : // grow/shrink, back to relaative
257 0 : aSize.Primary += fAmountX;
258 0 : aSize.Secondary += fAmountY;
259 :
260 0 : double fShiftAmountX = fAmountX / 2.0;
261 0 : double fShiftAmountY = fAmountY / 2.0;
262 :
263 : // shift X
264 0 : switch( rInOutPosition.Anchor )
265 : {
266 : case drawing::Alignment_TOP_LEFT:
267 : case drawing::Alignment_LEFT:
268 : case drawing::Alignment_BOTTOM_LEFT:
269 0 : aPos.Primary -= fShiftAmountX;
270 0 : break;
271 : case drawing::Alignment_TOP:
272 : case drawing::Alignment_CENTER:
273 : case drawing::Alignment_BOTTOM:
274 : // nothing
275 0 : break;
276 : case drawing::Alignment_TOP_RIGHT:
277 : case drawing::Alignment_RIGHT:
278 : case drawing::Alignment_BOTTOM_RIGHT:
279 0 : aPos.Primary += fShiftAmountX;
280 0 : break;
281 : case drawing::Alignment_MAKE_FIXED_SIZE:
282 0 : break;
283 : }
284 :
285 : // shift Y
286 0 : switch( rInOutPosition.Anchor )
287 : {
288 : case drawing::Alignment_TOP:
289 : case drawing::Alignment_TOP_LEFT:
290 : case drawing::Alignment_TOP_RIGHT:
291 0 : aPos.Secondary -= fShiftAmountY;
292 0 : break;
293 : case drawing::Alignment_CENTER:
294 : case drawing::Alignment_LEFT:
295 : case drawing::Alignment_RIGHT:
296 : // nothing
297 0 : break;
298 : case drawing::Alignment_BOTTOM:
299 : case drawing::Alignment_BOTTOM_LEFT:
300 : case drawing::Alignment_BOTTOM_RIGHT:
301 0 : aPos.Secondary += fShiftAmountY;
302 0 : break;
303 : case drawing::Alignment_MAKE_FIXED_SIZE:
304 0 : break;
305 : }
306 :
307 : // anchor must not be changed
308 : OSL_ASSERT( rInOutPosition.Anchor == aPos.Anchor );
309 :
310 0 : if( rInOutPosition.Primary == aPos.Primary &&
311 : rInOutPosition.Secondary == aPos.Secondary &&
312 : rInOutSize.Primary == aSize.Primary &&
313 : rInOutSize.Secondary == aSize.Secondary )
314 0 : return false;
315 :
316 : // check
317 0 : if( bCheck )
318 : {
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.
325 :
326 : chart2::RelativePosition aUpperLeft(
327 0 : RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_TOP_LEFT ));
328 : chart2::RelativePosition aLowerRight(
329 0 : RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_BOTTOM_RIGHT ));
330 :
331 : // Do not grow, if this leads to corners being off-screen
332 0 : if( fAmountX > 0.0 &&
333 : ( (aUpperLeft.Primary < fPosCheckThreshold) ||
334 : (aLowerRight.Primary > (1.0 - fPosCheckThreshold)) ))
335 0 : return false;
336 0 : if( fAmountY > 0.0 &&
337 : ( (aUpperLeft.Secondary < fPosCheckThreshold) ||
338 : (aLowerRight.Secondary > (1.0 - fPosCheckThreshold)) ))
339 0 : return false;
340 :
341 : // Do not shrink, if this leads to a size too small
342 0 : if( fAmountX < 0.0 &&
343 : ( aSize.Primary < fSizeCheckThreshold ))
344 0 : return false;
345 0 : if( fAmountY < 0.0 &&
346 : ( aSize.Secondary < fSizeCheckThreshold ))
347 0 : return false;
348 : }
349 :
350 0 : rInOutPosition = aPos;
351 0 : rInOutSize = aSize;
352 0 : return true;
353 : }
354 :
355 0 : bool RelativePositionHelper::moveObject(
356 : chart2::RelativePosition & rInOutPosition,
357 : const chart2::RelativeSize & rObjectSize,
358 : double fAmountX, double fAmountY,
359 : bool bCheck /* = true */ )
360 : {
361 0 : chart2::RelativePosition aPos( rInOutPosition );
362 0 : aPos.Primary += fAmountX;
363 0 : aPos.Secondary += fAmountY;
364 0 : const double fPosCheckThreshold = 0.02;
365 :
366 0 : if( bCheck )
367 : {
368 : chart2::RelativePosition aUpperLeft(
369 0 : RelativePositionHelper::getReanchoredPosition( aPos, rObjectSize, drawing::Alignment_TOP_LEFT ));
370 0 : chart2::RelativePosition aLowerRight( aUpperLeft );
371 0 : aLowerRight.Primary += rObjectSize.Primary;
372 0 : aLowerRight.Secondary += rObjectSize.Secondary;
373 :
374 0 : const double fFarEdgeThreshold = 1.0 - fPosCheckThreshold;
375 0 : 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 0 : return false;
380 : }
381 :
382 0 : rInOutPosition = aPos;
383 0 : return true;
384 : }
385 :
386 : } // namespace chart
387 :
388 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|