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