xref: /aoo42x/main/toolkit/source/layout/core/box.cxx (revision b0724fc6)
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 
ChildProps(Box::ChildData * pData)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 
ChildData(uno::Reference<awt::XLayoutConstrains> const & xChild)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*
createChild(uno::Reference<awt::XLayoutConstrains> const & xChild)59 Box::createChild( uno::Reference< awt::XLayoutConstrains > const& xChild )
60     {
61     return new ChildData( xChild );
62     }
63 
64 Box::ChildProps*
createChildProps(Box_Base::ChildData * pData)65 Box::createChildProps( Box_Base::ChildData *pData )
66 {
67     return new ChildProps( static_cast<Box::ChildData*> ( pData ) );
68 }
69 
Box(bool horizontal)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
calculateSize(long nWidth)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
getMinimumSize()160 Box::getMinimumSize() throw(uno::RuntimeException)
161 {
162     maRequisition = calculateSize();
163     return maRequisition;
164 }
165 
166 sal_Bool SAL_CALL
hasHeightForWidth()167 Box::hasHeightForWidth()
168     throw(uno::RuntimeException)
169 {
170     return mbHasFlowChildren;
171 }
172 
173 sal_Int32 SAL_CALL
getHeightForWidth(sal_Int32 nWidth)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
allocateArea(const awt::Rectangle & newArea)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