blob: 42d4c8a21b65cd2cb6000c29c22315759de7e603 [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.
*
*************************************************************/
#include "box.hxx"
#include <tools/debug.hxx>
#include <sal/macros.h>
// fixed point precision for distributing error
#define FIXED_PT 16
namespace layoutimpl
{
using namespace css;
Box::ChildProps::ChildProps( Box::ChildData *pData )
{
addProp( RTL_CONSTASCII_USTRINGPARAM( "Expand" ),
::getCppuType( static_cast< const sal_Bool* >( NULL ) ),
&(pData->mbExpand) );
addProp( RTL_CONSTASCII_USTRINGPARAM( "Fill" ),
::getCppuType( static_cast< const sal_Bool* >( NULL ) ),
&(pData->mbFill) );
addProp( RTL_CONSTASCII_USTRINGPARAM( "Padding" ),
::getCppuType( static_cast< const sal_Int32* >( NULL ) ),
&(pData->mnPadding) );
}
Box::ChildData::ChildData( uno::Reference< awt::XLayoutConstrains > const& xChild )
: Box_Base::ChildData( xChild )
, mnPadding( 0 )
, mbExpand( true )
, mbFill( true )
{
}
Box::ChildData*
Box::createChild( uno::Reference< awt::XLayoutConstrains > const& xChild )
{
return new ChildData( xChild );
}
Box::ChildProps*
Box::createChildProps( Box_Base::ChildData *pData )
{
return new ChildProps( static_cast<Box::ChildData*> ( pData ) );
}
Box::Box( bool horizontal )
: Box_Base()
, mnSpacing( 0 )
, mbHomogeneous( false )
, mbHorizontal( horizontal )
{
addProp( RTL_CONSTASCII_USTRINGPARAM( "Homogeneous" ),
::getCppuType( static_cast< const sal_Bool* >( NULL ) ),
&mbHomogeneous );
addProp( RTL_CONSTASCII_USTRINGPARAM( "Spacing" ),
::getCppuType( static_cast< const sal_Int32* >( NULL ) ),
&mnSpacing );
mbHasFlowChildren = false;
}
awt::Size
Box::calculateSize( long nWidth )
{
int nVisibleChildren = 0;
// primary vs secundary axis (instead of a X and Y)
int nPrimSize = 0;
int nSecSize = 0;
int nFlowMinWidth = 0; // in case the box only has flow children
mbHasFlowChildren = false;
for ( std::list<Box_Base::ChildData *>::const_iterator it
= maChildren.begin(); it != maChildren.end(); it++ )
{
ChildData *child = static_cast<Box::ChildData*> ( *it );
if ( !child->isVisible() )
continue;
uno::Reference< awt::XLayoutContainer > xChildCont( child->mxChild, uno::UNO_QUERY );
bool bFlow = xChildCont.is() && xChildCont->hasHeightForWidth();
awt::Size aChildSize = child->maRequisition = child->mxChild->getMinimumSize();
if ( !mbHorizontal /*vertical*/ && bFlow )
{
if ( nFlowMinWidth == 0 || nFlowMinWidth > aChildSize.Width )
nFlowMinWidth = aChildSize.Width;
mbHasFlowChildren = true;
}
else
{
int size = primDim( aChildSize ) + child->mnPadding * 2;
if ( mbHomogeneous )
nPrimSize = SAL_MAX( nPrimSize, size );
else
nPrimSize += size;
nSecSize = SAL_MAX( nSecSize, secDim( aChildSize ) );
}
nVisibleChildren++;
}
if ( nVisibleChildren )
{
if ( mbHomogeneous )
nPrimSize *= nVisibleChildren;
nPrimSize += (nVisibleChildren - 1) * mnSpacing;
}
if ( mbHasFlowChildren )
{
if ( nWidth == 0 )
nWidth = nSecSize ? nSecSize : nFlowMinWidth;
for ( std::list<Box_Base::ChildData *>::const_iterator it
= maChildren.begin(); it != maChildren.end(); it++ )
{
ChildData *child = static_cast<Box::ChildData*> ( *it );
if ( !child->isVisible() )
continue;
uno::Reference< awt::XLayoutContainer > xChildCont( child->mxChild, uno::UNO_QUERY );
bool bFlow = xChildCont.is() && xChildCont->hasHeightForWidth();
if ( bFlow )
nPrimSize += xChildCont->getHeightForWidth( nWidth );
}
}
nPrimSize += mnBorderWidth * 2;
nSecSize += mnBorderWidth * 2;
return awt::Size( mbHorizontal ? nPrimSize : nSecSize,
mbHorizontal ? nSecSize : nPrimSize );
}
awt::Size SAL_CALL
Box::getMinimumSize() throw(uno::RuntimeException)
{
maRequisition = calculateSize();
return maRequisition;
}
sal_Bool SAL_CALL
Box::hasHeightForWidth()
throw(uno::RuntimeException)
{
return mbHasFlowChildren;
}
sal_Int32 SAL_CALL
Box::getHeightForWidth( sal_Int32 nWidth )
throw(uno::RuntimeException)
{
if ( hasHeightForWidth() )
return calculateSize( nWidth ).Height;
return maRequisition.Height;
}
void SAL_CALL
Box::allocateArea( const awt::Rectangle &newArea )
throw (uno::RuntimeException)
{
maAllocation = newArea;
int nVisibleChildren = 0, nExpandChildren = 0;
for ( std::list<Box_Base::ChildData *>::const_iterator it
= maChildren.begin(); it != maChildren.end(); it++ )
{
ChildData *child = static_cast<Box::ChildData*> ( *it );
if ( child->isVisible() )
{
nVisibleChildren++;
if ( child->mbExpand )
nExpandChildren++;
}
}
if ( !nVisibleChildren )
return;
// split rectangle for dimension helpers
awt::Point newPoint( newArea.X, newArea.Y );
awt::Size newSize( newArea.Width, newArea.Height );
int nExtraSpace;
if ( mbHomogeneous )
nExtraSpace = ( ( primDim( newSize ) - mnBorderWidth * 2 -
( nVisibleChildren - 1 ) * mnSpacing )) / nVisibleChildren;
else if ( nExpandChildren )
{
int reqSize = primDim( maRequisition );
if ( !mbHorizontal && hasHeightForWidth() )
reqSize = getHeightForWidth( newArea.Width );
nExtraSpace = ( primDim( newSize ) - reqSize ) / nExpandChildren;
}
else
nExtraSpace = 0;
int nChildPrimPoint, nChildSecPoint, nChildPrimSize, nChildSecSize;
int nStartPoint = primDim( newPoint ) + mnBorderWidth;
int nBoxSecSize = SAL_MAX( 1, secDim( newSize ) - mnBorderWidth * 2 );
for ( std::list<Box_Base::ChildData *>::const_iterator it
= maChildren.begin(); it != maChildren.end(); it++ )
{
ChildData *child = static_cast<Box::ChildData*> ( *it );
if ( !child->isVisible() )
continue;
awt::Point aChildPos;
int nBoxPrimSize; // of the available box space
if ( mbHomogeneous )
nBoxPrimSize = nExtraSpace;
else
{
uno::Reference< awt::XLayoutContainer > xChildCont( child->mxChild, uno::UNO_QUERY );
bool bFlow = xChildCont.is() && xChildCont->hasHeightForWidth();
if ( !mbHorizontal && bFlow )
nBoxPrimSize = xChildCont->getHeightForWidth( newArea.Width );
else
nBoxPrimSize = primDim( child->maRequisition );
nBoxPrimSize += child->mnPadding;
if ( child->mbExpand )
nBoxPrimSize += nExtraSpace;
}
nChildPrimPoint = nStartPoint + child->mnPadding;
nChildSecPoint = secDim( newPoint ) + mnBorderWidth;
nChildSecSize = nBoxSecSize;
if ( child->mbFill )
nChildPrimSize = SAL_MAX( 1, nBoxPrimSize - child->mnPadding);
else
{
nChildPrimSize = primDim( child->maRequisition );
nChildPrimPoint += (nBoxPrimSize - nChildPrimSize) / 2;
nChildSecPoint += (nBoxSecSize - nChildSecSize) / 2;
}
awt::Rectangle area;
area.X = mbHorizontal ? nChildPrimPoint : nChildSecPoint;
area.Y = mbHorizontal ? nChildSecPoint : nChildPrimPoint;
area.Width = mbHorizontal ? nChildPrimSize : nChildSecSize;
area.Height = mbHorizontal ? nChildSecSize : nChildPrimSize;
allocateChildAt( child->mxChild, area );
nStartPoint += nBoxPrimSize + mnSpacing + child->mnPadding;
}
}
} // namespace layoutimpl