| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_chart2.hxx" |
| |
| #include "RelativePositionHelper.hxx" |
| #include <rtl/math.hxx> |
| |
| using namespace ::com::sun::star; |
| |
| namespace chart |
| { |
| |
| chart2::RelativePosition RelativePositionHelper::getReanchoredPosition( |
| const chart2::RelativePosition & rPosition, |
| const chart2::RelativeSize & rObjectSize, |
| drawing::Alignment aNewAnchor ) |
| { |
| chart2::RelativePosition aResult( rPosition ); |
| if( rPosition.Anchor != aNewAnchor ) |
| { |
| sal_Int32 nShiftHalfWidths = 0; |
| sal_Int32 nShiftHalfHeights = 0; |
| |
| // normalize to top-left |
| switch( rPosition.Anchor ) |
| { |
| case drawing::Alignment_TOP_LEFT: |
| break; |
| case drawing::Alignment_LEFT: |
| nShiftHalfHeights -= 1; |
| break; |
| case drawing::Alignment_BOTTOM_LEFT: |
| nShiftHalfHeights -= 2; |
| break; |
| case drawing::Alignment_TOP: |
| nShiftHalfWidths -= 1; |
| break; |
| case drawing::Alignment_CENTER: |
| nShiftHalfWidths -= 1; |
| nShiftHalfHeights -= 1; |
| break; |
| case drawing::Alignment_BOTTOM: |
| nShiftHalfWidths -= 1; |
| nShiftHalfHeights -= 2; |
| break; |
| case drawing::Alignment_TOP_RIGHT: |
| nShiftHalfWidths -= 2; |
| break; |
| case drawing::Alignment_RIGHT: |
| nShiftHalfWidths -= 2; |
| nShiftHalfHeights -= 1; |
| break; |
| case drawing::Alignment_BOTTOM_RIGHT: |
| nShiftHalfWidths -= 2; |
| nShiftHalfHeights -= 2; |
| break; |
| case drawing::Alignment_MAKE_FIXED_SIZE: |
| break; |
| } |
| |
| // transform |
| switch( aNewAnchor ) |
| { |
| case drawing::Alignment_TOP_LEFT: |
| break; |
| case drawing::Alignment_LEFT: |
| nShiftHalfHeights += 1; |
| break; |
| case drawing::Alignment_BOTTOM_LEFT: |
| nShiftHalfHeights += 2; |
| break; |
| case drawing::Alignment_TOP: |
| nShiftHalfWidths += 1; |
| break; |
| case drawing::Alignment_CENTER: |
| nShiftHalfWidths += 1; |
| nShiftHalfHeights += 1; |
| break; |
| case drawing::Alignment_BOTTOM: |
| nShiftHalfWidths += 1; |
| nShiftHalfHeights += 2; |
| break; |
| case drawing::Alignment_TOP_RIGHT: |
| nShiftHalfWidths += 2; |
| break; |
| case drawing::Alignment_RIGHT: |
| nShiftHalfWidths += 2; |
| nShiftHalfHeights += 1; |
| break; |
| case drawing::Alignment_BOTTOM_RIGHT: |
| nShiftHalfWidths += 2; |
| nShiftHalfHeights += 2; |
| break; |
| case drawing::Alignment_MAKE_FIXED_SIZE: |
| break; |
| } |
| |
| if( nShiftHalfWidths != 0 ) |
| aResult.Primary += (rObjectSize.Primary / 2.0) * nShiftHalfWidths; |
| if( nShiftHalfHeights != 0 ) |
| aResult.Secondary += (rObjectSize.Secondary / 2.0) * nShiftHalfHeights; |
| } |
| |
| return aResult; |
| } |
| |
| |
| awt::Point RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( |
| awt::Point aPoint |
| , awt::Size aObjectSize |
| , drawing::Alignment aAnchor ) |
| { |
| awt::Point aResult( aPoint ); |
| |
| double fXDelta = 0.0; |
| double fYDelta = 0.0; |
| |
| // adapt x-value |
| switch( aAnchor ) |
| { |
| case drawing::Alignment_TOP: |
| case drawing::Alignment_CENTER: |
| case drawing::Alignment_BOTTOM: |
| fXDelta -= static_cast< double >( aObjectSize.Width ) / 2.0; |
| break; |
| case drawing::Alignment_TOP_RIGHT: |
| case drawing::Alignment_RIGHT: |
| case drawing::Alignment_BOTTOM_RIGHT: |
| fXDelta -= aObjectSize.Width; |
| break; |
| case drawing::Alignment_TOP_LEFT: |
| case drawing::Alignment_LEFT: |
| case drawing::Alignment_BOTTOM_LEFT: |
| default: |
| // nothing to do |
| break; |
| } |
| |
| // adapt y-value |
| switch( aAnchor ) |
| { |
| case drawing::Alignment_LEFT: |
| case drawing::Alignment_CENTER: |
| case drawing::Alignment_RIGHT: |
| fYDelta -= static_cast< double >( aObjectSize.Height ) / 2.0; |
| break; |
| case drawing::Alignment_BOTTOM_LEFT: |
| case drawing::Alignment_BOTTOM: |
| case drawing::Alignment_BOTTOM_RIGHT: |
| fYDelta -= aObjectSize.Height; |
| break; |
| case drawing::Alignment_TOP_LEFT: |
| case drawing::Alignment_TOP: |
| case drawing::Alignment_TOP_RIGHT: |
| default: |
| // nothing to do |
| break; |
| } |
| |
| aResult.X += static_cast< sal_Int32 >( ::rtl::math::round( fXDelta )); |
| aResult.Y += static_cast< sal_Int32 >( ::rtl::math::round( fYDelta )); |
| |
| return aResult; |
| } |
| |
| awt::Point RelativePositionHelper::getCenterOfAnchoredObject( |
| awt::Point aPoint |
| , awt::Size aUnrotatedObjectSize |
| , drawing::Alignment aAnchor |
| , double fAnglePi ) |
| { |
| awt::Point aResult( aPoint ); |
| |
| double fXDelta = 0.0; |
| double fYDelta = 0.0; |
| |
| // adapt x-value |
| switch( aAnchor ) |
| { |
| case drawing::Alignment_TOP: |
| case drawing::Alignment_CENTER: |
| case drawing::Alignment_BOTTOM: |
| // nothing to do |
| break; |
| case drawing::Alignment_TOP_RIGHT: |
| case drawing::Alignment_RIGHT: |
| case drawing::Alignment_BOTTOM_RIGHT: |
| fXDelta -= aUnrotatedObjectSize.Width/2; |
| break; |
| case drawing::Alignment_TOP_LEFT: |
| case drawing::Alignment_LEFT: |
| case drawing::Alignment_BOTTOM_LEFT: |
| default: |
| fXDelta += aUnrotatedObjectSize.Width/2; |
| break; |
| } |
| |
| // adapt y-value |
| switch( aAnchor ) |
| { |
| case drawing::Alignment_LEFT: |
| case drawing::Alignment_CENTER: |
| case drawing::Alignment_RIGHT: |
| // nothing to do |
| break; |
| case drawing::Alignment_BOTTOM_LEFT: |
| case drawing::Alignment_BOTTOM: |
| case drawing::Alignment_BOTTOM_RIGHT: |
| fYDelta -= aUnrotatedObjectSize.Height/2; |
| break; |
| case drawing::Alignment_TOP_LEFT: |
| case drawing::Alignment_TOP: |
| case drawing::Alignment_TOP_RIGHT: |
| fYDelta += aUnrotatedObjectSize.Height/2; |
| default: |
| // nothing to do |
| break; |
| } |
| |
| //take rotation into account: |
| aResult.X += static_cast< sal_Int32 >( |
| ::rtl::math::round( fXDelta * rtl::math::cos( fAnglePi ) + fYDelta * rtl::math::sin( fAnglePi ) ) ); |
| aResult.Y += static_cast< sal_Int32 >( |
| ::rtl::math::round( - fXDelta * rtl::math::sin( fAnglePi ) + fYDelta * rtl::math::cos( fAnglePi ) ) ); |
| |
| return aResult; |
| } |
| |
| bool RelativePositionHelper::centerGrow( |
| chart2::RelativePosition & rInOutPosition, |
| chart2::RelativeSize & rInOutSize, |
| double fAmountX, double fAmountY, |
| bool bCheck /* = true */ ) |
| { |
| chart2::RelativePosition aPos( rInOutPosition ); |
| chart2::RelativeSize aSize( rInOutSize ); |
| const double fPosCheckThreshold = 0.02; |
| const double fSizeCheckThreshold = 0.1; |
| |
| // grow/shrink, back to relaative |
| aSize.Primary += fAmountX; |
| aSize.Secondary += fAmountY; |
| |
| double fShiftAmountX = fAmountX / 2.0; |
| double fShiftAmountY = fAmountY / 2.0; |
| |
| // shift X |
| switch( rInOutPosition.Anchor ) |
| { |
| case drawing::Alignment_TOP_LEFT: |
| case drawing::Alignment_LEFT: |
| case drawing::Alignment_BOTTOM_LEFT: |
| aPos.Primary -= fShiftAmountX; |
| break; |
| case drawing::Alignment_TOP: |
| case drawing::Alignment_CENTER: |
| case drawing::Alignment_BOTTOM: |
| // nothing |
| break; |
| case drawing::Alignment_TOP_RIGHT: |
| case drawing::Alignment_RIGHT: |
| case drawing::Alignment_BOTTOM_RIGHT: |
| aPos.Primary += fShiftAmountX; |
| break; |
| case drawing::Alignment_MAKE_FIXED_SIZE: |
| break; |
| } |
| |
| // shift Y |
| switch( rInOutPosition.Anchor ) |
| { |
| case drawing::Alignment_TOP: |
| case drawing::Alignment_TOP_LEFT: |
| case drawing::Alignment_TOP_RIGHT: |
| aPos.Secondary -= fShiftAmountY; |
| break; |
| case drawing::Alignment_CENTER: |
| case drawing::Alignment_LEFT: |
| case drawing::Alignment_RIGHT: |
| // nothing |
| break; |
| case drawing::Alignment_BOTTOM: |
| case drawing::Alignment_BOTTOM_LEFT: |
| case drawing::Alignment_BOTTOM_RIGHT: |
| aPos.Secondary += fShiftAmountY; |
| break; |
| case drawing::Alignment_MAKE_FIXED_SIZE: |
| break; |
| } |
| |
| // anchor must not be changed |
| OSL_ASSERT( rInOutPosition.Anchor == aPos.Anchor ); |
| |
| if( rInOutPosition.Primary == aPos.Primary && |
| rInOutPosition.Secondary == aPos.Secondary && |
| rInOutSize.Primary == aSize.Primary && |
| rInOutSize.Secondary == aSize.Secondary ) |
| return false; |
| |
| // check |
| if( bCheck ) |
| { |
| // Note: this somewhat complicated check allows the output being |
| // out-of-bounds if the input was also out-of-bounds, and the change is |
| // for "advantage". E.g., you have a chart that laps out on the left |
| // side. If you shrink it, this should be possible, also if it still |
| // laps out on the left side afterwards. But you shouldn't be able to |
| // grow it then. |
| |
| chart2::RelativePosition aUpperLeft( |
| RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_TOP_LEFT )); |
| chart2::RelativePosition aLowerRight( |
| RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_BOTTOM_RIGHT )); |
| |
| // Do not grow, if this leads to corners being off-screen |
| if( fAmountX > 0.0 && |
| ( (aUpperLeft.Primary < fPosCheckThreshold) || |
| (aLowerRight.Primary > (1.0 - fPosCheckThreshold)) )) |
| return false; |
| if( fAmountY > 0.0 && |
| ( (aUpperLeft.Secondary < fPosCheckThreshold) || |
| (aLowerRight.Secondary > (1.0 - fPosCheckThreshold)) )) |
| return false; |
| |
| // Do not shrink, if this leads to a size too small |
| if( fAmountX < 0.0 && |
| ( aSize.Primary < fSizeCheckThreshold )) |
| return false; |
| if( fAmountY < 0.0 && |
| ( aSize.Secondary < fSizeCheckThreshold )) |
| return false; |
| } |
| |
| rInOutPosition = aPos; |
| rInOutSize = aSize; |
| return true; |
| } |
| |
| bool RelativePositionHelper::moveObject( |
| chart2::RelativePosition & rInOutPosition, |
| const chart2::RelativeSize & rObjectSize, |
| double fAmountX, double fAmountY, |
| bool bCheck /* = true */ ) |
| { |
| chart2::RelativePosition aPos( rInOutPosition ); |
| aPos.Primary += fAmountX; |
| aPos.Secondary += fAmountY; |
| const double fPosCheckThreshold = 0.02; |
| |
| if( bCheck ) |
| { |
| chart2::RelativePosition aUpperLeft( |
| RelativePositionHelper::getReanchoredPosition( aPos, rObjectSize, drawing::Alignment_TOP_LEFT )); |
| chart2::RelativePosition aLowerRight( aUpperLeft ); |
| aLowerRight.Primary += rObjectSize.Primary; |
| aLowerRight.Secondary += rObjectSize.Secondary; |
| |
| const double fFarEdgeThreshold = 1.0 - fPosCheckThreshold; |
| if( ( fAmountX > 0.0 && (aLowerRight.Primary > fFarEdgeThreshold)) || |
| ( fAmountX < 0.0 && (aUpperLeft.Primary < fPosCheckThreshold)) || |
| ( fAmountY > 0.0 && (aLowerRight.Secondary > fFarEdgeThreshold)) || |
| ( fAmountY < 0.0 && (aUpperLeft.Secondary < fPosCheckThreshold)) ) |
| return false; |
| } |
| |
| rInOutPosition = aPos; |
| return true; |
| } |
| |
| } // namespace chart |