1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "box.hxx" 29 30 #include <tools/debug.hxx> 31 #include <sal/macros.h> 32 33 // fixed point precision for distributing error 34 #define FIXED_PT 16 35 36 namespace layoutimpl 37 { 38 39 using namespace css; 40 41 Box::ChildProps::ChildProps( Box::ChildData *pData ) 42 { 43 addProp( RTL_CONSTASCII_USTRINGPARAM( "Expand" ), 44 ::getCppuType( static_cast< const sal_Bool* >( NULL ) ), 45 &(pData->mbExpand) ); 46 addProp( RTL_CONSTASCII_USTRINGPARAM( "Fill" ), 47 ::getCppuType( static_cast< const sal_Bool* >( NULL ) ), 48 &(pData->mbFill) ); 49 addProp( RTL_CONSTASCII_USTRINGPARAM( "Padding" ), 50 ::getCppuType( static_cast< const sal_Int32* >( NULL ) ), 51 &(pData->mnPadding) ); 52 } 53 54 Box::ChildData::ChildData( uno::Reference< awt::XLayoutConstrains > const& xChild ) 55 : Box_Base::ChildData( xChild ) 56 , mnPadding( 0 ) 57 , mbExpand( true ) 58 , mbFill( true ) 59 { 60 } 61 62 Box::ChildData* 63 Box::createChild( uno::Reference< awt::XLayoutConstrains > const& xChild ) 64 { 65 return new ChildData( xChild ); 66 } 67 68 Box::ChildProps* 69 Box::createChildProps( Box_Base::ChildData *pData ) 70 { 71 return new ChildProps( static_cast<Box::ChildData*> ( pData ) ); 72 } 73 74 Box::Box( bool horizontal ) 75 : Box_Base() 76 , mnSpacing( 0 ) 77 , mbHomogeneous( false ) 78 , mbHorizontal( horizontal ) 79 { 80 addProp( RTL_CONSTASCII_USTRINGPARAM( "Homogeneous" ), 81 ::getCppuType( static_cast< const sal_Bool* >( NULL ) ), 82 &mbHomogeneous ); 83 addProp( RTL_CONSTASCII_USTRINGPARAM( "Spacing" ), 84 ::getCppuType( static_cast< const sal_Int32* >( NULL ) ), 85 &mnSpacing ); 86 mbHasFlowChildren = false; 87 } 88 89 awt::Size 90 Box::calculateSize( long nWidth ) 91 { 92 int nVisibleChildren = 0; 93 // primary vs secundary axis (instead of a X and Y) 94 int nPrimSize = 0; 95 int nSecSize = 0; 96 int nFlowMinWidth = 0; // in case the box only has flow children 97 98 mbHasFlowChildren = false; 99 100 for ( std::list<Box_Base::ChildData *>::const_iterator it 101 = maChildren.begin(); it != maChildren.end(); it++ ) 102 { 103 ChildData *child = static_cast<Box::ChildData*> ( *it ); 104 if ( !child->isVisible() ) 105 continue; 106 107 uno::Reference< awt::XLayoutContainer > xChildCont( child->mxChild, uno::UNO_QUERY ); 108 bool bFlow = xChildCont.is() && xChildCont->hasHeightForWidth(); 109 110 awt::Size aChildSize = child->maRequisition = child->mxChild->getMinimumSize(); 111 112 if ( !mbHorizontal /*vertical*/ && bFlow ) 113 { 114 if ( nFlowMinWidth == 0 || nFlowMinWidth > aChildSize.Width ) 115 nFlowMinWidth = aChildSize.Width; 116 mbHasFlowChildren = true; 117 } 118 else 119 { 120 int size = primDim( aChildSize ) + child->mnPadding * 2; 121 if ( mbHomogeneous ) 122 nPrimSize = SAL_MAX( nPrimSize, size ); 123 else 124 nPrimSize += size; 125 126 nSecSize = SAL_MAX( nSecSize, secDim( aChildSize ) ); 127 } 128 nVisibleChildren++; 129 } 130 131 if ( nVisibleChildren ) 132 { 133 if ( mbHomogeneous ) 134 nPrimSize *= nVisibleChildren; 135 nPrimSize += (nVisibleChildren - 1) * mnSpacing; 136 } 137 138 if ( mbHasFlowChildren ) 139 { 140 if ( nWidth == 0 ) 141 nWidth = nSecSize ? nSecSize : nFlowMinWidth; 142 for ( std::list<Box_Base::ChildData *>::const_iterator it 143 = maChildren.begin(); it != maChildren.end(); it++ ) 144 { 145 ChildData *child = static_cast<Box::ChildData*> ( *it ); 146 if ( !child->isVisible() ) 147 continue; 148 149 uno::Reference< awt::XLayoutContainer > xChildCont( child->mxChild, uno::UNO_QUERY ); 150 bool bFlow = xChildCont.is() && xChildCont->hasHeightForWidth(); 151 152 if ( bFlow ) 153 nPrimSize += xChildCont->getHeightForWidth( nWidth ); 154 } 155 } 156 157 nPrimSize += mnBorderWidth * 2; 158 nSecSize += mnBorderWidth * 2; 159 return awt::Size( mbHorizontal ? nPrimSize : nSecSize, 160 mbHorizontal ? nSecSize : nPrimSize ); 161 } 162 163 awt::Size SAL_CALL 164 Box::getMinimumSize() throw(uno::RuntimeException) 165 { 166 maRequisition = calculateSize(); 167 return maRequisition; 168 } 169 170 sal_Bool SAL_CALL 171 Box::hasHeightForWidth() 172 throw(uno::RuntimeException) 173 { 174 return mbHasFlowChildren; 175 } 176 177 sal_Int32 SAL_CALL 178 Box::getHeightForWidth( sal_Int32 nWidth ) 179 throw(uno::RuntimeException) 180 { 181 if ( hasHeightForWidth() ) 182 return calculateSize( nWidth ).Height; 183 return maRequisition.Height; 184 } 185 186 void SAL_CALL 187 Box::allocateArea( const awt::Rectangle &newArea ) 188 throw (uno::RuntimeException) 189 { 190 maAllocation = newArea; 191 int nVisibleChildren = 0, nExpandChildren = 0; 192 193 for ( std::list<Box_Base::ChildData *>::const_iterator it 194 = maChildren.begin(); it != maChildren.end(); it++ ) 195 { 196 ChildData *child = static_cast<Box::ChildData*> ( *it ); 197 if ( child->isVisible() ) 198 { 199 nVisibleChildren++; 200 if ( child->mbExpand ) 201 nExpandChildren++; 202 } 203 } 204 if ( !nVisibleChildren ) 205 return; 206 207 // split rectangle for dimension helpers 208 awt::Point newPoint( newArea.X, newArea.Y ); 209 awt::Size newSize( newArea.Width, newArea.Height ); 210 211 int nExtraSpace; 212 if ( mbHomogeneous ) 213 nExtraSpace = ( ( primDim( newSize ) - mnBorderWidth * 2 - 214 ( nVisibleChildren - 1 ) * mnSpacing )) / nVisibleChildren; 215 else if ( nExpandChildren ) 216 { 217 int reqSize = primDim( maRequisition ); 218 if ( !mbHorizontal && hasHeightForWidth() ) 219 reqSize = getHeightForWidth( newArea.Width ); 220 nExtraSpace = ( primDim( newSize ) - reqSize ) / nExpandChildren; 221 } 222 else 223 nExtraSpace = 0; 224 225 int nChildPrimPoint, nChildSecPoint, nChildPrimSize, nChildSecSize; 226 227 int nStartPoint = primDim( newPoint ) + mnBorderWidth; 228 int nBoxSecSize = SAL_MAX( 1, secDim( newSize ) - mnBorderWidth * 2 ); 229 230 for ( std::list<Box_Base::ChildData *>::const_iterator it 231 = maChildren.begin(); it != maChildren.end(); it++ ) 232 { 233 ChildData *child = static_cast<Box::ChildData*> ( *it ); 234 if ( !child->isVisible() ) 235 continue; 236 237 awt::Point aChildPos; 238 int nBoxPrimSize; // of the available box space 239 240 if ( mbHomogeneous ) 241 nBoxPrimSize = nExtraSpace; 242 else 243 { 244 uno::Reference< awt::XLayoutContainer > xChildCont( child->mxChild, uno::UNO_QUERY ); 245 bool bFlow = xChildCont.is() && xChildCont->hasHeightForWidth(); 246 if ( !mbHorizontal && bFlow ) 247 nBoxPrimSize = xChildCont->getHeightForWidth( newArea.Width ); 248 else 249 nBoxPrimSize = primDim( child->maRequisition ); 250 nBoxPrimSize += child->mnPadding; 251 if ( child->mbExpand ) 252 nBoxPrimSize += nExtraSpace; 253 } 254 255 nChildPrimPoint = nStartPoint + child->mnPadding; 256 nChildSecPoint = secDim( newPoint ) + mnBorderWidth; 257 258 nChildSecSize = nBoxSecSize; 259 if ( child->mbFill ) 260 nChildPrimSize = SAL_MAX( 1, nBoxPrimSize - child->mnPadding); 261 else 262 { 263 nChildPrimSize = primDim( child->maRequisition ); 264 nChildPrimPoint += (nBoxPrimSize - nChildPrimSize) / 2; 265 266 nChildSecPoint += (nBoxSecSize - nChildSecSize) / 2; 267 } 268 269 awt::Rectangle area; 270 area.X = mbHorizontal ? nChildPrimPoint : nChildSecPoint; 271 area.Y = mbHorizontal ? nChildSecPoint : nChildPrimPoint; 272 area.Width = mbHorizontal ? nChildPrimSize : nChildSecSize; 273 area.Height = mbHorizontal ? nChildSecSize : nChildPrimSize; 274 275 allocateChildAt( child->mxChild, area ); 276 277 nStartPoint += nBoxPrimSize + mnSpacing + child->mnPadding; 278 } 279 } 280 281 } // namespace layoutimpl 282