blob: 19210d67b994a8f1edae5730fdbd0e6fc74cc86c [file] [log] [blame]
/**************************************************************
*
* 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