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