source: vendor/trolltech/current/src/kernel/qlayoutengine.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 9.9 KB
Line 
1/****************************************************************************
2** $Id: qlayoutengine.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QLayout functionality
5**
6** Created : 981231
7**
8** Copyright (C) 1998-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qlayout.h"
39#include "private/qlayoutengine_p.h"
40
41#ifndef QT_NO_LAYOUT
42
43static inline int toFixed( int i ) { return i * 256; }
44static inline int fRound( int i ) {
45 return ( i % 256 < 128 ) ? i / 256 : 1 + i / 256;
46}
47
48/*
49 This is the main workhorse of the QGridLayout. It portions out
50 available space to the chain's children.
51
52 The calculation is done in fixed point: "fixed" variables are
53 scaled by a factor of 256.
54
55 If the layout runs "backwards" (i.e. RightToLeft or Up) the layout
56 is computed mirror-reversed, and it's the caller's responsibility
57 do reverse the values before use.
58
59 chain contains input and output parameters describing the geometry.
60 count is the count of items in the chain; pos and space give the
61 interval (relative to parentWidget topLeft).
62*/
63Q_EXPORT void qGeomCalc( QMemArray<QLayoutStruct> &chain, int start, int count,
64 int pos, int space, int spacer )
65{
66 typedef int fixed;
67 int cHint = 0;
68 int cMin = 0;
69 int cMax = 0;
70 int sumStretch = 0;
71 int spacerCount = 0;
72
73 bool wannaGrow = FALSE; // anyone who really wants to grow?
74 // bool canShrink = FALSE; // anyone who could be persuaded to shrink?
75
76 int i;
77 for ( i = start; i < start + count; i++ ) {
78 chain[i].done = FALSE;
79 cHint += chain[i].smartSizeHint();
80 cMin += chain[i].minimumSize;
81 cMax += chain[i].maximumSize;
82 sumStretch += chain[i].stretch;
83 if ( !chain[i].empty )
84 spacerCount++;
85 wannaGrow = wannaGrow || chain[i].expansive || chain[i].stretch > 0;
86 }
87
88 int extraspace = 0;
89 if ( spacerCount )
90 spacerCount--; // only spacers between things
91 if ( space < cMin + spacerCount * spacer ) {
92 for ( i = start; i < start+count; i++ ) {
93 chain[i].size = chain[i].minimumSize;
94 chain[i].done = TRUE;
95 }
96 } else if ( space < cHint + spacerCount*spacer ) {
97 /*
98 Less space than smartSizeHint(), but more than minimumSize.
99 Currently take space equally from each, as in Qt 2.x.
100 Commented-out lines will give more space to stretchier
101 items.
102 */
103 int n = count;
104 int space_left = space - spacerCount*spacer;
105 int overdraft = cHint - space_left;
106
107 // first give to the fixed ones:
108 for ( i = start; i < start + count; i++ ) {
109 if ( !chain[i].done
110 && chain[i].minimumSize >= chain[i].smartSizeHint() ) {
111 chain[i].size = chain[i].smartSizeHint();
112 chain[i].done = TRUE;
113 space_left -= chain[i].smartSizeHint();
114 // sumStretch -= chain[i].stretch;
115 n--;
116 }
117 }
118 bool finished = n == 0;
119 while ( !finished ) {
120 finished = TRUE;
121 fixed fp_over = toFixed( overdraft );
122 fixed fp_w = 0;
123
124 for ( i = start; i < start+count; i++ ) {
125 if ( chain[i].done )
126 continue;
127 // if ( sumStretch <= 0 )
128 fp_w += fp_over / n;
129 // else
130 // fp_w += (fp_over * chain[i].stretch) / sumStretch;
131 int w = fRound( fp_w );
132 chain[i].size = chain[i].smartSizeHint() - w;
133 fp_w -= toFixed( w ); // give the difference to the next
134 if ( chain[i].size < chain[i].minimumSize ) {
135 chain[i].done = TRUE;
136 chain[i].size = chain[i].minimumSize;
137 finished = FALSE;
138 overdraft -= ( chain[i].smartSizeHint()
139 - chain[i].minimumSize );
140 // sumStretch -= chain[i].stretch;
141 n--;
142 break;
143 }
144 }
145 }
146 } else { // extra space
147 int n = count;
148 int space_left = space - spacerCount*spacer;
149 // first give to the fixed ones, and handle non-expansiveness
150 for ( i = start; i < start + count; i++ ) {
151 if ( !chain[i].done
152 && (chain[i].maximumSize <= chain[i].smartSizeHint()
153 || (wannaGrow && !chain[i].expansive && chain[i].stretch == 0)) ) {
154 chain[i].size = chain[i].smartSizeHint();
155 chain[i].done = TRUE;
156 space_left -= chain[i].smartSizeHint();
157 sumStretch -= chain[i].stretch;
158 n--;
159 }
160 }
161 extraspace = space_left;
162
163 /*
164 Do a trial distribution and calculate how much it is off.
165 If there are more deficit pixels than surplus pixels, give
166 the minimum size items what they need, and repeat.
167 Otherwise give to the maximum size items, and repeat.
168
169 Paul Olav Tvete has a wonderful mathematical proof of the
170 correctness of this principle, but unfortunately this
171 comment is too small to contain it.
172 */
173 int surplus, deficit;
174 do {
175 surplus = deficit = 0;
176 fixed fp_space = toFixed( space_left );
177 fixed fp_w = 0;
178 for ( i = start; i < start+count; i++ ) {
179 if ( chain[i].done )
180 continue;
181 extraspace = 0;
182 if ( sumStretch <= 0 )
183 fp_w += fp_space / n;
184 else
185 fp_w += (fp_space * chain[i].stretch) / sumStretch;
186 int w = fRound( fp_w );
187 chain[i].size = w;
188 fp_w -= toFixed( w ); // give the difference to the next
189 if ( w < chain[i].smartSizeHint() ) {
190 deficit += chain[i].smartSizeHint() - w;
191 } else if ( w > chain[i].maximumSize ) {
192 surplus += w - chain[i].maximumSize;
193 }
194 }
195 if ( deficit > 0 && surplus <= deficit ) {
196 // give to the ones that have too little
197 for ( i = start; i < start+count; i++ ) {
198 if ( !chain[i].done &&
199 chain[i].size < chain[i].smartSizeHint() ) {
200 chain[i].size = chain[i].smartSizeHint();
201 chain[i].done = TRUE;
202 space_left -= chain[i].smartSizeHint();
203 sumStretch -= chain[i].stretch;
204 n--;
205 }
206 }
207 }
208 if ( surplus > 0 && surplus >= deficit ) {
209 // take from the ones that have too much
210 for ( i = start; i < start+count; i++ ) {
211 if ( !chain[i].done &&
212 chain[i].size > chain[i].maximumSize ) {
213 chain[i].size = chain[i].maximumSize;
214 chain[i].done = TRUE;
215 space_left -= chain[i].maximumSize;
216 sumStretch -= chain[i].stretch;
217 n--;
218 }
219 }
220 }
221 } while ( n > 0 && surplus != deficit );
222 if ( n == 0 )
223 extraspace = space_left;
224 }
225
226 /*
227 As a last resort, we distribute the unwanted space equally
228 among the spacers (counting the start and end of the chain). We
229 could, but don't, attempt a sub-pixel allocation of the extra
230 space.
231 */
232 int extra = extraspace / ( spacerCount + 2 );
233 int p = pos + extra;
234 for ( i = start; i < start+count; i++ ) {
235 chain[i].pos = p;
236 p = p + chain[i].size;
237 if ( !chain[i].empty )
238 p += spacer+extra;
239 }
240}
241
242Q_EXPORT QSize qSmartMinSize( const QWidgetItem *i )
243{
244 QWidget *w = ((QWidgetItem *)i)->widget();
245
246 QSize s( 0, 0 );
247 if ( w->layout() ) {
248 s = w->layout()->totalMinimumSize();
249 } else {
250 QSize sh;
251
252 if ( w->sizePolicy().horData() != QSizePolicy::Ignored ) {
253 if ( w->sizePolicy().mayShrinkHorizontally() ) {
254 s.setWidth( w->minimumSizeHint().width() );
255 } else {
256 sh = w->sizeHint();
257 s.setWidth( sh.width() );
258 }
259 }
260
261 if ( w->sizePolicy().verData() != QSizePolicy::Ignored ) {
262 if ( w->sizePolicy().mayShrinkVertically() ) {
263 s.setHeight( w->minimumSizeHint().height() );
264 } else {
265 s.setHeight( sh.isValid() ? sh.height()
266 : w->sizeHint().height() );
267 }
268 }
269 }
270 s = s.boundedTo( w->maximumSize() );
271 QSize min = w->minimumSize();
272 if ( min.width() > 0 )
273 s.setWidth( min.width() );
274 if ( min.height() > 0 )
275 s.setHeight( min.height() );
276
277 if ( i->hasHeightForWidth() && min.height() == 0 && min.width() > 0 )
278 s.setHeight( i->heightForWidth(s.width()) );
279
280 s = s.expandedTo( QSize(1, 1) );
281 return s;
282}
283
284Q_EXPORT QSize qSmartMinSize( QWidget *w )
285{
286 QWidgetItem item( w );
287 return qSmartMinSize( &item );
288}
289
290Q_EXPORT QSize qSmartMaxSize( const QWidgetItem *i, int align )
291{
292 QWidget *w = ( (QWidgetItem*)i )->widget();
293 if ( align & Qt::AlignHorizontal_Mask && align & Qt::AlignVertical_Mask )
294 return QSize( QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX );
295 QSize s = w->maximumSize();
296 if ( s.width() == QWIDGETSIZE_MAX && !(align & Qt::AlignHorizontal_Mask) )
297 if ( !w->sizePolicy().mayGrowHorizontally() )
298 s.setWidth( w->sizeHint().width() );
299
300 if ( s.height() == QWIDGETSIZE_MAX && !(align & Qt::AlignVertical_Mask) )
301 if ( !w->sizePolicy().mayGrowVertically() )
302 s.setHeight( w->sizeHint().height() );
303
304 s = s.expandedTo( w->minimumSize() );
305
306 if ( align & Qt::AlignHorizontal_Mask )
307 s.setWidth( QLAYOUTSIZE_MAX );
308 if ( align & Qt::AlignVertical_Mask )
309 s.setHeight( QLAYOUTSIZE_MAX );
310 return s;
311}
312
313Q_EXPORT QSize qSmartMaxSize( QWidget *w, int align )
314{
315 QWidgetItem item( w );
316 return qSmartMaxSize( &item, align );
317}
318
319#endif // QT_NO_LAYOUT
Note: See TracBrowser for help on using the repository browser.