summaryrefslogtreecommitdiff
path: root/libqtaux/qsplitter.cpp
authormickeyl <mickeyl>2004-01-13 21:14:51 (UTC)
committer mickeyl <mickeyl>2004-01-13 21:14:51 (UTC)
commitffe47019a96da4e6b7057fca30bb64274443099b (patch) (unidiff)
treeae203606aee544bec92ac9cc139a713199cf5522 /libqtaux/qsplitter.cpp
parent7f865d5f46330faf3574495cc68093490f896411 (diff)
downloadopie-ffe47019a96da4e6b7057fca30bb64274443099b.zip
opie-ffe47019a96da4e6b7057fca30bb64274443099b.tar.gz
opie-ffe47019a96da4e6b7057fca30bb64274443099b.tar.bz2
introduce libqtaux in order to get a LGPL clean libopie2 after the merge
with libopie1
Diffstat (limited to 'libqtaux/qsplitter.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--libqtaux/qsplitter.cpp1128
1 files changed, 1128 insertions, 0 deletions
diff --git a/libqtaux/qsplitter.cpp b/libqtaux/qsplitter.cpp
new file mode 100644
index 0000000..ab6e01b
--- a/dev/null
+++ b/libqtaux/qsplitter.cpp
@@ -0,0 +1,1128 @@
1/****************************************************************************
2** $Id$
3**
4** Splitter widget
5**
6** Created: 980105
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the widgets 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#include "qsplitter.h"
38
39#include "qpainter.h"
40#include "qdrawutil.h"
41#include "qbitmap.h"
42#include "qlayoutengine_p.h"
43#include "qlist.h"
44#include "qarray.h"
45#include "qobjectlist.h"
46#include "qapplication.h" //sendPostedEvents
47
48class QSplitterHandle : public QWidget
49{
50public:
51 QSplitterHandle( Qt::Orientation o,
52 QSplitter *parent, const char* name=0 );
53 void setOrientation( Qt::Orientation o );
54 Qt::Orientation orientation() const { return orient; }
55
56 bool opaque() const { return s->opaqueResize(); }
57
58 QSize sizeHint() const;
59 QSizePolicy sizePolicy() const;
60
61 int id() const { return myId; } // data->list.at(id())->wid == this
62 void setId( int i ) { myId = i; }
63
64protected:
65 void paintEvent( QPaintEvent * );
66 void mouseMoveEvent( QMouseEvent * );
67 void mousePressEvent( QMouseEvent * );
68 void mouseReleaseEvent( QMouseEvent * );
69
70private:
71 Qt::Orientation orient;
72 bool opaq;
73 int myId;
74
75 QSplitter *s;
76};
77
78static int mouseOffset;
79static int opaqueOldPos = -1; //### there's only one mouse, but this is a bit risky
80
81
82QSplitterHandle::QSplitterHandle( Qt::Orientation o,
83 QSplitter *parent, const char * name )
84 : QWidget( parent, name )
85{
86 s = parent;
87 setOrientation(o);
88}
89
90QSizePolicy QSplitterHandle::sizePolicy() const
91{
92 //### removeme 3.0
93 return QWidget::sizePolicy();
94}
95
96QSize QSplitterHandle::sizeHint() const
97{
98 int sw = style().splitterWidth();
99 return QSize(sw,sw).expandedTo( QApplication::globalStrut() );
100}
101
102void QSplitterHandle::setOrientation( Qt::Orientation o )
103{
104 orient = o;
105#ifndef QT_NO_CURSOR
106 if ( o == QSplitter::Horizontal )
107 setCursor( splitHCursor );
108 else
109 setCursor( splitVCursor );
110#endif
111}
112
113
114void QSplitterHandle::mouseMoveEvent( QMouseEvent *e )
115{
116 if ( !(e->state()&LeftButton) )
117 return;
118 QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()))
119 - mouseOffset;
120 if ( opaque() ) {
121 s->moveSplitter( pos, id() );
122 } else {
123 int min = pos; int max = pos;
124 s->getRange( id(), &min, &max );
125 s->setRubberband( QMAX( min, QMIN(max, pos )));
126 }
127}
128
129void QSplitterHandle::mousePressEvent( QMouseEvent *e )
130{
131 if ( e->button() == LeftButton )
132 mouseOffset = s->pick(e->pos());
133}
134
135void QSplitterHandle::mouseReleaseEvent( QMouseEvent *e )
136{
137 if ( !opaque() && e->button() == LeftButton ) {
138 QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()));
139 s->setRubberband( -1 );
140 s->moveSplitter( pos, id() );
141 }
142}
143
144void QSplitterHandle::paintEvent( QPaintEvent * )
145{
146 QPainter p( this );
147 s->drawSplitter( &p, 0, 0, width(), height() );
148}
149
150
151class QSplitterLayoutStruct
152{
153public:
154 QSplitter::ResizeMode mode;
155 QCOORD sizer;
156 bool isSplitter;
157 QWidget *wid;
158};
159
160class QSplitterData
161{
162public:
163 QSplitterData() : opaque( FALSE ), firstShow( TRUE ) {}
164
165 QList<QSplitterLayoutStruct> list;
166 bool opaque;
167 bool firstShow;
168};
169
170
171// NOT REVISED
172/*!
173 \class QSplitter qsplitter.h
174 \brief The QSplitter class implements a splitter widget.
175
176 \ingroup organizers
177
178 A splitter lets the user control the size of child widgets by
179 dragging the boundary between the children. Any number of widgets
180 may be controlled.
181
182 To show a QListBox, a QListView and a QMultiLineEdit side by side:
183
184 \code
185 QSplitter *split = new QSplitter( parent );
186 QListBox *lb = new QListBox( split );
187 QListView *lv = new QListView( split );
188 QMultiLineEdit *ed = new QMultiLineEdit( split );
189 \endcode
190
191 In QSplitter the boundary can be either horizontal or vertical. The
192 default is horizontal (the children are side by side) and you
193 can use setOrientation( QSplitter::Vertical ) to set it to vertical.
194
195 By default, all widgets can be as large or as small as the user
196 wishes, down to \link QWidget::minimumSizeHint() minimumSizeHint()\endlink.
197 You can naturally use setMinimumSize() and/or
198 setMaximumSize() on the children. Use setResizeMode() to specify that
199 a widget should keep its size when the splitter is resized.
200
201 QSplitter normally resizes the children only at the end of a
202 resize operation, but if you call setOpaqueResize( TRUE ), the
203 widgets are resized as often as possible.
204
205 The initial distribution of size between the widgets is determined
206 by the initial size of each widget. You can also use setSizes() to
207 set the sizes of all the widgets. The function sizes() returns the
208 sizes set by the user.
209
210 If you hide() a child, its space will be distributed among the other
211 children. When you show() it again, it will be reinstated.
212
213 <img src=qsplitter-m.png> <img src=qsplitter-w.png>
214
215 \sa QTabBar
216*/
217
218
219
220static QSize minSize( const QWidget *w )
221{
222 QSize min = w->minimumSize();
223 QSize s;
224 if ( min.height() <= 0 || min.width() <= 0 )
225 s = w->minimumSizeHint();
226 if ( min.height() > 0 )
227 s.setHeight( min.height() );
228 if ( min.width() > 0 )
229 s.setWidth( min.width() );
230 return s.expandedTo(QSize(0,0));
231}
232
233/*!
234 Constructs a horizontal splitter.
235*/
236
237QSplitter::QSplitter( QWidget *parent, const char *name )
238 :QFrame(parent,name,WPaintUnclipped)
239{
240 orient = Horizontal;
241 init();
242}
243
244
245/*!
246 Constructs splitter with orientation \a o.
247*/
248
249QSplitter::QSplitter( Orientation o, QWidget *parent, const char *name )
250 :QFrame(parent,name,WPaintUnclipped)
251{
252 orient = o;
253 init();
254}
255
256
257/*!
258 Destructs the splitter.
259*/
260
261QSplitter::~QSplitter()
262{
263 data->list.setAutoDelete( TRUE );
264 delete data;
265}
266
267
268void QSplitter::init()
269{
270 data = new QSplitterData;
271 if ( orient == Horizontal )
272 setSizePolicy( QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Minimum) );
273 else
274 setSizePolicy( QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Fixed) );
275}
276
277
278/*!
279 \fn void QSplitter::refresh()
280
281 Updates the splitter state. You should not need to call this
282 function during normal use of the splitter.
283*/
284
285
286/*! Sets the orientation to \a o. By default the orientation is
287 horizontal (the widgets are side by side).
288
289 \sa orientation()
290*/
291
292void QSplitter::setOrientation( Orientation o )
293{
294 if ( orient == o )
295 return;
296 orient = o;
297
298 if ( orient == Horizontal )
299 setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) );
300 else
301 setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
302
303 QSplitterLayoutStruct *s = data->list.first();
304 while ( s ) {
305 if ( s->isSplitter )
306 ((QSplitterHandle*)s->wid)->setOrientation( o );
307 s = data->list.next(); // ### next at end of loop, no iterator
308 }
309 recalc( isVisible() );
310}
311
312
313/*!
314 \fn Orientation QSplitter::orientation() const
315
316 Returns the orientation (\c Horizontal or \c Vertical) of the splitter.
317 \sa setOrientation()
318*/
319
320/*!
321 \reimp
322*/
323void QSplitter::resizeEvent( QResizeEvent * )
324{
325 doResize();
326}
327
328
329/*!
330 Inserts the widget \a w at the end, or at the beginning if \a first is TRUE
331
332 It is the responsibility of the caller of this function to make sure
333 that \a w is not already in the splitter, and to call recalcId if
334 needed. (If \a first is TRUE, then recalcId is very probably
335 needed.)
336*/
337
338QSplitterLayoutStruct *QSplitter::addWidget( QWidget *w, bool first )
339{
340 QSplitterLayoutStruct *s;
341 QSplitterHandle *newHandle = 0;
342 if ( data->list.count() > 0 ) {
343 s = new QSplitterLayoutStruct;
344 s->mode = KeepSize;
345 newHandle = new QSplitterHandle( orientation(), this );
346 s->wid = newHandle;
347 newHandle->setId(data->list.count());
348 s->isSplitter = TRUE;
349 s->sizer = pick( newHandle->sizeHint() );
350 if ( first )
351 data->list.insert( 0, s );
352 else
353 data->list.append( s );
354 }
355 s = new QSplitterLayoutStruct;
356 s->mode = Stretch;
357 s->wid = w;
358 if ( !testWState( WState_Resized ) && w->sizeHint().isValid() )
359 s->sizer = pick( w->sizeHint() );
360 else
361 s->sizer = pick( w->size() );
362 s->isSplitter = FALSE;
363 if ( first )
364 data->list.insert( 0, s );
365 else
366 data->list.append( s );
367 if ( newHandle && isVisible() )
368 newHandle->show(); //will trigger sending of post events
369 return s;
370}
371
372
373/*!
374 Tells the splitter that a child widget has been inserted/removed.
375*/
376
377void QSplitter::childEvent( QChildEvent *c )
378{
379 if ( c->type() == QEvent::ChildInserted ) {
380 if ( !c->child()->isWidgetType() )
381 return;
382
383 if ( ((QWidget*)c->child())->testWFlags( WType_TopLevel ) )
384 return;
385
386 QSplitterLayoutStruct *s = data->list.first();
387 while ( s ) {
388 if ( s->wid == c->child() )
389 return;
390 s = data->list.next();
391 }
392 addWidget( (QWidget*)c->child() );
393 recalc( isVisible() );
394
395 } else if ( c->type() == QEvent::ChildRemoved ) {
396 QSplitterLayoutStruct *p = 0;
397 if ( data->list.count() > 1 )
398 p = data->list.at(1); //remove handle _after_ first widget.
399 QSplitterLayoutStruct *s = data->list.first();
400 while ( s ) {
401 if ( s->wid == c->child() ) {
402 data->list.removeRef( s );
403 delete s;
404 if ( p && p->isSplitter ) {
405 data->list.removeRef( p );
406 delete p->wid; //will call childEvent
407 delete p;
408 }
409 recalcId();
410 doResize();
411 return;
412 }
413 p = s;
414 s = data->list.next();
415 }
416 }
417}
418
419
420/*!
421 Shows a rubber band at position \a p. If \a p is negative, the
422 rubber band is removed.
423*/
424
425void QSplitter::setRubberband( int p )
426{
427 QPainter paint( this );
428 paint.setPen( gray );
429 paint.setBrush( gray );
430 paint.setRasterOp( XorROP );
431 QRect r = contentsRect();
432 const int rBord = 3; //Themable????
433 const int sw = style().splitterWidth();
434 if ( orient == Horizontal ) {
435 if ( opaqueOldPos >= 0 )
436 paint.drawRect( opaqueOldPos + sw/2 - rBord , r.y(),
437 2*rBord, r.height() );
438 if ( p >= 0 )
439 paint.drawRect( p + sw/2 - rBord, r.y(), 2*rBord, r.height() );
440 } else {
441 if ( opaqueOldPos >= 0 )
442 paint.drawRect( r.x(), opaqueOldPos + sw/2 - rBord,
443 r.width(), 2*rBord );
444 if ( p >= 0 )
445 paint.drawRect( r.x(), p + sw/2 - rBord, r.width(), 2*rBord );
446 }
447 opaqueOldPos = p;
448}
449
450
451/*! \reimp */
452
453bool QSplitter::event( QEvent *e )
454{
455 if ( e->type() == QEvent::LayoutHint || ( e->type() == QEvent::Show && data->firstShow ) ) {
456 recalc( isVisible() );
457 if ( e->type() == QEvent::Show )
458 data->firstShow = FALSE;
459 }
460 return QWidget::event( e );
461}
462
463
464/*!
465 Draws the splitter handle in the rectangle described by \a x, \a y,
466 \a w, \a h using painter \a p.
467 \sa QStyle::drawSplitter
468*/
469
470void QSplitter::drawSplitter( QPainter *p,
471 QCOORD x, QCOORD y, QCOORD w, QCOORD h )
472{
473 style().drawSplitter( p, x, y, w, h, colorGroup(), orient );
474}
475
476
477/*!
478 Returns the id of the splitter to the right of or below the widget \a w,
479 or 0 if there is no such splitter.
480 (ie. it is either not in this QSplitter, or it is at the end).
481*/
482
483int QSplitter::idAfter( QWidget* w ) const
484{
485 QSplitterLayoutStruct *s = data->list.first();
486 bool seen_w = FALSE;
487 while ( s ) {
488 if ( s->isSplitter && seen_w )
489 return data->list.at();
490 if ( !s->isSplitter && s->wid == w )
491 seen_w = TRUE;
492 s = data->list.next();
493 }
494 return 0;
495}
496
497
498/*!
499 Moves the left/top edge of the splitter handle with id \a id as
500 close as possible to \a p which is the distance from the left (or
501 top) edge of the widget.
502
503 \sa idAfter()
504*/
505void QSplitter::moveSplitter( QCOORD p, int id )
506{
507 p = adjustPos( p, id );
508
509 QSplitterLayoutStruct *s = data->list.at(id);
510 int oldP = orient == Horizontal? s->wid->x() : s->wid->y();
511 bool upLeft = p < oldP;
512
513 moveAfter( p, id, upLeft );
514 moveBefore( p-1, id-1, upLeft );
515
516 storeSizes();
517}
518
519
520void QSplitter::setG( QWidget *w, int p, int s )
521{
522 if ( orient == Horizontal )
523 w->setGeometry( p, contentsRect().y(), s, contentsRect().height() );
524 else
525 w->setGeometry( contentsRect().x(), p, contentsRect().width(), s );
526}
527
528
529/*!
530 Places the right/bottom edge of the widget at \a id at position \a pos.
531
532 \sa idAfter()
533*/
534
535void QSplitter::moveBefore( int pos, int id, bool upLeft )
536{
537 QSplitterLayoutStruct *s = data->list.at(id);
538 if ( !s )
539 return;
540 QWidget *w = s->wid;
541 if ( w->isHidden() ) {
542 moveBefore( pos, id-1, upLeft );
543 } else if ( s->isSplitter ) {
544 int dd = s->sizer;
545 if ( upLeft ) {
546 setG( w, pos-dd+1, dd );
547 moveBefore( pos-dd, id-1, upLeft );
548 } else {
549 moveBefore( pos-dd, id-1, upLeft );
550 setG( w, pos-dd+1, dd );
551 }
552 } else {
553 int left = pick( w->pos() );
554 int dd = pos - left + 1;
555 dd = QMAX( pick(minSize(w)), QMIN(dd, pick(w->maximumSize())));
556 int newLeft = pos-dd+1;
557 setG( w, newLeft, dd );
558 if ( left != newLeft )
559 moveBefore( newLeft-1, id-1, upLeft );
560 }
561}
562
563
564/*!
565 Places the left/top edge of the widget at \a id at position \a pos.
566
567 \sa idAfter()
568*/
569
570void QSplitter::moveAfter( int pos, int id, bool upLeft )
571{
572 QSplitterLayoutStruct *s = id < int(data->list.count()) ?
573 data->list.at(id) : 0;
574 if ( !s )
575 return;
576 QWidget *w = s->wid;
577 if ( w->isHidden() ) {
578 moveAfter( pos, id+1, upLeft );
579 } else if ( pick( w->pos() ) == pos ) {
580 //No need to do anything if it's already there.
581 return;
582 } else if ( s->isSplitter ) {
583 int dd = s->sizer;
584 if ( upLeft ) {
585 setG( w, pos, dd );
586 moveAfter( pos+dd, id+1, upLeft );
587 } else {
588 moveAfter( pos+dd, id+1, upLeft );
589 setG( w, pos, dd );
590 }
591 } else {
592 int right = pick( w->geometry().bottomRight() );
593
594 int dd = right - pos + 1;
595 dd = QMAX( pick(minSize(w)), QMIN(dd, pick(w->maximumSize())));
596 int newRight = pos+dd-1;
597 setG( w, pos, dd );
598 moveAfter( newRight+1, id+1, upLeft );
599 }
600}
601
602
603/*!
604 Returns the valid range of the splitter with id \a id in \a min and \a max.
605
606 \sa idAfter()
607*/
608
609void QSplitter::getRange( int id, int *min, int *max )
610{
611 int minB = 0;//before
612 int maxB = 0;
613 int minA = 0;
614 int maxA = 0;//after
615 int n = data->list.count();
616 if ( id < 0 || id >= n )
617 return;
618 int i;
619 for ( i = 0; i < id; i++ ) {
620 QSplitterLayoutStruct *s = data->list.at(i);
621 if ( s->wid->isHidden() ) {
622 //ignore
623 } else if ( s->isSplitter ) {
624 minB += s->sizer;
625 maxB += s->sizer;
626 } else {
627 minB += pick( minSize(s->wid) );
628 maxB += pick( s->wid->maximumSize() );
629 }
630 }
631 for ( i = id; i < n; i++ ) {
632 QSplitterLayoutStruct *s = data->list.at(i);
633 if ( s->wid->isHidden() ) {
634 //ignore
635 } else if ( s->isSplitter ) {
636 minA += s->sizer;
637 maxA += s->sizer;
638 } else {
639 minA += pick( minSize(s->wid) );
640 maxA += pick( s->wid->maximumSize() );
641 }
642 }
643 QRect r = contentsRect();
644 if ( min )
645 *min = pick(r.topLeft()) + QMAX( minB, pick(r.size())-maxA );
646 if ( max )
647 *max = pick(r.topLeft()) + QMIN( maxB, pick(r.size())-minA );
648
649}
650
651
652/*!
653 Returns the legal position closest to \a p of the splitter with id \a id.
654
655 \sa idAfter()
656*/
657
658int QSplitter::adjustPos( int p, int id )
659{
660 int min = 0;
661 int max = 0;
662 getRange( id, &min, &max );
663 p = QMAX( min, QMIN( p, max ) );
664
665 return p;
666}
667
668
669void QSplitter::doResize()
670{
671 QRect r = contentsRect();
672 int i;
673 int n = data->list.count();
674 QArray<QLayoutStruct> a( n );
675 for ( i = 0; i< n; i++ ) {
676 a[i].init();
677 QSplitterLayoutStruct *s = data->list.at(i);
678 if ( s->wid->isHidden() ) {
679 a[i].stretch = 0;
680 a[i].sizeHint = a[i].minimumSize = 0;
681 a[i].maximumSize = 0;
682 } else if ( s->isSplitter ) {
683 a[i].stretch = 0;
684 a[i].sizeHint = a[i].minimumSize = a[i].maximumSize = s->sizer;
685 a[i].empty = FALSE;
686 } else if ( s->mode == KeepSize ) {
687 a[i].stretch = 0;
688 a[i].minimumSize = pick( minSize(s->wid) );
689 a[i].sizeHint = s->sizer;
690 a[i].maximumSize = pick( s->wid->maximumSize() );
691 a[i].empty = FALSE;
692 } else if ( s->mode == FollowSizeHint ) {
693 a[i].stretch = 0;
694 a[i].minimumSize = a[i].sizeHint = pick( s->wid->sizeHint() );
695 a[i].maximumSize = pick( s->wid->maximumSize() );
696 a[i].empty = FALSE;
697 } else { //proportional
698 a[i].stretch = s->sizer;
699 a[i].maximumSize = pick( s->wid->maximumSize() );
700 a[i].sizeHint = a[i].minimumSize = pick( minSize(s->wid) );
701 a[i].empty = FALSE;
702 }
703 }
704
705 qGeomCalc( a, 0, n, pick( r.topLeft() ), pick( r.size() ), 0 );
706 for ( i = 0; i< n; i++ ) {
707 QSplitterLayoutStruct *s = data->list.at(i);
708 if ( orient == Horizontal )
709 s->wid->setGeometry( a[i].pos, r.top(), a[i].size, r.height() );
710 else
711 s->wid->setGeometry( r.left(), a[i].pos, r.width(), a[i].size );
712 }
713
714}
715
716
717void QSplitter::recalc( bool update )
718{
719 int fi = 2*frameWidth();
720 int maxl = fi;
721 int minl = fi;
722 int maxt = QWIDGETSIZE_MAX;
723 int mint = fi;
724 int n = data->list.count();
725 bool first = TRUE;
726 /*
727 The splitter before a hidden widget is always hidden.
728 The splitter before the first visible widget is hidden.
729 The splitter before any other visible widget is visible.
730 */
731 for ( int i = 0; i< n; i++ ) {
732 QSplitterLayoutStruct *s = data->list.at(i);
733 if ( !s->isSplitter ) {
734 QSplitterLayoutStruct *p = (i > 0) ? p = data->list.at( i-1 ) : 0;
735 if ( p && p->isSplitter )
736 if ( first || s->wid->isHidden() )
737 p->wid->hide(); //may trigger new recalc
738 else
739 p->wid->show(); //may trigger new recalc
740 if ( !s->wid->isHidden() )
741 first = FALSE;
742 }
743 }
744
745 bool empty=TRUE;
746 for ( int j = 0; j< n; j++ ) {
747 QSplitterLayoutStruct *s = data->list.at(j);
748 if ( !s->wid->isHidden() ) {
749 empty = FALSE;
750 if ( s->isSplitter ) {
751 minl += s->sizer;
752 maxl += s->sizer;
753 } else {
754 QSize minS = minSize(s->wid);
755 minl += pick( minS );
756 maxl += pick( s->wid->maximumSize() );
757 mint = QMAX( mint, trans( minS ));
758 int tm = trans( s->wid->maximumSize() );
759 if ( tm > 0 )
760 maxt = QMIN( maxt, tm );
761 }
762 }
763 }
764 if ( empty )
765 maxl = maxt = 0;
766 else
767 maxl = QMIN( maxl, QWIDGETSIZE_MAX );
768 if ( maxt < mint )
769 maxt = mint;
770
771 if ( orient == Horizontal ) {
772 setMaximumSize( maxl, maxt );
773 setMinimumSize( minl, mint );
774 } else {
775 setMaximumSize( maxt, maxl );
776 setMinimumSize( mint, minl );
777 }
778 if ( update )
779 doResize();
780}
781
782/*! \enum QSplitter::ResizeMode
783
784 This enum type describes how QSplitter will resize each of its child widgets. The currently defined values are: <ul>
785
786 <li> \c Stretch - the widget will be resized when the splitter
787 itself is resized.
788
789 <li> \c KeepSize - QSplitter will try to keep this widget's size
790 unchanged.
791
792 <li> \c FollowSizeHint - QSplitter will resize the widget when its
793 size hint changes.
794
795 </ul>
796
797*/
798
799/*!
800 Sets resize mode of \a w to \a mode.
801
802 \sa ResizeMode
803*/
804
805void QSplitter::setResizeMode( QWidget *w, ResizeMode mode )
806{
807 processChildEvents();
808 QSplitterLayoutStruct *s = data->list.first();
809 while ( s ) {
810 if ( s->wid == w ) {
811 s->mode = mode;
812 return;
813 }
814 s = data->list.next();
815 }
816 s = addWidget( w, TRUE );
817 s->mode = mode;
818}
819
820
821/*!
822 Returns TRUE if opaque resize is on, FALSE otherwise.
823
824 \sa setOpaqueResize()
825*/
826
827bool QSplitter::opaqueResize() const
828{
829 return data->opaque;
830}
831
832
833/*!
834 Sets opaque resize to \a on. Opaque resize is initially turned off.
835
836 \sa opaqueResize()
837*/
838
839void QSplitter::setOpaqueResize( bool on )
840{
841 data->opaque = on;
842}
843
844
845/*!
846 Moves \a w to the leftmost/top position.
847*/
848
849void QSplitter::moveToFirst( QWidget *w )
850{
851 processChildEvents();
852 bool found = FALSE;
853 QSplitterLayoutStruct *s = data->list.first();
854 while ( s ) {
855 if ( s->wid == w ) {
856 found = TRUE;
857 QSplitterLayoutStruct *p = data->list.prev();
858 if ( p ) { // not already at first place
859 data->list.take(); //take p
860 data->list.take(); // take s
861 data->list.insert( 0, p );
862 data->list.insert( 0, s );
863 }
864 break;
865 }
866 s = data->list.next();
867 }
868 if ( !found )
869 addWidget( w, TRUE );
870 recalcId();
871}
872
873
874/*!
875 Moves \a w to the rightmost/bottom position.
876*/
877
878void QSplitter::moveToLast( QWidget *w )
879{
880 processChildEvents();
881 bool found = FALSE;
882 QSplitterLayoutStruct *s = data->list.first();
883 while ( s ) {
884 if ( s->wid == w ) {
885 found = TRUE;
886 data->list.take(); // take s
887 QSplitterLayoutStruct *p = data->list.current();
888 if ( p ) { // the splitter handle after s
889 data->list.take(); //take p
890 data->list.append( p );
891 }
892 data->list.append( s );
893 break;
894 }
895 s = data->list.next();
896 }
897 if ( !found )
898 addWidget( w);
899 recalcId();
900}
901
902
903void QSplitter::recalcId()
904{
905 int n = data->list.count();
906 for ( int i = 0; i < n; i++ ) {
907 QSplitterLayoutStruct *s = data->list.at(i);
908 if ( s->isSplitter )
909 ((QSplitterHandle*)s->wid)->setId(i);
910 }
911}
912
913
914/*!\reimp
915*/
916QSize QSplitter::sizeHint() const
917{
918 constPolish();
919 int l = 0;
920 int t = 0;
921 if ( children() ) {
922 const QObjectList * c = children();
923 QObjectListIt it( *c );
924 QObject * o;
925
926 while( (o=it.current()) != 0 ) {
927 ++it;
928 if ( o->isWidgetType() &&
929 !((QWidget*)o)->isHidden() ) {
930 QSize s = ((QWidget*)o)->sizeHint();
931 if ( s.isValid() ) {
932 l += pick( s );
933 t = QMAX( t, trans( s ) );
934 }
935 }
936 }
937 }
938 return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
939}
940
941
942/*!
943\reimp
944*/
945
946QSize QSplitter::minimumSizeHint() const
947{
948 constPolish();
949 int l = 0;
950 int t = 0;
951 if ( children() ) {
952 const QObjectList * c = children();
953 QObjectListIt it( *c );
954 QObject * o;
955
956 while( (o=it.current()) != 0 ) {
957 ++it;
958 if ( o->isWidgetType() &&
959 !((QWidget*)o)->isHidden() ) {
960 QSize s = minSize((QWidget*)o);
961 if ( s.isValid() ) {
962 l += pick( s );
963 t = QMAX( t, trans( s ) );
964 }
965 }
966 }
967 }
968 return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
969}
970
971
972
973/*!\reimp
974*/
975QSizePolicy QSplitter::sizePolicy() const
976{
977 return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
978}
979
980
981/*!
982 Calculates stretch parameters from current sizes
983*/
984
985void QSplitter::storeSizes()
986{
987 QSplitterLayoutStruct *s = data->list.first();
988 while ( s ) {
989 if ( !s->isSplitter )
990 s->sizer = pick( s->wid->size() );
991 s = data->list.next();
992 }
993}
994
995
996#if 0 // ### remove this code ASAP
997
998/*!
999 Hides \a w if \a hide is TRUE, and updates the splitter.
1000
1001 \warning Due to a limitation in the current implementation,
1002 calling QWidget::hide() will not work.
1003*/
1004
1005void QSplitter::setHidden( QWidget *w, bool hide )
1006{
1007 if ( w == w1 ) {
1008 w1show = !hide;
1009 } else if ( w == w2 ) {
1010 w2show = !hide;
1011 } else {
1012#ifdef CHECK_RANGE
1013 qWarning( "QSplitter::setHidden(), unknown widget" );
1014#endif
1015 return;
1016 }
1017 if ( hide )
1018 w->hide();
1019 else
1020 w->show();
1021 recalc( TRUE );
1022}
1023
1024
1025/*!
1026 Returns the hidden status of \a w
1027*/
1028
1029bool QSplitter::isHidden( QWidget *w ) const
1030{
1031 if ( w == w1 )
1032 return !w1show;
1033 else if ( w == w2 )
1034 return !w2show;
1035#ifdef CHECK_RANGE
1036 else
1037 qWarning( "QSplitter::isHidden(), unknown widget" );
1038#endif
1039 return FALSE;
1040}
1041#endif
1042
1043
1044/*!
1045 Returns a list of the size parameters of all the widgets in this
1046 splitter.
1047
1048 Giving the values to setSizes() will give a splitter with the same
1049 layout as this one.
1050
1051 \sa setSizes()
1052*/
1053
1054QValueList<int> QSplitter::sizes() const
1055{
1056 if ( !testWState(WState_Polished) ) {
1057 QWidget* that = (QWidget*) this;
1058 that->polish();
1059 }
1060 QValueList<int> list;
1061 QSplitterLayoutStruct *s = data->list.first();
1062 while ( s ) {
1063 if ( !s->isSplitter )
1064 list.append( s->sizer );
1065 s = data->list.next();
1066 }
1067 return list;
1068}
1069
1070
1071
1072/*!
1073 Sets the size parameters to the values given in \a list.
1074 If the splitter is horizontal, the values set the sizes from
1075 left to right. If it is vertical, the sizes are applied from
1076 top to bottom.
1077 Extra values in \a list are ignored.
1078
1079 If \a list contains too few values, the result is undefined
1080 but the program will still be well-behaved.
1081
1082 \sa sizes()
1083*/
1084
1085void QSplitter::setSizes( QValueList<int> list )
1086{
1087 processChildEvents();
1088 QValueList<int>::Iterator it = list.begin();
1089 QSplitterLayoutStruct *s = data->list.first();
1090 while ( s && it != list.end() ) {
1091 if ( !s->isSplitter ) {
1092 s->sizer = *it;
1093 ++it;
1094 }
1095 s = data->list.next();
1096 }
1097 doResize();
1098}
1099
1100
1101/*!
1102 Gets all posted child events, ensuring that the internal state of
1103 the splitter is consistent with the programmer's idea.
1104*/
1105
1106void QSplitter::processChildEvents()
1107{
1108 QApplication::sendPostedEvents( this, QEvent::ChildInserted );
1109}
1110
1111
1112/*!
1113 \reimp
1114*/
1115
1116void QSplitter::styleChange( QStyle& old )
1117{
1118 int sw = style().splitterWidth();
1119 QSplitterLayoutStruct *s = data->list.first();
1120 while ( s ) {
1121 if ( s->isSplitter )
1122 s->sizer = sw;
1123 s = data->list.next();
1124 }
1125 doResize();
1126 QFrame::styleChange( old );
1127}
1128