2 * Copyright (C) 2003 by Unai Garro <ugarro@users.sourceforge.net>
3 * Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
4 * Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
5 * Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "kdmlayout.h"
25 KdmLayoutFixed::KdmLayoutFixed( const QDomNode
&/*node*/ )
27 //Parsing FIXED parameters on 'node' [NONE!]
31 KdmLayoutFixed::update( QStack
<QSize
> &parentSizes
, const QRect
&parentGeometry
, bool force
)
33 enter("Fixed::update") << parentGeometry
<< "depth" << parentSizes
.size();
35 // I can't layout children if the parent rectangle is not valid
36 if (parentGeometry
.width() < 0 || parentGeometry
.height() < 0) {
37 leave() << "invalid geometry";
40 // For each child in list I ask their hinted size and set it!
41 parentSizes
.push( parentGeometry
.size() );
43 itm
->setGeometry( parentSizes
, itm
->placementHint( parentSizes
, parentGeometry
.topLeft() ), force
);
48 KdmLayoutBox::KdmLayoutBox( const QDomNode
&node
)
50 //Parsing BOX parameters
52 QDomElement el
= n
.toElement();
53 box
.isVertical
= el
.attribute( "orientation", "vertical" ) != "horizontal";
54 box
.xpadding
= el
.attribute( "xpadding", "0" ).toInt();
55 box
.ypadding
= el
.attribute( "ypadding", "0" ).toInt();
56 box
.spacing
= el
.attribute( "spacing", "0" ).toInt();
57 box
.minwidth
= el
.attribute( "min-width", "0" ).toInt();
58 box
.minheight
= el
.attribute( "min-height", "0" ).toInt();
59 box
.homogeneous
= el
.attribute( "homogeneous", "false" ) == "true";
63 int min
, opt
, max
, set
;
66 LayoutHint() : done( false )
72 KdmLayoutBox::update( QStack
<QSize
> &parentSizes
, const QRect
&parentGeometry
, bool force
)
74 enter("Box::update") << parentGeometry
<< "depth" << parentSizes
.size();
76 // I can't layout children if the parent rectangle is not valid
77 if (!parentGeometry
.isValid() || parentGeometry
.isEmpty()) {
78 leave() << "invalid geometry";
82 QRect childrenRect
= parentGeometry
;
83 // Begin cutting the parent rectangle to attach children on the right place
84 childrenRect
.adjust( box
.xpadding
, box
.ypadding
, -box
.xpadding
, -box
.ypadding
);
86 debug() << "childrenRect" << childrenRect
;
88 // For each child in list ...
89 if (box
.homogeneous
) {
91 forEachVisibleChild (itm
)
93 forEachVisibleChild (itm
) {
94 QRect temp
= childrenRect
;
96 int height
= (temp
.height() - (ccnt
- 1) * box
.spacing
) / ccnt
;
97 temp
.setHeight( height
);
98 childrenRect
.setTop( childrenRect
.top() + height
+ box
.spacing
);
100 int width
= (temp
.width() - (ccnt
- 1) * box
.spacing
) / ccnt
;
101 temp
.setWidth( width
);
102 childrenRect
.setLeft( childrenRect
.left() + width
+ box
.spacing
);
104 parentSizes
.push( temp
.size() );
105 QRect itemRect
= itm
->placementHint( parentSizes
, temp
.topLeft() );
107 parentSizes
.push( parentGeometry
.size() );
108 itm
->setGeometry( parentSizes
, itemRect
, force
);
113 QVector
<LayoutHint
> lhs
;
114 int ccnt
= 0, mintot
= 0, opttot
= 0, esum
= 0;
115 parentSizes
.push( QSize( 0, 0 ) );
116 forEachVisibleChild (itm
) {
118 itm
->sizingHint( parentSizes
, sh
);
119 lhs
.resize( ccnt
+ 1 );
120 if (box
.isVertical
) {
121 lhs
[ccnt
].min
= sh
.min
.height();
122 lhs
[ccnt
].opt
= sh
.opt
.height();
123 lhs
[ccnt
].max
= sh
.max
.height();
125 lhs
[ccnt
].min
= sh
.min
.width();
126 lhs
[ccnt
].opt
= sh
.opt
.width();
127 lhs
[ccnt
].max
= sh
.max
.width();
129 mintot
+= lhs
[ccnt
].min
;
130 opttot
+= lhs
[ccnt
].opt
;
131 if (itm
->geom
.expand
)
132 esum
+= itm
->geom
.expand
;
134 lhs
[ccnt
].done
= true;
135 lhs
[ccnt
].set
= lhs
[ccnt
].opt
;
140 int havetot
= box
.isVertical
? childrenRect
.size().height() : childrenRect
.size().width();
142 if (havetot
< opttot
) {
143 // fix your theme, dude
144 if (havetot
< mintot
) {
145 for (int i
= 0; i
< ccnt
; i
++) {
146 lhs
[i
].set
= lhs
[i
].min
* havetot
/ mintot
;
147 havetot
-= lhs
[i
].set
;
148 mintot
-= lhs
[i
].min
;
151 for (int i
= 0; i
< ccnt
; i
++) {
152 lhs
[i
].set
= lhs
[i
].opt
* havetot
/ opttot
;
153 havetot
-= lhs
[i
].set
;
154 opttot
-= lhs
[i
].opt
;
159 spacing
= box
.spacing
;
160 if (havetot
< opttot
+ (ccnt
- 1) * spacing
)
161 spacing
= (havetot
- opttot
) / (ccnt
- 1);
162 int extra
= havetot
- opttot
- (ccnt
- 1) * spacing
;
163 int tesum
, wesum
, textra
, wextra
;
165 tesum
= wesum
= esum
;
166 textra
= wextra
= extra
;
168 forEachVisibleChild (itm
) {
169 if (!lhs
[idx
].done
) {
170 int mex
= itm
->geom
.expand
* wextra
/ wesum
;
172 wesum
-= itm
->geom
.expand
;
173 if (lhs
[idx
].opt
+ mex
> lhs
[idx
].max
) {
174 lhs
[idx
].set
= lhs
[idx
].max
;
175 lhs
[idx
].done
= true;
176 esum
-= itm
->geom
.expand
;
177 extra
-= lhs
[idx
].opt
;
179 lhs
[idx
].set
= lhs
[idx
].opt
+ mex
;
183 } while (tesum
!= esum
);
186 forEachVisibleChild (itm
) {
187 QRect temp
= childrenRect
;
188 if (box
.isVertical
) {
189 temp
.setHeight( lhs
[idx
].set
);
190 childrenRect
.setTop( childrenRect
.top() + lhs
[idx
].set
+ spacing
);
192 temp
.setWidth( lhs
[idx
].set
);
193 childrenRect
.setLeft( childrenRect
.left() + lhs
[idx
].set
+ spacing
);
195 parentSizes
.push( temp
.size() );
196 QRect itemRect
= itm
->placementHint( parentSizes
, temp
.topLeft() );
198 debug() << "placementHint for" << itm
<< "temp" << temp
<< "final"
199 << itemRect
<< "childrenRect now" << childrenRect
;
200 parentSizes
.push( parentGeometry
.size() );
201 itm
->setGeometry( parentSizes
, itemRect
, force
);
210 KdmLayoutBox::sizeHint( QStack
<QSize
> &parentSizes
)
212 enter("Box::sizeHint") << NoSpace
<< "parentSize #" << parentSizes
.size()
213 << Space
<< parentSizes
.top();
216 QSize
bounds( 0, 0 ), sum( 0, 0 );
218 // Sum up area taken by children
219 parentSizes
.push( QSize( 0, 0 ) );
220 forEachVisibleChild (itm
) {
222 itm
->sizingHint( parentSizes
, sh
);
223 bounds
= bounds
.expandedTo( sh
.opt
);
229 if (box
.homogeneous
) {
231 bounds
.rheight() *= ccnt
;
233 bounds
.rwidth() *= ccnt
;
236 bounds
.rheight() = sum
.height();
238 bounds
.rwidth() = sum
.width();
241 // Add padding and items spacing
242 int totspc
= box
.spacing
* (ccnt
- 1);
244 bounds
.rheight() += totspc
;
246 bounds
.rwidth() += totspc
;
247 bounds
+= QSize( 2 * box
.xpadding
, 2 * box
.ypadding
);
249 leave() << "bounds" << bounds
;
251 // Make hint at least equal to minimum size (if set)
252 return bounds
.expandedTo( QSize( box
.minwidth
, box
.minheight
) );