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