1 /////////////////////////////////////////////////////////////////////////////
3 // File : qsplitterP.cxx
4 // Description : the patch for Qt's QSplitter class (qsplitter.cpp)
5 /////////////////////////////////////////////////////////////////////////////
7 /****************************************************************************
14 ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
16 ** This file is part of the widgets module of the Qt GUI Toolkit.
18 ** This file may be distributed under the terms of the Q Public License
19 ** as defined by Trolltech AS of Norway and appearing in the file
20 ** LICENSE.QPL included in the packaging of this file.
22 ** This file may be distributed and/or modified under the terms of the
23 ** GNU General Public License version 2 as published by the Free Software
24 ** Foundation and appearing in the file LICENSE.GPL included in the
25 ** packaging of this file.
27 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
28 ** licenses may use this file in accordance with the Qt Commercial License
29 ** Agreement provided with the Software.
31 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
32 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
34 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
35 ** information about Qt Commercial License Agreements.
36 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
37 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
39 ** Contact info@trolltech.com if any conditions of this licensing are
42 **********************************************************************/
44 #include "qsplitterP.h"
45 #ifndef QT_NO_COMPLEXWIDGETS
49 #include <qdrawutil.h>
51 #include <private/qlayoutengine_p.h>
56 #include <qptrlist.h> //qt3.x
57 #include <qmemarray.h> //qt3.x
58 #include <qstyle.h> //qt3.x
61 #include <qobjectlist.h>
62 #include <qapplication.h> //sendPostedEvents
65 #define SPLITTER_ICON_WIDTH 10
66 #define SPLITTER_ICON_HEIGHT 12
68 static int mouseOffset;
69 static int opaqueOldPos = -1; //### there's only one mouse, but this is a bit risky
71 static const char* splitter_left_xpm[] = {
73 " s none m none c none",
74 ". s iconColor1 m black c black",
82 static const char* splitter_right_xpm[] = {
84 " s iconColor1 m black c black",
85 ". s none m none c none",
93 static const char* splitter_up_xpm[] = {
95 " s none m none c none",
96 ". s iconColor1 m black c black",
104 static const char* splitter_down_xpm[] = {
106 " s iconColor1 m black c black",
107 ". s none m none c none",
115 QSplitterPHandle::QSplitterPHandle( Qt::Orientation o,
116 QSplitterP *parent, const char * name )
117 : QWidget( parent, name )
121 left = new QPushButton(this);
122 right = new QPushButton(this);
123 unleft = new QPushButton(this);
124 unright = new QPushButton(this);
128 left->setAutoDefault(false); unleft->setAutoDefault(false);
129 right->setAutoDefault(false); unright->setAutoDefault(false);
130 left->setFlat(true); right->setFlat(true); unleft->setFlat(true); unright->setFlat(true);
131 left->setCursor( arrowCursor ); right->setCursor( arrowCursor );
132 unleft->setCursor( arrowCursor ); unright->setCursor( arrowCursor );
134 // VSR 21/11/02 -> ================================
135 setMinimumSize( 1, 1 );
136 // VSR 21/11/02 <- ================================
138 connect(left, SIGNAL(clicked()), this, SLOT(onBeforeCompress()));
139 connect(right, SIGNAL(clicked()), this, SLOT(onAfterCompress()));
140 connect(unleft, SIGNAL(clicked()), this, SLOT(onBeforeUnCompress()));
141 connect(unright, SIGNAL(clicked()), this, SLOT(onAfterUnCompress()));
144 void QSplitterPHandle::onBeforeCompress() {
145 oldpos = s->pick(pos());
146 int pos = s->pick(s->widgetBefore(id())->pos());
147 s->compress(s->widgetBefore(id()));
148 s->moveSplitter(pos, id());
149 s->updateSplitterHandles();
152 void QSplitterPHandle::onBeforeUnCompress() {
153 s->unCompress(s->widgetBefore(id()));
154 s->moveSplitter(oldpos, id());
155 s->updateSplitterHandles();
158 void QSplitterPHandle::onAfterCompress() {
159 oldpos = s->pick(pos());
160 int pos = s->pick(s->widgetAfter(id())->pos()) + s->pick(s->widgetAfter(id())->size()) - s->pick(size());
161 s->compress(s->widgetAfter(id()));
162 s->moveSplitter(pos, id());
163 s->updateSplitterHandles();
166 void QSplitterPHandle::onAfterUnCompress() {
167 s->unCompress(s->widgetAfter(id()));
168 s->moveSplitter(oldpos, id());
169 s->updateSplitterHandles();
172 // VSR 21/11/02 -> ================================
173 void QSplitterPHandle::compressAfter()
178 void QSplitterPHandle::unCompressAfter()
183 void QSplitterPHandle::compressBefore()
188 void QSplitterPHandle::unCompressBefore()
190 onBeforeUnCompress();
192 // VSR 21/11/02 <- ================================
194 QSizePolicy QSplitterPHandle::sizePolicy() const
197 return QWidget::sizePolicy();
200 QSize QSplitterPHandle::sizeHint() const
203 int sw = style().splitterWidth();
204 return QSize(sw,sw).expandedTo( QApplication::globalStrut() );
206 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this);
207 return (style().sizeFromContents(QStyle::CT_Splitter, s, QSize(sw, sw)).
208 expandedTo(QApplication::globalStrut()));
212 void QSplitterPHandle::setOrientation( Qt::Orientation o )
216 if ( o == QSplitterP::Horizontal )
217 setCursor( splitHCursor );
219 setCursor( splitVCursor );
223 if ( orient == QSplitterP::Horizontal )
225 lp = QPixmap(splitter_left_xpm);
226 rp = QPixmap(splitter_right_xpm);
230 lp = QPixmap(splitter_up_xpm);
231 rp = QPixmap(splitter_down_xpm);
234 right->setPixmap(rp);
235 unleft->setPixmap(rp);
236 unright->setPixmap(lp);
239 void QSplitterPHandle::mouseMoveEvent( QMouseEvent *e )
241 if ( !(e->state()&LeftButton) )
243 QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()))
246 s->moveSplitter( pos, id() );
248 int min = pos; int max = pos;
249 s->getRange( id(), &min, &max );
250 s->setRubberband( QMAX( min, QMIN(max, pos )));
254 void QSplitterPHandle::mousePressEvent( QMouseEvent *e )
256 if ( e->button() == LeftButton )
257 mouseOffset = s->pick(e->pos());
260 void QSplitterPHandle::mouseReleaseEvent( QMouseEvent *e )
262 if ( !opaque() && e->button() == LeftButton ) {
263 QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()));
264 s->setRubberband( -1 );
265 s->moveSplitter( pos, id() );
269 void QSplitterPHandle::paintEvent( QPaintEvent * )
273 s->drawSplitter( &p, 0, 0, width(), height() );
276 void QSplitterPHandle::updateButtonState() {
277 if (!s->isCompressEnabled()) {
284 if ( orient == QSplitterP::Horizontal )
286 left->setGeometry( QRect( QPoint( (width() - SPLITTER_ICON_WIDTH)/2, 0 ),
287 QSize ( SPLITTER_ICON_WIDTH, SPLITTER_ICON_HEIGHT ) ) );
288 right->setGeometry( QRect( QPoint( (width() - SPLITTER_ICON_WIDTH)/2, SPLITTER_ICON_HEIGHT ),
289 QSize ( SPLITTER_ICON_WIDTH, SPLITTER_ICON_HEIGHT ) ) );
290 unleft->setGeometry( left->geometry() );
291 unright->setGeometry( right->geometry() );
295 left->setGeometry( QRect( QPoint( 0, (height() - SPLITTER_ICON_WIDTH)/2 ),
296 QSize ( SPLITTER_ICON_HEIGHT, SPLITTER_ICON_WIDTH ) ) );
297 right->setGeometry( QRect( QPoint( SPLITTER_ICON_HEIGHT, (height() - SPLITTER_ICON_WIDTH)/2),
298 QSize ( SPLITTER_ICON_HEIGHT, SPLITTER_ICON_WIDTH ) ) );
299 unleft->setGeometry( left->geometry() );
300 unright->setGeometry( right->geometry() );
302 if ( s->isCompressed( s->widgetBefore( id() ) ) ) {
305 right->setEnabled(false);
310 right->setEnabled(true);
312 if ( s->isCompressed( s->widgetAfter( id() ) ) ) {
315 left->setEnabled(false);
320 left->setEnabled(true);
325 class QSplitterPLayoutStruct
328 QSplitterP::ResizeMode mode;
337 QSplitterPData() : opaque( FALSE ), firstShow( TRUE ) {}
339 QList<QSplitterPLayoutStruct> list;
347 \class QSplitter qsplitter.h
348 \brief The QSplitter class implements a splitter widget.
352 A splitter lets the user control the size of child widgets by
353 dragging the boundary between the children. Any number of widgets
356 To show a QListBox, a QListView and a QMultiLineEdit side by side:
359 QSplitter *split = new QSplitter( parent );
360 QListBox *lb = new QListBox( split );
361 QListView *lv = new QListView( split );
362 QMultiLineEdit *ed = new QMultiLineEdit( split );
365 In QSplitter the boundary can be either horizontal or vertical. The
366 default is horizontal (the children are side by side) and you
367 can use setOrientation( QSplitter::Vertical ) to set it to vertical.
369 By default, all widgets can be as large or as small as the user
370 wishes, down to \link QWidget::minimumSizeHint() minimumSizeHint()\endlink.
371 You can naturally use setMinimumSize() and/or
372 setMaximumSize() on the children. Use setResizeMode() to specify that
373 a widget should keep its size when the splitter is resized.
375 QSplitter normally resizes the children only at the end of a
376 resize operation, but if you call setOpaqueResize( TRUE ), the
377 widgets are resized as often as possible.
379 The initial distribution of size between the widgets is determined
380 by the initial size of each widget. You can also use setSizes() to
381 set the sizes of all the widgets. The function sizes() returns the
382 sizes set by the user.
384 If you hide() a child, its space will be distributed among the other
385 children. When you show() it again, it will be reinstated.
387 <img src=qsplitter-m.png> <img src=qsplitter-w.png>
394 QSize QSplitterP::minSize( const QWidget *w ) const
396 if ( isCompressed(w) && (data->list.count() > 1 ) ) return QSize(0,0);
397 QSize min = w->minimumSize();
399 if ( min.height() <= 0 || min.width() <= 0 )
400 s = w->minimumSizeHint();
401 if ( min.height() > 0 )
402 s.setHeight( min.height() );
403 if ( min.width() > 0 )
404 s.setWidth( min.width() );
405 return s.expandedTo(QSize(0,0));
408 QSize QSplitterP::maxSize( const QWidget* w ) const
410 if ( isCompressed(w) && (data->list.count() > 1 ) ) return QSize(0,0);
411 else return w->maximumSize();
415 Constructs a horizontal splitter.
418 QSplitterP::QSplitterP( QWidget *parent, const char *name )
419 :QFrame(parent,name,WPaintUnclipped)
427 Constructs splitter with orientation \a o.
430 QSplitterP::QSplitterP( Orientation o, QWidget *parent, const char *name )
431 :QFrame(parent,name,WPaintUnclipped)
439 Destructs the splitter.
442 QSplitterP::~QSplitterP()
444 data->list.setAutoDelete( TRUE );
449 void QSplitterP::init()
451 data = new QSplitterPData;
452 if ( orient == Horizontal )
453 setSizePolicy( QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Minimum) );
455 setSizePolicy( QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Fixed) );
456 compressed_widgets.clear();
457 compress_flag = false;
462 \fn void QSplitter::refresh()
464 Updates the splitter state. You should not need to call this
465 function during normal use of the splitter.
469 /*! Sets the orientation to \a o. By default the orientation is
470 horizontal (the widgets are side by side).
475 void QSplitterP::setOrientation( Orientation o )
481 if ( orient == Horizontal )
482 setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) );
484 setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
486 QSplitterPLayoutStruct *s = data->list.first();
489 ((QSplitterPHandle*)s->wid)->setOrientation( o );
490 s = data->list.next(); // ### next at end of loop, no iterator
492 recalc( isVisible() );
497 \fn Orientation QSplitter::orientation() const
499 Returns the orientation (\c Horizontal or \c Vertical) of the splitter.
506 void QSplitterP::resizeEvent( QResizeEvent * )
513 Inserts the widget \a w at the end, or at the beginning if \a first is TRUE
515 It is the responsibility of the caller of this function to make sure
516 that \a w is not already in the splitter, and to call recalcId if
517 needed. (If \a first is TRUE, then recalcId is very probably
521 QSplitterPLayoutStruct *QSplitterP::addWidget( QWidget *w, bool first )
523 QSplitterPLayoutStruct *s;
524 QSplitterPHandle *newHandle = 0;
525 if ( data->list.count() > 0 ) {
526 s = new QSplitterPLayoutStruct;
528 newHandle = new QSplitterPHandle( orientation(), this );
530 newHandle->setId(data->list.count());
531 s->isSplitter = TRUE;
532 s->sizer = pick( newHandle->sizeHint() );
534 data->list.insert( 0, s );
536 data->list.append( s );
538 s = new QSplitterPLayoutStruct;
541 if ( !testWState( WState_Resized ) && w->sizeHint().isValid() )
542 s->sizer = pick( w->sizeHint() );
544 s->sizer = pick( w->size() );
545 s->isSplitter = FALSE;
547 data->list.insert( 0, s );
549 data->list.append( s );
550 if ( newHandle && isVisible() )
551 newHandle->show(); //will trigger sending of post events
557 Tells the splitter that a child widget has been inserted/removed.
560 void QSplitterP::childEvent( QChildEvent *c )
562 if ( c->type() == QEvent::ChildInserted ) {
563 if ( !c->child()->isWidgetType() )
566 if ( ((QWidget*)c->child())->testWFlags( WType_TopLevel ) )
569 QSplitterPLayoutStruct *s = data->list.first();
571 if ( s->wid == c->child() )
573 s = data->list.next();
575 addWidget( (QWidget*)c->child() );
576 recalc( isVisible() );
578 } else if ( c->type() == QEvent::ChildRemoved ) {
579 QSplitterPLayoutStruct *p = 0;
580 if ( data->list.count() > 1 )
581 p = data->list.at(1); //remove handle _after_ first widget.
582 QSplitterPLayoutStruct *s = data->list.first();
584 if ( s->wid == c->child() ) {
585 data->list.removeRef( s );
587 if ( p && p->isSplitter ) {
588 data->list.removeRef( p );
589 delete p->wid; //will call childEvent
597 s = data->list.next();
604 Shows a rubber band at position \a p. If \a p is negative, the
605 rubber band is removed.
608 void QSplitterP::setRubberband( int p )
610 QPainter paint( this );
611 paint.setPen( gray );
612 paint.setBrush( gray );
613 paint.setRasterOp( XorROP );
614 QRect r = contentsRect();
615 const int rBord = 3; //Themable????
617 const int sw = style().splitterWidth();
619 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); //qt3.x
621 if ( orient == Horizontal ) {
622 if ( opaqueOldPos >= 0 )
623 paint.drawRect( opaqueOldPos + sw/2 - rBord , r.y(),
624 2*rBord, r.height() );
626 paint.drawRect( p + sw/2 - rBord, r.y(), 2*rBord, r.height() );
628 if ( opaqueOldPos >= 0 )
629 paint.drawRect( r.x(), opaqueOldPos + sw/2 - rBord,
630 r.width(), 2*rBord );
632 paint.drawRect( r.x(), p + sw/2 - rBord, r.width(), 2*rBord );
640 bool QSplitterP::event( QEvent *e )
642 if ( e->type() == QEvent::LayoutHint || ( e->type() == QEvent::Show && data->firstShow ) ) {
643 recalc( isVisible() );
644 if ( e->type() == QEvent::Show )
645 data->firstShow = FALSE;
647 return QWidget::event( e );
652 Draws the splitter handle in the rectangle described by \a x, \a y,
653 \a w, \a h using painter \a p.
654 \sa QStyle::drawSplitter
657 void QSplitterP::drawSplitter( QPainter *p,
658 QCOORD x, QCOORD y, QCOORD w, QCOORD h )
661 style().drawSplitter( p, x, y, w, h, colorGroup(), orient );
663 style().drawPrimitive(QStyle::PE_Splitter, p, QRect(x, y, w, h), colorGroup(),
664 (orientation() == Qt::Horizontal ?
665 QStyle::Style_Horizontal : 0));
671 Returns the id of the splitter to the right of or below the widget \a w,
672 or 0 if there is no such splitter.
673 (ie. it is either not in this QSplitter, or it is at the end).
676 int QSplitterP::idAfter( QWidget* w ) const
678 QSplitterPLayoutStruct *s = data->list.first();
681 if ( s->isSplitter && seen_w )
682 return data->list.at();
683 if ( !s->isSplitter && s->wid == w )
685 s = data->list.next();
690 // VSR 21/11/02 -> ================================
691 QSplitterPHandle* QSplitterP::getHandleAfter(QWidget* w)
693 QSplitterPLayoutStruct *s = data->list.first();
696 if ( s->isSplitter && seen_w )
697 return (QSplitterPHandle*)s->wid;
698 if ( !s->isSplitter && s->wid == w )
700 s = data->list.next();
705 QSplitterPHandle* QSplitterP::getHandleBefore(QWidget* w)
707 QSplitterPLayoutStruct *s = data->list.first();
708 QSplitterPHandle* h = 0;
711 h = (QSplitterPHandle*)s;
712 if ( !s->isSplitter && s->wid == w )
714 s = data->list.next();
718 // VSR 21/11/02 <- ================================
720 QWidget* QSplitterP::widgetBefore( int id ) const
722 QSplitterPLayoutStruct *s = data->list.first();
725 if ( !s->isSplitter ) {
727 if (idAfter(w) == id) return w;
729 s = data->list.next();
734 QWidget* QSplitterP::widgetAfter( int id ) const
736 QSplitterPLayoutStruct *s = data->list.first();
739 if ( !s->isSplitter && seen_s )
741 if ( s->isSplitter && data->list.at() == id )
743 s = data->list.next();
748 void QSplitterP::unCompress(QWidget* w) {
749 compressed_widgets.remove(w);
752 void QSplitterP::compress(QWidget* w)
754 if (!isCompressed(w)) compressed_widgets.append(w);
757 bool QSplitterP::isCompressed(const QWidget* w) const {
758 QWidget* t = (QWidget*)w;
759 if (compressed_widgets.containsRef(t)==0) return false;
764 Moves the left/top edge of the splitter handle with id \a id as
765 close as possible to \a p which is the distance from the left (or
766 top) edge of the widget.
770 void QSplitterP::moveSplitter( QCOORD p, int id )
772 p = adjustPos( p, id );
774 QSplitterPLayoutStruct *s = data->list.at(id);
775 int oldP = orient == Horizontal? s->wid->x() : s->wid->y();
776 bool upLeft = p < oldP;
778 moveAfter( p, id, upLeft );
779 moveBefore( p-1, id-1, upLeft );
785 void QSplitterP::setG( QWidget *w, int p, int s )
787 if ( orient == Horizontal )
788 w->setGeometry( p, contentsRect().y(), s, contentsRect().height() );
790 w->setGeometry( contentsRect().x(), p, contentsRect().width(), s );
795 Places the right/bottom edge of the widget at \a id at position \a pos.
800 void QSplitterP::moveBefore( int pos, int id, bool upLeft )
802 QSplitterPLayoutStruct *s = data->list.at(id);
806 if ( w->isHidden() ) {
807 moveBefore( pos, id-1, upLeft );
808 } else if ( s->isSplitter ) {
811 setG( w, pos-dd+1, dd );
812 moveBefore( pos-dd, id-1, upLeft );
814 moveBefore( pos-dd, id-1, upLeft );
815 setG( w, pos-dd+1, dd );
818 int left = pick( w->pos() );
819 int dd = pos - left + 1;
820 dd = QMAX( pick(minSize(w)), QMIN(dd, pick(maxSize(w))));
821 int newLeft = pos-dd+1;
822 setG( w, newLeft, dd );
823 if ( left != newLeft )
824 moveBefore( newLeft-1, id-1, upLeft );
830 Places the left/top edge of the widget at \a id at position \a pos.
835 void QSplitterP::moveAfter( int pos, int id, bool upLeft )
837 QSplitterPLayoutStruct *s = id < int(data->list.count()) ?
838 data->list.at(id) : 0;
842 if ( w->isHidden() ) {
843 moveAfter( pos, id+1, upLeft );
844 } else if ( pick( w->pos() ) == pos ) {
845 //No need to do anything if it's already there.
847 } else if ( s->isSplitter ) {
851 moveAfter( pos+dd, id+1, upLeft );
853 moveAfter( pos+dd, id+1, upLeft );
857 int right = pick( w->geometry().bottomRight() );
859 int dd = right - pos + 1;
860 dd = QMAX( pick(minSize(w)), QMIN(dd, pick(maxSize(w))));
861 int newRight = pos+dd-1;
863 moveAfter( newRight+1, id+1, upLeft );
869 Returns the valid range of the splitter with id \a id in \a min and \a max.
874 void QSplitterP::getRange( int id, int *min, int *max )
876 int minB = 0; //before
879 int maxA = 0; //after
880 int n = data->list.count();
881 if ( id < 0 || id >= n )
884 for ( i = 0; i < id; i++ ) {
885 QSplitterPLayoutStruct *s = data->list.at(i);
886 if ( s->isSplitter ) {
890 minB += pick( minSize(s->wid) );
891 maxB += pick( maxSize(s->wid) );
894 for ( i = id; i < n; i++ ) {
895 QSplitterPLayoutStruct *s = data->list.at(i);
896 if ( s->isSplitter ) {
900 minA += pick( minSize(s->wid) );
901 maxA += pick( maxSize(s->wid) );
904 QRect r = contentsRect();
906 *min = pick(r.topLeft()) + QMAX( minB, pick(r.size())-maxA );
908 *max = pick(r.topLeft()) + QMIN( maxB, pick(r.size())-minA );
914 Returns the legal position closest to \a p of the splitter with id \a id.
919 int QSplitterP::adjustPos( int p, int id )
923 getRange( id, &min, &max );
924 p = QMAX( min, QMIN( p, max ) );
930 void QSplitterP::doResize()
932 QRect r = contentsRect();
934 int n = data->list.count();
935 QArray<QLayoutStruct> a( n );
936 for ( i = 0; i< n; i++ ) {
938 QSplitterPLayoutStruct *s = data->list.at(i);
939 if ( s->wid->isHidden() ) {
941 a[i].sizeHint = a[i].minimumSize = 0;
942 a[i].maximumSize = 0;
943 } else if ( s->isSplitter ) {
945 a[i].sizeHint = a[i].minimumSize = a[i].maximumSize = s->sizer;
947 } else if ( s->mode == KeepSize ) {
949 a[i].minimumSize = pick( minSize(s->wid) );
950 a[i].sizeHint = s->sizer;
951 a[i].maximumSize = pick( maxSize(s->wid) );
953 } else if ( s->mode == FollowSizeHint ) {
955 a[i].minimumSize = a[i].sizeHint = pick( s->wid->sizeHint() );
956 a[i].maximumSize = pick( maxSize(s->wid) );
958 } else { //proportional
959 a[i].stretch = s->sizer;
960 a[i].maximumSize = pick( maxSize(s->wid) );
961 a[i].sizeHint = a[i].minimumSize = pick( minSize(s->wid) );
966 qGeomCalc( a, 0, n, pick( r.topLeft() ), pick( r.size() ), 0 );
967 for ( i = 0; i< n; i++ ) {
968 QSplitterPLayoutStruct *s = data->list.at(i);
969 if ( orient == Horizontal )
970 s->wid->setGeometry( a[i].pos, r.top(), a[i].size, r.height() );
972 s->wid->setGeometry( r.left(), a[i].pos, r.width(), a[i].size );
978 void QSplitterP::recalc( bool update )
980 int fi = 2*frameWidth();
983 int maxt = QWIDGETSIZE_MAX;
985 int n = data->list.count();
988 The splitter before a hidden widget is always hidden.
989 The splitter before the first visible widget is hidden.
990 The splitter before any other visible widget is visible.
992 for ( int i = 0; i< n; i++ ) {
993 QSplitterPLayoutStruct *s = data->list.at(i);
994 if ( !s->isSplitter ) {
995 QSplitterPLayoutStruct *p = (i > 0) ? p = data->list.at( i-1 ) : 0;
996 if ( p && p->isSplitter )
997 if ( first || s->wid->isHidden() )
998 p->wid->hide(); //may trigger new recalc
1000 p->wid->show(); //may trigger new recalc
1001 if ( !s->wid->isHidden() )
1007 for ( int j = 0; j< n; j++ ) {
1008 QSplitterPLayoutStruct *s = data->list.at(j);
1009 if ( !s->wid->isHidden() ) {
1011 if ( s->isSplitter ) {
1015 QSize minS = minSize(s->wid);
1016 minl += pick( minS );
1017 maxl += pick( maxSize(s->wid) );
1018 mint = QMAX( mint, trans( minS ));
1019 int tm = trans( maxSize(s->wid) );
1021 maxt = QMIN( maxt, tm );
1028 maxl = QMIN( maxl, QWIDGETSIZE_MAX );
1032 if ( orient == Horizontal ) {
1033 setMaximumSize( maxl, maxt );
1034 setMinimumSize( minl, mint );
1036 setMaximumSize( maxt, maxl );
1037 setMinimumSize( mint, minl );
1043 /*! \enum QSplitter::ResizeMode
1045 This enum type describes how QSplitter will resize each of its child widgets. The currently defined values are: <ul>
1047 <li> \c Stretch - the widget will be resized when the splitter
1050 <li> \c KeepSize - QSplitter will try to keep this widget's size
1053 <li> \c FollowSizeHint - QSplitter will resize the widget when its
1061 Sets resize mode of \a w to \a mode.
1066 void QSplitterP::setResizeMode( QWidget *w, ResizeMode mode )
1068 processChildEvents();
1069 QSplitterPLayoutStruct *s = data->list.first();
1071 if ( s->wid == w ) {
1075 s = data->list.next();
1077 s = addWidget( w, TRUE );
1083 Returns TRUE if opaque resize is on, FALSE otherwise.
1085 \sa setOpaqueResize()
1088 bool QSplitterP::opaqueResize() const
1090 return data->opaque;
1095 Sets opaque resize to \a on. Opaque resize is initially turned off.
1100 void QSplitterP::setOpaqueResize( bool on )
1107 Moves \a w to the leftmost/top position.
1110 void QSplitterP::moveToFirst( QWidget *w )
1112 processChildEvents();
1114 QSplitterPLayoutStruct *s = data->list.first();
1116 if ( s->wid == w ) {
1118 QSplitterPLayoutStruct *p = data->list.prev();
1119 if ( p ) { // not already at first place
1120 data->list.take(); //take p
1121 data->list.take(); // take s
1122 data->list.insert( 0, p );
1123 data->list.insert( 0, s );
1127 s = data->list.next();
1130 addWidget( w, TRUE );
1136 Moves \a w to the rightmost/bottom position.
1139 void QSplitterP::moveToLast( QWidget *w )
1141 processChildEvents();
1143 QSplitterPLayoutStruct *s = data->list.first();
1145 if ( s->wid == w ) {
1147 data->list.take(); // take s
1148 QSplitterPLayoutStruct *p = data->list.current();
1149 if ( p ) { // the splitter handle after s
1150 data->list.take(); //take p
1151 data->list.append( p );
1153 data->list.append( s );
1156 s = data->list.next();
1164 void QSplitterP::recalcId()
1166 int n = data->list.count();
1167 for ( int i = 0; i < n; i++ ) {
1168 QSplitterPLayoutStruct *s = data->list.at(i);
1169 if ( s->isSplitter )
1170 ((QSplitterPHandle*)s->wid)->setId(i);
1177 QSize QSplitterP::sizeHint() const
1183 const QObjectList * c = children();
1184 QObjectListIt it( *c );
1187 while( (o=it.current()) != 0 ) {
1189 if ( o->isWidgetType() &&
1190 !((QWidget*)o)->isHidden() ) {
1191 QSize s = ((QWidget*)o)->sizeHint();
1192 if ( s.isValid() ) {
1194 t = QMAX( t, trans( s ) );
1199 return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
1207 QSize QSplitterP::minimumSizeHint() const
1213 const QObjectList * c = children();
1214 QObjectListIt it( *c );
1217 while( (o=it.current()) != 0 ) {
1219 if ( o->isWidgetType() &&
1220 !((QWidget*)o)->isHidden() ) {
1221 QSize s = minSize((QWidget*)o);
1222 if ( s.isValid() ) {
1224 t = QMAX( t, trans( s ) );
1229 return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
1236 QSizePolicy QSplitterP::sizePolicy() const
1238 return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
1243 Calculates stretch parameters from current sizes
1246 void QSplitterP::storeSizes()
1248 QSplitterPLayoutStruct *s = data->list.first();
1250 if ( !s->isSplitter )
1251 s->sizer = pick( s->wid->size() );
1252 s = data->list.next();
1257 #if 0 // ### remove this code ASAP
1260 Hides \a w if \a hide is TRUE, and updates the splitter.
1262 \warning Due to a limitation in the current implementation,
1263 calling QWidget::hide() will not work.
1266 void QSplitterP::setHidden( QWidget *w, bool hide )
1270 } else if ( w == w2 ) {
1274 qWarning( "QSplitterP::setHidden(), unknown widget" );
1287 Returns the hidden status of \a w
1290 bool QSplitterP::isHidden( QWidget *w ) const
1298 qWarning( "QSplitterP::isHidden(), unknown widget" );
1306 Returns a list of the size parameters of all the widgets in this
1309 Giving the values to setSizes() will give a splitter with the same
1313 QValueList<int> QSplitterP::sizes() const
1315 if ( !testWState(WState_Polished) ) {
1316 QWidget* that = (QWidget*) this;
1319 QValueList<int> list;
1320 QSplitterPLayoutStruct *s = data->list.first();
1322 if ( !s->isSplitter )
1323 list.append( s->sizer );
1324 s = data->list.next();
1332 Sets the size parameters to the values given in \a list.
1333 If the splitterP is horizontal, the values set the sizes from
1334 left to right. If it is vertical, the sizes are applied from
1336 Extra values in \a list are ignored.
1338 If \a list contains too few values, the result is undefined
1339 but the program will still be well-behaved.
1342 void QSplitterP::setSizes( QValueList<int> list )
1344 processChildEvents();
1345 QValueList<int>::Iterator it = list.begin();
1346 QSplitterPLayoutStruct *s = data->list.first();
1347 while ( s && it != list.end() ) {
1348 if ( !s->isSplitter ) {
1352 s = data->list.next();
1359 Gets all posted child events, ensuring that the internal state of
1360 the splitter is consistent with the programmer's idea.
1363 void QSplitterP::processChildEvents()
1365 QApplication::sendPostedEvents( this, QEvent::ChildInserted );
1373 void QSplitterP::styleChange( QStyle& old )
1375 #if QT_VERSION < 300
1376 int sw = style().splitterWidth();
1378 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); //qt3.x
1380 QSplitterPLayoutStruct *s = data->list.first();
1382 if ( s->isSplitter )
1384 s = data->list.next();
1387 QFrame::styleChange( old );
1391 bool QSplitterP::isCompressEnabled() const
1393 return compress_flag;
1396 void QSplitterP::setCompressEnabled(bool on) {
1400 void QSplitterP::updateSplitterHandles() const {
1401 QSplitterPLayoutStruct *s = data->list.first();
1403 if ( s->isSplitter )
1404 ((QSplitterPHandle*)s->wid)->updateButtonState();
1405 s = data->list.next();