/************************************************************** * * 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 #include // 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 ( 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::const_iterator it = maChildren.begin(); it != maChildren.end(); it++ ) { ChildData *child = static_cast ( *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::const_iterator it = maChildren.begin(); it != maChildren.end(); it++ ) { ChildData *child = static_cast ( *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::const_iterator it = maChildren.begin(); it != maChildren.end(); it++ ) { ChildData *child = static_cast ( *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::const_iterator it = maChildren.begin(); it != maChildren.end(); it++ ) { ChildData *child = static_cast ( *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