1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_chart2.hxx"
26
27 #include "RelativePositionHelper.hxx"
28 #include <rtl/math.hxx>
29
30 using namespace ::com::sun::star;
31
32 namespace chart
33 {
34
getReanchoredPosition(const chart2::RelativePosition & rPosition,const chart2::RelativeSize & rObjectSize,drawing::Alignment aNewAnchor)35 chart2::RelativePosition RelativePositionHelper::getReanchoredPosition(
36 const chart2::RelativePosition & rPosition,
37 const chart2::RelativeSize & rObjectSize,
38 drawing::Alignment aNewAnchor )
39 {
40 chart2::RelativePosition aResult( rPosition );
41 if( rPosition.Anchor != aNewAnchor )
42 {
43 sal_Int32 nShiftHalfWidths = 0;
44 sal_Int32 nShiftHalfHeights = 0;
45
46 // normalize to top-left
47 switch( rPosition.Anchor )
48 {
49 case drawing::Alignment_TOP_LEFT:
50 break;
51 case drawing::Alignment_LEFT:
52 nShiftHalfHeights -= 1;
53 break;
54 case drawing::Alignment_BOTTOM_LEFT:
55 nShiftHalfHeights -= 2;
56 break;
57 case drawing::Alignment_TOP:
58 nShiftHalfWidths -= 1;
59 break;
60 case drawing::Alignment_CENTER:
61 nShiftHalfWidths -= 1;
62 nShiftHalfHeights -= 1;
63 break;
64 case drawing::Alignment_BOTTOM:
65 nShiftHalfWidths -= 1;
66 nShiftHalfHeights -= 2;
67 break;
68 case drawing::Alignment_TOP_RIGHT:
69 nShiftHalfWidths -= 2;
70 break;
71 case drawing::Alignment_RIGHT:
72 nShiftHalfWidths -= 2;
73 nShiftHalfHeights -= 1;
74 break;
75 case drawing::Alignment_BOTTOM_RIGHT:
76 nShiftHalfWidths -= 2;
77 nShiftHalfHeights -= 2;
78 break;
79 case drawing::Alignment_MAKE_FIXED_SIZE:
80 break;
81 }
82
83 // transform
84 switch( aNewAnchor )
85 {
86 case drawing::Alignment_TOP_LEFT:
87 break;
88 case drawing::Alignment_LEFT:
89 nShiftHalfHeights += 1;
90 break;
91 case drawing::Alignment_BOTTOM_LEFT:
92 nShiftHalfHeights += 2;
93 break;
94 case drawing::Alignment_TOP:
95 nShiftHalfWidths += 1;
96 break;
97 case drawing::Alignment_CENTER:
98 nShiftHalfWidths += 1;
99 nShiftHalfHeights += 1;
100 break;
101 case drawing::Alignment_BOTTOM:
102 nShiftHalfWidths += 1;
103 nShiftHalfHeights += 2;
104 break;
105 case drawing::Alignment_TOP_RIGHT:
106 nShiftHalfWidths += 2;
107 break;
108 case drawing::Alignment_RIGHT:
109 nShiftHalfWidths += 2;
110 nShiftHalfHeights += 1;
111 break;
112 case drawing::Alignment_BOTTOM_RIGHT:
113 nShiftHalfWidths += 2;
114 nShiftHalfHeights += 2;
115 break;
116 case drawing::Alignment_MAKE_FIXED_SIZE:
117 break;
118 }
119
120 if( nShiftHalfWidths != 0 )
121 aResult.Primary += (rObjectSize.Primary / 2.0) * nShiftHalfWidths;
122 if( nShiftHalfHeights != 0 )
123 aResult.Secondary += (rObjectSize.Secondary / 2.0) * nShiftHalfHeights;
124 }
125
126 return aResult;
127 }
128
129
getUpperLeftCornerOfAnchoredObject(awt::Point aPoint,awt::Size aObjectSize,drawing::Alignment aAnchor)130 awt::Point RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
131 awt::Point aPoint
132 , awt::Size aObjectSize
133 , drawing::Alignment aAnchor )
134 {
135 awt::Point aResult( aPoint );
136
137 double fXDelta = 0.0;
138 double fYDelta = 0.0;
139
140 // adapt x-value
141 switch( aAnchor )
142 {
143 case drawing::Alignment_TOP:
144 case drawing::Alignment_CENTER:
145 case drawing::Alignment_BOTTOM:
146 fXDelta -= static_cast< double >( aObjectSize.Width ) / 2.0;
147 break;
148 case drawing::Alignment_TOP_RIGHT:
149 case drawing::Alignment_RIGHT:
150 case drawing::Alignment_BOTTOM_RIGHT:
151 fXDelta -= aObjectSize.Width;
152 break;
153 case drawing::Alignment_TOP_LEFT:
154 case drawing::Alignment_LEFT:
155 case drawing::Alignment_BOTTOM_LEFT:
156 default:
157 // nothing to do
158 break;
159 }
160
161 // adapt y-value
162 switch( aAnchor )
163 {
164 case drawing::Alignment_LEFT:
165 case drawing::Alignment_CENTER:
166 case drawing::Alignment_RIGHT:
167 fYDelta -= static_cast< double >( aObjectSize.Height ) / 2.0;
168 break;
169 case drawing::Alignment_BOTTOM_LEFT:
170 case drawing::Alignment_BOTTOM:
171 case drawing::Alignment_BOTTOM_RIGHT:
172 fYDelta -= aObjectSize.Height;
173 break;
174 case drawing::Alignment_TOP_LEFT:
175 case drawing::Alignment_TOP:
176 case drawing::Alignment_TOP_RIGHT:
177 default:
178 // nothing to do
179 break;
180 }
181
182 aResult.X += static_cast< sal_Int32 >( ::rtl::math::round( fXDelta ));
183 aResult.Y += static_cast< sal_Int32 >( ::rtl::math::round( fYDelta ));
184
185 return aResult;
186 }
187
getCenterOfAnchoredObject(awt::Point aPoint,awt::Size aUnrotatedObjectSize,drawing::Alignment aAnchor,double fAnglePi)188 awt::Point RelativePositionHelper::getCenterOfAnchoredObject(
189 awt::Point aPoint
190 , awt::Size aUnrotatedObjectSize
191 , drawing::Alignment aAnchor
192 , double fAnglePi )
193 {
194 awt::Point aResult( aPoint );
195
196 double fXDelta = 0.0;
197 double fYDelta = 0.0;
198
199 // adapt x-value
200 switch( aAnchor )
201 {
202 case drawing::Alignment_TOP:
203 case drawing::Alignment_CENTER:
204 case drawing::Alignment_BOTTOM:
205 // nothing to do
206 break;
207 case drawing::Alignment_TOP_RIGHT:
208 case drawing::Alignment_RIGHT:
209 case drawing::Alignment_BOTTOM_RIGHT:
210 fXDelta -= aUnrotatedObjectSize.Width/2;
211 break;
212 case drawing::Alignment_TOP_LEFT:
213 case drawing::Alignment_LEFT:
214 case drawing::Alignment_BOTTOM_LEFT:
215 default:
216 fXDelta += aUnrotatedObjectSize.Width/2;
217 break;
218 }
219
220 // adapt y-value
221 switch( aAnchor )
222 {
223 case drawing::Alignment_LEFT:
224 case drawing::Alignment_CENTER:
225 case drawing::Alignment_RIGHT:
226 // nothing to do
227 break;
228 case drawing::Alignment_BOTTOM_LEFT:
229 case drawing::Alignment_BOTTOM:
230 case drawing::Alignment_BOTTOM_RIGHT:
231 fYDelta -= aUnrotatedObjectSize.Height/2;
232 break;
233 case drawing::Alignment_TOP_LEFT:
234 case drawing::Alignment_TOP:
235 case drawing::Alignment_TOP_RIGHT:
236 fYDelta += aUnrotatedObjectSize.Height/2;
237 default:
238 // nothing to do
239 break;
240 }
241
242 //take rotation into account:
243 aResult.X += static_cast< sal_Int32 >(
244 ::rtl::math::round( fXDelta * rtl::math::cos( fAnglePi ) + fYDelta * rtl::math::sin( fAnglePi ) ) );
245 aResult.Y += static_cast< sal_Int32 >(
246 ::rtl::math::round( - fXDelta * rtl::math::sin( fAnglePi ) + fYDelta * rtl::math::cos( fAnglePi ) ) );
247
248 return aResult;
249 }
250
centerGrow(chart2::RelativePosition & rInOutPosition,chart2::RelativeSize & rInOutSize,double fAmountX,double fAmountY,bool bCheck)251 bool RelativePositionHelper::centerGrow(
252 chart2::RelativePosition & rInOutPosition,
253 chart2::RelativeSize & rInOutSize,
254 double fAmountX, double fAmountY,
255 bool bCheck /* = true */ )
256 {
257 chart2::RelativePosition aPos( rInOutPosition );
258 chart2::RelativeSize aSize( rInOutSize );
259 const double fPosCheckThreshold = 0.02;
260 const double fSizeCheckThreshold = 0.1;
261
262 // grow/shrink, back to relaative
263 aSize.Primary += fAmountX;
264 aSize.Secondary += fAmountY;
265
266 double fShiftAmountX = fAmountX / 2.0;
267 double fShiftAmountY = fAmountY / 2.0;
268
269 // shift X
270 switch( rInOutPosition.Anchor )
271 {
272 case drawing::Alignment_TOP_LEFT:
273 case drawing::Alignment_LEFT:
274 case drawing::Alignment_BOTTOM_LEFT:
275 aPos.Primary -= fShiftAmountX;
276 break;
277 case drawing::Alignment_TOP:
278 case drawing::Alignment_CENTER:
279 case drawing::Alignment_BOTTOM:
280 // nothing
281 break;
282 case drawing::Alignment_TOP_RIGHT:
283 case drawing::Alignment_RIGHT:
284 case drawing::Alignment_BOTTOM_RIGHT:
285 aPos.Primary += fShiftAmountX;
286 break;
287 case drawing::Alignment_MAKE_FIXED_SIZE:
288 break;
289 }
290
291 // shift Y
292 switch( rInOutPosition.Anchor )
293 {
294 case drawing::Alignment_TOP:
295 case drawing::Alignment_TOP_LEFT:
296 case drawing::Alignment_TOP_RIGHT:
297 aPos.Secondary -= fShiftAmountY;
298 break;
299 case drawing::Alignment_CENTER:
300 case drawing::Alignment_LEFT:
301 case drawing::Alignment_RIGHT:
302 // nothing
303 break;
304 case drawing::Alignment_BOTTOM:
305 case drawing::Alignment_BOTTOM_LEFT:
306 case drawing::Alignment_BOTTOM_RIGHT:
307 aPos.Secondary += fShiftAmountY;
308 break;
309 case drawing::Alignment_MAKE_FIXED_SIZE:
310 break;
311 }
312
313 // anchor must not be changed
314 OSL_ASSERT( rInOutPosition.Anchor == aPos.Anchor );
315
316 if( rInOutPosition.Primary == aPos.Primary &&
317 rInOutPosition.Secondary == aPos.Secondary &&
318 rInOutSize.Primary == aSize.Primary &&
319 rInOutSize.Secondary == aSize.Secondary )
320 return false;
321
322 // check
323 if( bCheck )
324 {
325 // Note: this somewhat complicated check allows the output being
326 // out-of-bounds if the input was also out-of-bounds, and the change is
327 // for "advantage". E.g., you have a chart that laps out on the left
328 // side. If you shrink it, this should be possible, also if it still
329 // laps out on the left side afterwards. But you shouldn't be able to
330 // grow it then.
331
332 chart2::RelativePosition aUpperLeft(
333 RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_TOP_LEFT ));
334 chart2::RelativePosition aLowerRight(
335 RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_BOTTOM_RIGHT ));
336
337 // Do not grow, if this leads to corners being off-screen
338 if( fAmountX > 0.0 &&
339 ( (aUpperLeft.Primary < fPosCheckThreshold) ||
340 (aLowerRight.Primary > (1.0 - fPosCheckThreshold)) ))
341 return false;
342 if( fAmountY > 0.0 &&
343 ( (aUpperLeft.Secondary < fPosCheckThreshold) ||
344 (aLowerRight.Secondary > (1.0 - fPosCheckThreshold)) ))
345 return false;
346
347 // Do not shrink, if this leads to a size too small
348 if( fAmountX < 0.0 &&
349 ( aSize.Primary < fSizeCheckThreshold ))
350 return false;
351 if( fAmountY < 0.0 &&
352 ( aSize.Secondary < fSizeCheckThreshold ))
353 return false;
354 }
355
356 rInOutPosition = aPos;
357 rInOutSize = aSize;
358 return true;
359 }
360
moveObject(chart2::RelativePosition & rInOutPosition,const chart2::RelativeSize & rObjectSize,double fAmountX,double fAmountY,bool bCheck)361 bool RelativePositionHelper::moveObject(
362 chart2::RelativePosition & rInOutPosition,
363 const chart2::RelativeSize & rObjectSize,
364 double fAmountX, double fAmountY,
365 bool bCheck /* = true */ )
366 {
367 chart2::RelativePosition aPos( rInOutPosition );
368 aPos.Primary += fAmountX;
369 aPos.Secondary += fAmountY;
370 const double fPosCheckThreshold = 0.02;
371
372 if( bCheck )
373 {
374 chart2::RelativePosition aUpperLeft(
375 RelativePositionHelper::getReanchoredPosition( aPos, rObjectSize, drawing::Alignment_TOP_LEFT ));
376 chart2::RelativePosition aLowerRight( aUpperLeft );
377 aLowerRight.Primary += rObjectSize.Primary;
378 aLowerRight.Secondary += rObjectSize.Secondary;
379
380 const double fFarEdgeThreshold = 1.0 - fPosCheckThreshold;
381 if( ( fAmountX > 0.0 && (aLowerRight.Primary > fFarEdgeThreshold)) ||
382 ( fAmountX < 0.0 && (aUpperLeft.Primary < fPosCheckThreshold)) ||
383 ( fAmountY > 0.0 && (aLowerRight.Secondary > fFarEdgeThreshold)) ||
384 ( fAmountY < 0.0 && (aUpperLeft.Secondary < fPosCheckThreshold)) )
385 return false;
386 }
387
388 rInOutPosition = aPos;
389 return true;
390 }
391
392 } // namespace chart
393