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 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 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 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 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 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