add more spacing
[personal-kdebase.git] / workspace / kdm / kfrontend / themer / kdmlayout.cpp
blobfcea8e7faeaa755fa6842d4bc7274ec1c9b57e31
1 /*
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"
23 #include "kdmitem.h"
25 KdmLayoutFixed::KdmLayoutFixed( const QDomNode &/*node*/ )
27 //Parsing FIXED parameters on 'node' [NONE!]
30 void
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";
38 return;
40 // For each child in list I ask their hinted size and set it!
41 parentSizes.push( parentGeometry.size() );
42 forEachChild (itm)
43 itm->setGeometry( parentSizes, itm->placementHint( parentSizes, parentGeometry.topLeft() ), force );
44 parentSizes.pop();
45 leave() << "done";
48 KdmLayoutBox::KdmLayoutBox( const QDomNode &node )
50 //Parsing BOX parameters
51 QDomNode n = node;
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";
62 struct LayoutHint {
63 int min, opt, max, set;
64 bool done;
66 LayoutHint() : done( false )
71 void
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";
79 return;
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) {
90 int ccnt = 0;
91 forEachVisibleChild (itm)
92 ccnt++;
93 forEachVisibleChild (itm) {
94 QRect temp = childrenRect;
95 if (box.isVertical) {
96 int height = (temp.height() - (ccnt - 1) * box.spacing) / ccnt;
97 temp.setHeight( height );
98 childrenRect.setTop( childrenRect.top() + height + box.spacing );
99 } else {
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() );
106 parentSizes.pop();
107 parentSizes.push( parentGeometry.size() );
108 itm->setGeometry( parentSizes, itemRect, force );
109 parentSizes.pop();
110 ccnt--;
112 } else {
113 QVector<LayoutHint> lhs;
114 int ccnt = 0, mintot = 0, opttot = 0, esum = 0;
115 parentSizes.push( QSize( 0, 0 ) );
116 forEachVisibleChild (itm) {
117 SizeHint sh;
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();
124 } else {
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;
133 else {
134 lhs[ccnt].done = true;
135 lhs[ccnt].set = lhs[ccnt].opt;
137 ccnt++;
139 parentSizes.pop();
140 int havetot = box.isVertical ? childrenRect.size().height() : childrenRect.size().width();
141 int spacing;
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;
150 } else {
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;
157 spacing = 0;
158 } else {
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;
164 do {
165 tesum = wesum = esum;
166 textra = wextra = extra;
167 int idx = 0;
168 forEachVisibleChild (itm) {
169 if (!lhs[idx].done) {
170 int mex = itm->geom.expand * wextra / wesum;
171 wextra -= mex;
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;
178 } else
179 lhs[idx].set = lhs[idx].opt + mex;
181 idx++;
183 } while (tesum != esum);
185 int idx = 0;
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 );
191 } else {
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() );
197 parentSizes.pop();
198 debug() << "placementHint for" << itm << "temp" << temp << "final"
199 << itemRect << "childrenRect now" << childrenRect;
200 parentSizes.push( parentGeometry.size() );
201 itm->setGeometry( parentSizes, itemRect, force );
202 parentSizes.pop();
203 idx++;
206 leave() << "done";
209 QSize
210 KdmLayoutBox::sizeHint( QStack<QSize> &parentSizes )
212 enter("Box::sizeHint") << NoSpace << "parentSize #" << parentSizes.size()
213 << Space << parentSizes.top();
215 int ccnt = 0;
216 QSize bounds( 0, 0 ), sum( 0, 0 );
218 // Sum up area taken by children
219 parentSizes.push( QSize( 0, 0 ) );
220 forEachVisibleChild (itm) {
221 SizeHint sh;
222 itm->sizingHint( parentSizes, sh );
223 bounds = bounds.expandedTo( sh.opt );
224 sum += sh.opt;
225 ccnt++;
227 parentSizes.pop();
229 if (box.homogeneous) {
230 if (box.isVertical)
231 bounds.rheight() *= ccnt;
232 else
233 bounds.rwidth() *= ccnt;
234 } else {
235 if (box.isVertical)
236 bounds.rheight() = sum.height();
237 else
238 bounds.rwidth() = sum.width();
241 // Add padding and items spacing
242 int totspc = box.spacing * (ccnt - 1);
243 if (box.isVertical)
244 bounds.rheight() += totspc;
245 else
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 ) );