kexi

kexiflowlayout.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "kexiflowlayout.h"
21
22#include <kdebug.h>
23
25
26class KexiFlowLayoutIterator : public TQGLayoutIterator
27{
28 public:
29 KexiFlowLayoutIterator( TQPtrList<TQLayoutItem> *list )
30 : m_idx(0), m_list( list )
31 {}
32 uint count() const;
33 TQLayoutItem *current();
34 TQLayoutItem *next();
35 TQLayoutItem *takeCurrent();
36
37 private:
38 int m_idx;
39 TQPtrList<TQLayoutItem> *m_list;
40};
41
42uint
43KexiFlowLayoutIterator::count() const
44{
45 return m_list->count();
46}
47
48TQLayoutItem *
49KexiFlowLayoutIterator::current()
50{
51 return (m_idx < (int)count()) ? m_list->at(m_idx) : 0;
52}
53
54TQLayoutItem *
55KexiFlowLayoutIterator::next()
56{
57 m_idx++;
58 return current();
59}
60
61TQLayoutItem *
62KexiFlowLayoutIterator::takeCurrent()
63{
64 return (m_idx < (int)count()) ? m_list->take(m_idx) : 0;
65}
66
68
69KexiFlowLayout::KexiFlowLayout(TQWidget *parent, int border, int space, const char *name)
70 : TQLayout(parent, border, space, name)
71{
72 m_orientation =TQt::Horizontal;
73 m_justify = false;
74 m_cached_width = 0;
75}
76
77KexiFlowLayout::KexiFlowLayout(TQLayout* parent, int space, const char *name)
78 : TQLayout( parent, space, name )
79{
80 m_orientation =TQt::Horizontal;
81 m_justify = false;
82 m_cached_width = 0;
83}
84
85KexiFlowLayout::KexiFlowLayout(int space, const char *name)
86 : TQLayout(space, name)
87 {
88 m_orientation =TQt::Horizontal;
89 m_justify = false;
90 m_cached_width = 0;
91 }
92
93KexiFlowLayout::~KexiFlowLayout()
94{
95 deleteAllItems();
96}
97
98void
99KexiFlowLayout::addItem(TQLayoutItem *item)
100{
101 m_list.append(item);
102}
103
104void
105KexiFlowLayout::addSpacing(int size)
106{
107 if (m_orientation ==TQt::Horizontal)
108 addItem( new TQSpacerItem( size, 0, TQSizePolicy::Fixed, TQSizePolicy::Minimum ) );
109 else
110 addItem( new TQSpacerItem( 0, size, TQSizePolicy::Minimum, TQSizePolicy::Fixed ) );
111}
112
113TQLayoutIterator
114KexiFlowLayout::iterator()
115{
116 return TQLayoutIterator( new KexiFlowLayoutIterator(&m_list) );
117}
118
119TQPtrList<TQWidget>*
121{
122 TQPtrList<TQWidget> *list = new TQPtrList<TQWidget>();
123 for (TQPtrListIterator<TQLayoutItem> it(m_list); it.current(); ++it) {
124 if(it.current()->widget())
125 list->append(it.current()->widget());
126 }
127 return list;
128}
129
130void
131KexiFlowLayout::invalidate()
132{
133 TQLayout::invalidate();
134 m_cached_sizeHint = TQSize();
135 m_cached_minSize = TQSize();
136 m_cached_width = 0;
137}
138
139bool
140KexiFlowLayout::isEmpty()
141{
142 return m_list.isEmpty();
143}
144
145bool
146KexiFlowLayout::hasHeightForWidth() const
147{
148 return (m_orientation ==TQt::Horizontal);
149}
150
151int
152KexiFlowLayout::heightForWidth(int w) const
153{
154 if(m_cached_width != w) {
155 // workaround to allow this method to stay 'const'
156 KexiFlowLayout *mthis = (KexiFlowLayout*)this;
157 int h = mthis->simulateLayout( TQRect(0,0,w,0) );
158 mthis->m_cached_hfw = h;
159 mthis->m_cached_width = w;
160 return h;
161 }
162 return m_cached_hfw;
163}
164
165TQSize
166KexiFlowLayout::sizeHint() const
167{
168 if(m_cached_sizeHint.isEmpty()) {
169 KexiFlowLayout *mthis = (KexiFlowLayout*)this;
170 TQRect r = TQRect(0, 0, 2000, 2000);
171 mthis->simulateLayout(r);
172 }
173 return m_cached_sizeHint;
174}
175
176TQSize
177KexiFlowLayout::minimumSize() const
178{
179//js: do we really need to simulate layout here?
180// I commented this out because it was impossible to stretch layout conveniently.
181// Now, minimum size is computed automatically based on item's minimumSize...
182#if 0
183 if(m_cached_minSize.isEmpty()) {
184 KexiFlowLayout *mthis = (KexiFlowLayout*)this;
185 TQRect r = TQRect(0, 0, 2000, 2000);
186 mthis->simulateLayout(r);
187 }
188#endif
189 return m_cached_minSize;
190}
191
192TQSizePolicy::ExpandData
193KexiFlowLayout::expanding() const
194{
195 if(m_orientation == TQt::Vertical)
196 return TQSizePolicy::Vertically;
197 else
198 return TQSizePolicy::Horizontally;
199}
200
201void
202KexiFlowLayout::setGeometry(const TQRect &r)
203{
204 TQLayout::setGeometry(r);
205 if(m_orientation ==TQt::Horizontal)
207 else
209}
210
211int
212KexiFlowLayout::simulateLayout(const TQRect &r)
213{
214 if(m_orientation ==TQt::Horizontal)
215 return doHorizontalLayout(r, true);
216 else
217 return doVerticalLayout(r, true);
218}
219
220int
221KexiFlowLayout::doHorizontalLayout(const TQRect &r, bool testOnly)
222{
223 int x = r.x();
224 int y = r.y();
225 int h = 0; // height of this line
226 int availableSpace = r.width() + spacing();
227 int expandingWidgets=0; // number of widgets in the line with TQSizePolicy == Expanding
228 TQPtrListIterator<TQLayoutItem> it(m_list);
229 TQPtrList<TQLayoutItem> currentLine;
230 TQLayoutItem *o;
231 TQSize minSize, sizeHint(20, 20);
232 int minSizeHeight = 0 - spacing();
233
234 while ( (o = it.current()) != 0 ) {
235 if(o->isEmpty()) {
236 ++it;
237 continue;
238 }
239
240// kdDebug() << "- doHorizontalLayout(): " << o->widget()->className() << " " << o->widget()->name() << endl;
241 TQSize oSizeHint = o->sizeHint(); // we cache these ones because it can take a while to get it (eg for child layouts)
242 if ((x + oSizeHint.width()) > r.right() && h > 0) {
243 // do the layout of current line
244 TQPtrListIterator<TQLayoutItem> it2(currentLine);
245 TQLayoutItem *item;
246 int wx = r.x();
247 int sizeHintWidth = 0 -spacing(), minSizeWidth=0 - spacing(), lineMinHeight=0;
248 while( (item = it2.current()) != 0 ) {
249 TQSize itemSizeHint = item->sizeHint(); // we cache these ones because it can take
250 TQSize itemMinSize = item->minimumSize(); // a while to get them
251 TQSize s;
252 if(m_justify) {
253 if(expandingWidgets != 0) {
254 if(item->expanding() == TQSizePolicy::Horizontally || item->expanding() == TQSizePolicy::BothDirections)
255 s = TQSize( TQMIN(itemSizeHint.width() + availableSpace / expandingWidgets
256 , r.width()), itemSizeHint.height() );
257 else
258 s = TQSize( TQMIN(itemSizeHint.width(), r.width()), itemSizeHint.height() );
259 }
260 else
261 s = TQSize( TQMIN(itemSizeHint.width() + availableSpace / (int)currentLine.count()
262 , r.width()), itemSizeHint.height() );
263 }
264 else
265 s = TQSize ( TQMIN(itemSizeHint.width(), r.width()), itemSizeHint.height() );
266 if(!testOnly)
267 item->setGeometry( TQRect(TQPoint(wx, y), s) );
268 wx = wx + s.width() + spacing();
269 minSizeWidth = minSizeWidth + spacing() + itemMinSize.width();
270 sizeHintWidth = sizeHintWidth + spacing() + itemSizeHint.width();
271 lineMinHeight = TQMAX( lineMinHeight, itemMinSize.height() );
272 ++it2;
273 }
274 sizeHint = sizeHint.expandedTo( TQSize(sizeHintWidth, 0) );
275 minSize = minSize.expandedTo( TQSize(minSizeWidth, 0) );
276 minSizeHeight = minSizeHeight + spacing() + lineMinHeight;
277 // start a new line
278 y = y + spacing() + h;
279 h = 0;
280 x = r.x();
281 currentLine.clear();
282 expandingWidgets = 0;
283 availableSpace = r.width() + spacing();
284 }
285
286 x = x + spacing() + oSizeHint.width();
287 h = TQMAX( h, oSizeHint.height() );
288 currentLine.append(o);
289 if(o->expanding() == TQSizePolicy::Horizontally || o->expanding() == TQSizePolicy::BothDirections)
290 ++expandingWidgets;
291 availableSpace = TQMAX(0, availableSpace - spacing() - oSizeHint.width());
292 ++it;
293 }
294
295 // don't forget to layout the last line
296 TQPtrListIterator<TQLayoutItem> it2(currentLine);
297 TQLayoutItem *item;
298 int wx = r.x();
299 int sizeHintWidth = 0 -spacing(), minSizeWidth=0 - spacing(), lineMinHeight=0;
300 while( (item = it2.current()) != 0 ) {
301 TQSize itemSizeHint = item->sizeHint(); // we cache these ones because it can take
302 TQSize itemMinSize = item->minimumSize(); // a while to get them
303 TQSize s;
304 if(m_justify) {
305 if(expandingWidgets != 0) {
306 if(item->expanding() == TQSizePolicy::Horizontally || item->expanding() == TQSizePolicy::BothDirections)
307 s = TQSize( TQMIN(itemSizeHint.width() + availableSpace / expandingWidgets
308 , r.width()), itemSizeHint.height() );
309 else
310 s = TQSize( TQMIN(itemSizeHint.width(), r.width()), itemSizeHint.height() );
311 }
312 else
313 s = TQSize( TQMIN(itemSizeHint.width() + availableSpace / (int)currentLine.count()
314 , r.width()), itemSizeHint.height() );
315 }
316 else
317 s = TQSize ( TQMIN(itemSizeHint.width(), r.width()), itemSizeHint.height() );
318 if(!testOnly)
319 item->setGeometry( TQRect(TQPoint(wx, y), s) );
320 wx = wx + s.width() + spacing();
321 minSizeWidth = minSizeWidth + spacing() + itemMinSize.width();
322 sizeHintWidth = sizeHintWidth + spacing() + itemSizeHint.width();
323 lineMinHeight = TQMAX( lineMinHeight, itemMinSize.height() );
324 ++it2;
325 }
326 sizeHint = sizeHint.expandedTo( TQSize(sizeHintWidth, y + spacing() + h) );
327 minSizeHeight = minSizeHeight + spacing() + lineMinHeight;
328 minSize = minSize.expandedTo( TQSize(minSizeWidth, minSizeHeight) );
329
330 // store sizeHint() and minimumSize()
331 m_cached_sizeHint = sizeHint + TQSize(2* margin(), 2*margin());
332 m_cached_minSize = minSize + TQSize(2* margin() , 2*margin());
333 // return our height
334 return y + h - r.y();
335}
336
337int
338KexiFlowLayout::doVerticalLayout(const TQRect &r, bool testOnly)
339{
340 int x = r.x();
341 int y = r.y();
342 int w = 0; // width of this line
343 int availableSpace = r.height() + spacing();
344 int expandingWidgets=0; // number of widgets in the line with TQSizePolicy == Expanding
345 TQPtrListIterator<TQLayoutItem> it(m_list);
346 TQPtrList<TQLayoutItem> currentLine;
347 TQLayoutItem *o;
348 TQSize minSize, sizeHint(20, 20);
349 int minSizeWidth = 0 - spacing();
350
351 while ( (o = it.current()) != 0 ) {
352 if(o->isEmpty()) {
353 ++it;
354 continue;
355 }
356
357 TQSize oSizeHint = o->sizeHint(); // we cache these ones because it can take a while to get it (eg for child layouts)
358 if (y + oSizeHint.height() > r.bottom() && w > 0) {
359 // do the layout of current line
360 TQPtrListIterator<TQLayoutItem> it2(currentLine);
361 TQLayoutItem *item;
362 int wy = r.y();
363 int sizeHintHeight = 0 - spacing(), minSizeHeight = 0 - spacing(), colMinWidth=0;
364 while( (item = it2.current()) != 0 ) {
365 TQSize itemSizeHint = item->sizeHint(); // we cache these ones because it can take
366 TQSize itemMinSize = item->minimumSize(); // a while to get them
367 TQSize s;
368 if(m_justify) {
369 if(expandingWidgets != 0) {
370 if(item->expanding() == TQSizePolicy::Vertically || item->expanding() == TQSizePolicy::BothDirections)
371 s = TQSize( itemSizeHint.width(), TQMIN(itemSizeHint.height() + availableSpace / expandingWidgets
372 , r.height()) );
373 else
374 s = TQSize( itemSizeHint.width(), TQMIN(itemSizeHint.height(), r.height()) );
375 }
376 else
377 s = TQSize( itemSizeHint.width(), TQMIN(itemSizeHint.height() + availableSpace / (int)currentLine.count()
378 , r.height()) );
379 }
380 else
381 s = TQSize ( itemSizeHint.width(), TQMIN(itemSizeHint.height(), r.height()) );
382 if(!testOnly)
383 item->setGeometry( TQRect(TQPoint(x, wy), s) );
384 wy = wy + s.height() + spacing();
385 minSizeHeight = minSizeHeight + spacing() + itemMinSize.height();
386 sizeHintHeight = sizeHintHeight + spacing() + itemSizeHint.height();
387 colMinWidth = TQMAX( colMinWidth, itemMinSize.width() );
388 ++it2;
389 }
390 sizeHint = sizeHint.expandedTo( TQSize(0, sizeHintHeight) );
391 minSize = minSize.expandedTo( TQSize(0, minSizeHeight) );
392 minSizeWidth = minSizeWidth + spacing() + colMinWidth;
393 // start a new column
394 x = x + spacing() + w;
395 w = 0;
396 y = r.y();
397 currentLine.clear();
398 expandingWidgets = 0;
399 availableSpace = r.height() + spacing();
400 }
401
402 y = y + spacing() + oSizeHint.height();
403 w = TQMAX( w, oSizeHint.width() );
404 currentLine.append(o);
405 if(o->expanding() == TQSizePolicy::Vertically || o->expanding() == TQSizePolicy::BothDirections)
406 ++expandingWidgets;
407 availableSpace = TQMAX(0, availableSpace - spacing() - oSizeHint.height());
408 ++it;
409 }
410
411 // don't forget to layout the last line
412 TQPtrListIterator<TQLayoutItem> it2(currentLine);
413 TQLayoutItem *item;
414 int wy = r.y();
415 int sizeHintHeight = 0 - spacing(), minSizeHeight = 0 - spacing(), colMinWidth=0;
416 while( (item = it2.current()) != 0 ) {
417 TQSize itemSizeHint = item->sizeHint(); // we cache these ones because it can take
418 TQSize itemMinSize = item->minimumSize(); // a while to get them
419 TQSize s;
420 if(m_justify) {
421 if(expandingWidgets != 0) {
422 if(item->expanding() == TQSizePolicy::Vertically || item->expanding() == TQSizePolicy::BothDirections)
423 s = TQSize( itemSizeHint.width(), TQMIN(itemSizeHint.height() + availableSpace / expandingWidgets
424 , r.height()) );
425 else
426 s = TQSize( itemSizeHint.width(), TQMIN(itemSizeHint.height(), r.height()) );
427 }
428 else
429 s = TQSize( itemSizeHint.width(), TQMIN(itemSizeHint.height() + availableSpace / (int)currentLine.count()
430 , r.height()) );
431 }
432 else
433 s = TQSize ( itemSizeHint.width(), TQMIN(itemSizeHint.height(), r.height()) );
434 if(!testOnly)
435 item->setGeometry( TQRect(TQPoint(x, wy), s) );
436 wy = wy + s.height() + spacing();
437 minSizeHeight = minSizeHeight + spacing() + itemMinSize.height();
438 sizeHintHeight = sizeHintHeight + spacing() + itemSizeHint.height();
439 colMinWidth = TQMAX( colMinWidth, itemMinSize.width() );
440 ++it2;
441 }
442 sizeHint = sizeHint.expandedTo( TQSize( x + spacing() + w, sizeHintHeight) );
443 minSizeWidth = minSizeWidth + spacing() + colMinWidth;
444 minSize = minSize.expandedTo( TQSize(minSizeWidth, minSizeHeight) );
445
446 // store sizeHint() and minimumSize()
447 m_cached_sizeHint = sizeHint + TQSize(2* margin(), 2*margin());
448 m_cached_minSize = minSize + TQSize(2* margin(), 2*margin());
449 // return our width
450 return x + w - r.x();
451}
int doVerticalLayout(const TQRect &, bool testonly=false)
TQPtrList< TQWidget > * widgetList() const
int doHorizontalLayout(const TQRect &, bool testonly=false)