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