2 /****************************************************************************
9 ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
11 ** This file is part of the widgets module of the Qt GUI Toolkit.
13 ** This file may be distributed under the terms of the Q Public License
14 ** as defined by Trolltech AS of Norway and appearing in the file
15 ** LICENSE.QPL included in the packaging of this file.
17 ** This file may be distributed and/or modified under the terms of the
18 ** GNU General Public License version 2 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.GPL included in the
20 ** packaging of this file.
22 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
23 ** licenses may use this file in accordance with the Qt Commercial License
24 ** Agreement provided with the Software.
26 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
27 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
30 ** information about Qt Commercial License Agreements.
31 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
32 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
34 ** Contact info@trolltech.com if any conditions of this licensing are
37 **********************************************************************/
38 #include "qsplitterP.h"
39 #ifndef QT_NO_COMPLEXWIDGETS
43 #include <qdrawutil.h>
45 #include <private/qlayoutengine_p.h>
50 #include <qptrlist.h> //qt3.x
51 #include <qmemarray.h> //qt3.x
52 #include <qstyle.h> //qt3.x
55 #include <qobjectlist.h>
56 #include <qapplication.h> //sendPostedEvents
58 #define SPLITTER_ICON_WIDTH 10
59 #define SPLITTER_ICON_HEIGHT 12
61 static int mouseOffset;
62 static int opaqueOldPos = -1; //### there's only one mouse, but this is a bit risky
64 static const char* splitter_left_xpm[] = {
66 " s none m none c none",
67 ". s iconColor1 m black c black",
75 static const char* splitter_right_xpm[] = {
77 " s iconColor1 m black c black",
78 ". s none m none c none",
86 static const char* splitter_up_xpm[] = {
88 " s none m none c none",
89 ". s iconColor1 m black c black",
97 static const char* splitter_down_xpm[] = {
99 " s iconColor1 m black c black",
100 ". s none m none c none",
108 QSplitterPHandle::QSplitterPHandle( Qt::Orientation o,
109 QSplitterP *parent, const char * name )
110 : QWidget( parent, name )
114 left = new QPushButton(this);
115 right = new QPushButton(this);
116 unleft = new QPushButton(this);
117 unright = new QPushButton(this);
121 left->setAutoDefault(false); unleft->setAutoDefault(false);
122 right->setAutoDefault(false); unright->setAutoDefault(false);
123 left->setFlat(true); right->setFlat(true); unleft->setFlat(true); unright->setFlat(true);
124 left->setCursor( arrowCursor ); right->setCursor( arrowCursor );
125 unleft->setCursor( arrowCursor ); unright->setCursor( arrowCursor );
127 // VSR 21/11/02 -> ================================
128 setMinimumSize( 1, 1 );
129 // VSR 21/11/02 <- ================================
131 connect(left, SIGNAL(clicked()), this, SLOT(onBeforeCompress()));
132 connect(right, SIGNAL(clicked()), this, SLOT(onAfterCompress()));
133 connect(unleft, SIGNAL(clicked()), this, SLOT(onBeforeUnCompress()));
134 connect(unright, SIGNAL(clicked()), this, SLOT(onAfterUnCompress()));
137 void QSplitterPHandle::onBeforeCompress() {
138 oldpos = s->pick(pos());
139 int pos = s->pick(s->widgetBefore(id())->pos());
140 s->compress(s->widgetBefore(id()));
141 s->moveSplitter(pos, id());
142 s->updateSplitterHandles();
145 void QSplitterPHandle::onBeforeUnCompress() {
146 s->unCompress(s->widgetBefore(id()));
147 s->moveSplitter(oldpos, id());
148 s->updateSplitterHandles();
151 void QSplitterPHandle::onAfterCompress() {
152 oldpos = s->pick(pos());
153 int pos = s->pick(s->widgetAfter(id())->pos()) + s->pick(s->widgetAfter(id())->size()) - s->pick(size());
154 s->compress(s->widgetAfter(id()));
155 s->moveSplitter(pos, id());
156 s->updateSplitterHandles();
159 void QSplitterPHandle::onAfterUnCompress() {
160 s->unCompress(s->widgetAfter(id()));
161 s->moveSplitter(oldpos, id());
162 s->updateSplitterHandles();
165 // VSR 21/11/02 -> ================================
166 void QSplitterPHandle::compressAfter()
171 void QSplitterPHandle::unCompressAfter()
176 void QSplitterPHandle::compressBefore()
181 void QSplitterPHandle::unCompressBefore()
183 onBeforeUnCompress();
185 // VSR 21/11/02 <- ================================
187 QSizePolicy QSplitterPHandle::sizePolicy() const
190 return QWidget::sizePolicy();
193 QSize QSplitterPHandle::sizeHint() const
196 int sw = style().splitterWidth();
197 return QSize(sw,sw).expandedTo( QApplication::globalStrut() );
199 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this);
200 return (style().sizeFromContents(QStyle::CT_Splitter, s, QSize(sw, sw)).
201 expandedTo(QApplication::globalStrut()));
205 void QSplitterPHandle::setOrientation( Qt::Orientation o )
209 if ( o == QSplitterP::Horizontal )
210 setCursor( splitHCursor );
212 setCursor( splitVCursor );
216 if ( orient == QSplitterP::Horizontal )
218 lp = QPixmap(splitter_left_xpm);
219 rp = QPixmap(splitter_right_xpm);
223 lp = QPixmap(splitter_up_xpm);
224 rp = QPixmap(splitter_down_xpm);
227 right->setPixmap(rp);
228 unleft->setPixmap(rp);
229 unright->setPixmap(lp);
232 void QSplitterPHandle::mouseMoveEvent( QMouseEvent *e )
234 if ( !(e->state()&LeftButton) )
236 QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()))
239 s->moveSplitter( pos, id() );
241 int min = pos; int max = pos;
242 s->getRange( id(), &min, &max );
243 s->setRubberband( QMAX( min, QMIN(max, pos )));
247 void QSplitterPHandle::mousePressEvent( QMouseEvent *e )
249 if ( e->button() == LeftButton )
250 mouseOffset = s->pick(e->pos());
253 void QSplitterPHandle::mouseReleaseEvent( QMouseEvent *e )
255 if ( !opaque() && e->button() == LeftButton ) {
256 QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()));
257 s->setRubberband( -1 );
258 s->moveSplitter( pos, id() );
262 void QSplitterPHandle::paintEvent( QPaintEvent * )
266 s->drawSplitter( &p, 0, 0, width(), height() );
269 void QSplitterPHandle::updateButtonState() {
270 if (!s->isCompressEnabled()) {
277 if ( orient == QSplitterP::Horizontal )
279 left->setGeometry( QRect( QPoint( (width() - SPLITTER_ICON_WIDTH)/2, 0 ),
280 QSize ( SPLITTER_ICON_WIDTH, SPLITTER_ICON_HEIGHT ) ) );
281 right->setGeometry( QRect( QPoint( (width() - SPLITTER_ICON_WIDTH)/2, SPLITTER_ICON_HEIGHT ),
282 QSize ( SPLITTER_ICON_WIDTH, SPLITTER_ICON_HEIGHT ) ) );
283 unleft->setGeometry( left->geometry() );
284 unright->setGeometry( right->geometry() );
288 left->setGeometry( QRect( QPoint( 0, (height() - SPLITTER_ICON_WIDTH)/2 ),
289 QSize ( SPLITTER_ICON_HEIGHT, SPLITTER_ICON_WIDTH ) ) );
290 right->setGeometry( QRect( QPoint( SPLITTER_ICON_HEIGHT, (height() - SPLITTER_ICON_WIDTH)/2),
291 QSize ( SPLITTER_ICON_HEIGHT, SPLITTER_ICON_WIDTH ) ) );
292 unleft->setGeometry( left->geometry() );
293 unright->setGeometry( right->geometry() );
295 if ( s->isCompressed( s->widgetBefore( id() ) ) ) {
298 right->setEnabled(false);
303 right->setEnabled(true);
305 if ( s->isCompressed( s->widgetAfter( id() ) ) ) {
308 left->setEnabled(false);
313 left->setEnabled(true);
318 class QSplitterPLayoutStruct
321 QSplitterP::ResizeMode mode;
330 QSplitterPData() : opaque( FALSE ), firstShow( TRUE ) {}
332 QList<QSplitterPLayoutStruct> list;
340 \class QSplitter qsplitter.h
341 \brief The QSplitter class implements a splitter widget.
345 A splitter lets the user control the size of child widgets by
346 dragging the boundary between the children. Any number of widgets
349 To show a QListBox, a QListView and a QMultiLineEdit side by side:
352 QSplitter *split = new QSplitter( parent );
353 QListBox *lb = new QListBox( split );
354 QListView *lv = new QListView( split );
355 QMultiLineEdit *ed = new QMultiLineEdit( split );
358 In QSplitter the boundary can be either horizontal or vertical. The
359 default is horizontal (the children are side by side) and you
360 can use setOrientation( QSplitter::Vertical ) to set it to vertical.
362 By default, all widgets can be as large or as small as the user
363 wishes, down to \link QWidget::minimumSizeHint() minimumSizeHint()\endlink.
364 You can naturally use setMinimumSize() and/or
365 setMaximumSize() on the children. Use setResizeMode() to specify that
366 a widget should keep its size when the splitter is resized.
368 QSplitter normally resizes the children only at the end of a
369 resize operation, but if you call setOpaqueResize( TRUE ), the
370 widgets are resized as often as possible.
372 The initial distribution of size between the widgets is determined
373 by the initial size of each widget. You can also use setSizes() to
374 set the sizes of all the widgets. The function sizes() returns the
375 sizes set by the user.
377 If you hide() a child, its space will be distributed among the other
378 children. When you show() it again, it will be reinstated.
380 <img src=qsplitter-m.png> <img src=qsplitter-w.png>
387 QSize QSplitterP::minSize( const QWidget *w ) const
389 if ( isCompressed(w) && (data->list.count() > 1 ) ) return QSize(0,0);
390 QSize min = w->minimumSize();
392 if ( min.height() <= 0 || min.width() <= 0 )
393 s = w->minimumSizeHint();
394 if ( min.height() > 0 )
395 s.setHeight( min.height() );
396 if ( min.width() > 0 )
397 s.setWidth( min.width() );
398 return s.expandedTo(QSize(0,0));
401 QSize QSplitterP::maxSize( const QWidget* w ) const
403 if ( isCompressed(w) && (data->list.count() > 1 ) ) return QSize(0,0);
404 else return w->maximumSize();
408 Constructs a horizontal splitter.
411 QSplitterP::QSplitterP( QWidget *parent, const char *name )
412 :QFrame(parent,name,WPaintUnclipped)
420 Constructs splitter with orientation \a o.
423 QSplitterP::QSplitterP( Orientation o, QWidget *parent, const char *name )
424 :QFrame(parent,name,WPaintUnclipped)
432 Destructs the splitter.
435 QSplitterP::~QSplitterP()
437 data->list.setAutoDelete( TRUE );
442 void QSplitterP::init()
444 data = new QSplitterPData;
445 if ( orient == Horizontal )
446 setSizePolicy( QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Minimum) );
448 setSizePolicy( QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Fixed) );
449 compressed_widgets.clear();
450 compress_flag = false;
455 \fn void QSplitter::refresh()
457 Updates the splitter state. You should not need to call this
458 function during normal use of the splitter.
462 /*! Sets the orientation to \a o. By default the orientation is
463 horizontal (the widgets are side by side).
468 void QSplitterP::setOrientation( Orientation o )
474 if ( orient == Horizontal )
475 setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) );
477 setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
479 QSplitterPLayoutStruct *s = data->list.first();
482 ((QSplitterPHandle*)s->wid)->setOrientation( o );
483 s = data->list.next(); // ### next at end of loop, no iterator
485 recalc( isVisible() );
490 \fn Orientation QSplitter::orientation() const
492 Returns the orientation (\c Horizontal or \c Vertical) of the splitter.
499 void QSplitterP::resizeEvent( QResizeEvent * )
506 Inserts the widget \a w at the end, or at the beginning if \a first is TRUE
508 It is the responsibility of the caller of this function to make sure
509 that \a w is not already in the splitter, and to call recalcId if
510 needed. (If \a first is TRUE, then recalcId is very probably
514 QSplitterPLayoutStruct *QSplitterP::addWidget( QWidget *w, bool first )
516 QSplitterPLayoutStruct *s;
517 QSplitterPHandle *newHandle = 0;
518 if ( data->list.count() > 0 ) {
519 s = new QSplitterPLayoutStruct;
521 newHandle = new QSplitterPHandle( orientation(), this );
523 newHandle->setId(data->list.count());
524 s->isSplitter = TRUE;
525 s->sizer = pick( newHandle->sizeHint() );
527 data->list.insert( 0, s );
529 data->list.append( s );
531 s = new QSplitterPLayoutStruct;
534 if ( !testWState( WState_Resized ) && w->sizeHint().isValid() )
535 s->sizer = pick( w->sizeHint() );
537 s->sizer = pick( w->size() );
538 s->isSplitter = FALSE;
540 data->list.insert( 0, s );
542 data->list.append( s );
543 if ( newHandle && isVisible() )
544 newHandle->show(); //will trigger sending of post events
550 Tells the splitter that a child widget has been inserted/removed.
553 void QSplitterP::childEvent( QChildEvent *c )
555 if ( c->type() == QEvent::ChildInserted ) {
556 if ( !c->child()->isWidgetType() )
559 if ( ((QWidget*)c->child())->testWFlags( WType_TopLevel ) )
562 QSplitterPLayoutStruct *s = data->list.first();
564 if ( s->wid == c->child() )
566 s = data->list.next();
568 addWidget( (QWidget*)c->child() );
569 recalc( isVisible() );
571 } else if ( c->type() == QEvent::ChildRemoved ) {
572 QSplitterPLayoutStruct *p = 0;
573 if ( data->list.count() > 1 )
574 p = data->list.at(1); //remove handle _after_ first widget.
575 QSplitterPLayoutStruct *s = data->list.first();
577 if ( s->wid == c->child() ) {
578 data->list.removeRef( s );
580 if ( p && p->isSplitter ) {
581 data->list.removeRef( p );
582 delete p->wid; //will call childEvent
590 s = data->list.next();
597 Shows a rubber band at position \a p. If \a p is negative, the
598 rubber band is removed.
601 void QSplitterP::setRubberband( int p )
603 QPainter paint( this );
604 paint.setPen( gray );
605 paint.setBrush( gray );
606 paint.setRasterOp( XorROP );
607 QRect r = contentsRect();
608 const int rBord = 3; //Themable????
610 const int sw = style().splitterWidth();
612 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); //qt3.x
614 if ( orient == Horizontal ) {
615 if ( opaqueOldPos >= 0 )
616 paint.drawRect( opaqueOldPos + sw/2 - rBord , r.y(),
617 2*rBord, r.height() );
619 paint.drawRect( p + sw/2 - rBord, r.y(), 2*rBord, r.height() );
621 if ( opaqueOldPos >= 0 )
622 paint.drawRect( r.x(), opaqueOldPos + sw/2 - rBord,
623 r.width(), 2*rBord );
625 paint.drawRect( r.x(), p + sw/2 - rBord, r.width(), 2*rBord );
633 bool QSplitterP::event( QEvent *e )
635 if ( e->type() == QEvent::LayoutHint || ( e->type() == QEvent::Show && data->firstShow ) ) {
636 recalc( isVisible() );
637 if ( e->type() == QEvent::Show )
638 data->firstShow = FALSE;
640 return QWidget::event( e );
645 Draws the splitter handle in the rectangle described by \a x, \a y,
646 \a w, \a h using painter \a p.
647 \sa QStyle::drawSplitter
650 void QSplitterP::drawSplitter( QPainter *p,
651 QCOORD x, QCOORD y, QCOORD w, QCOORD h )
654 style().drawSplitter( p, x, y, w, h, colorGroup(), orient );
656 style().drawPrimitive(QStyle::PE_Splitter, p, QRect(x, y, w, h), colorGroup(),
657 (orientation() == Qt::Horizontal ?
658 QStyle::Style_Horizontal : 0));
664 Returns the id of the splitter to the right of or below the widget \a w,
665 or 0 if there is no such splitter.
666 (ie. it is either not in this QSplitter, or it is at the end).
669 int QSplitterP::idAfter( QWidget* w ) const
671 QSplitterPLayoutStruct *s = data->list.first();
674 if ( s->isSplitter && seen_w )
675 return data->list.at();
676 if ( !s->isSplitter && s->wid == w )
678 s = data->list.next();
683 // VSR 21/11/02 -> ================================
684 QSplitterPHandle* QSplitterP::getHandleAfter(QWidget* w)
686 QSplitterPLayoutStruct *s = data->list.first();
689 if ( s->isSplitter && seen_w )
690 return (QSplitterPHandle*)s->wid;
691 if ( !s->isSplitter && s->wid == w )
693 s = data->list.next();
698 QSplitterPHandle* QSplitterP::getHandleBefore(QWidget* w)
700 QSplitterPLayoutStruct *s = data->list.first();
701 QSplitterPHandle* h = 0;
704 h = (QSplitterPHandle*)s;
705 if ( !s->isSplitter && s->wid == w )
707 s = data->list.next();
711 // VSR 21/11/02 <- ================================
713 QWidget* QSplitterP::widgetBefore( int id ) const
715 QSplitterPLayoutStruct *s = data->list.first();
718 if ( !s->isSplitter ) {
720 if (idAfter(w) == id) return w;
722 s = data->list.next();
727 QWidget* QSplitterP::widgetAfter( int id ) const
729 QSplitterPLayoutStruct *s = data->list.first();
732 if ( !s->isSplitter && seen_s )
734 if ( s->isSplitter && data->list.at() == id )
736 s = data->list.next();
741 void QSplitterP::unCompress(QWidget* w) {
742 compressed_widgets.remove(w);
745 void QSplitterP::compress(QWidget* w)
747 if (!isCompressed(w)) compressed_widgets.append(w);
750 bool QSplitterP::isCompressed(const QWidget* w) const {
751 QWidget* t = (QWidget*)w;
752 if (compressed_widgets.containsRef(t)==0) return false;
757 Moves the left/top edge of the splitter handle with id \a id as
758 close as possible to \a p which is the distance from the left (or
759 top) edge of the widget.
763 void QSplitterP::moveSplitter( QCOORD p, int id )
765 p = adjustPos( p, id );
767 QSplitterPLayoutStruct *s = data->list.at(id);
768 int oldP = orient == Horizontal? s->wid->x() : s->wid->y();
769 bool upLeft = p < oldP;
771 moveAfter( p, id, upLeft );
772 moveBefore( p-1, id-1, upLeft );
778 void QSplitterP::setG( QWidget *w, int p, int s )
780 if ( orient == Horizontal )
781 w->setGeometry( p, contentsRect().y(), s, contentsRect().height() );
783 w->setGeometry( contentsRect().x(), p, contentsRect().width(), s );
788 Places the right/bottom edge of the widget at \a id at position \a pos.
793 void QSplitterP::moveBefore( int pos, int id, bool upLeft )
795 QSplitterPLayoutStruct *s = data->list.at(id);
799 if ( w->isHidden() ) {
800 moveBefore( pos, id-1, upLeft );
801 } else if ( s->isSplitter ) {
804 setG( w, pos-dd+1, dd );
805 moveBefore( pos-dd, id-1, upLeft );
807 moveBefore( pos-dd, id-1, upLeft );
808 setG( w, pos-dd+1, dd );
811 int left = pick( w->pos() );
812 int dd = pos - left + 1;
813 dd = QMAX( pick(minSize(w)), QMIN(dd, pick(maxSize(w))));
814 int newLeft = pos-dd+1;
815 setG( w, newLeft, dd );
816 if ( left != newLeft )
817 moveBefore( newLeft-1, id-1, upLeft );
823 Places the left/top edge of the widget at \a id at position \a pos.
828 void QSplitterP::moveAfter( int pos, int id, bool upLeft )
830 QSplitterPLayoutStruct *s = id < int(data->list.count()) ?
831 data->list.at(id) : 0;
835 if ( w->isHidden() ) {
836 moveAfter( pos, id+1, upLeft );
837 } else if ( pick( w->pos() ) == pos ) {
838 //No need to do anything if it's already there.
840 } else if ( s->isSplitter ) {
844 moveAfter( pos+dd, id+1, upLeft );
846 moveAfter( pos+dd, id+1, upLeft );
850 int right = pick( w->geometry().bottomRight() );
852 int dd = right - pos + 1;
853 dd = QMAX( pick(minSize(w)), QMIN(dd, pick(maxSize(w))));
854 int newRight = pos+dd-1;
856 moveAfter( newRight+1, id+1, upLeft );
862 Returns the valid range of the splitter with id \a id in \a min and \a max.
867 void QSplitterP::getRange( int id, int *min, int *max )
869 int minB = 0; //before
872 int maxA = 0; //after
873 int n = data->list.count();
874 if ( id < 0 || id >= n )
877 for ( i = 0; i < id; i++ ) {
878 QSplitterPLayoutStruct *s = data->list.at(i);
879 if ( s->isSplitter ) {
883 minB += pick( minSize(s->wid) );
884 maxB += pick( maxSize(s->wid) );
887 for ( i = id; i < n; i++ ) {
888 QSplitterPLayoutStruct *s = data->list.at(i);
889 if ( s->isSplitter ) {
893 minA += pick( minSize(s->wid) );
894 maxA += pick( maxSize(s->wid) );
897 QRect r = contentsRect();
899 *min = pick(r.topLeft()) + QMAX( minB, pick(r.size())-maxA );
901 *max = pick(r.topLeft()) + QMIN( maxB, pick(r.size())-minA );
907 Returns the legal position closest to \a p of the splitter with id \a id.
912 int QSplitterP::adjustPos( int p, int id )
916 getRange( id, &min, &max );
917 p = QMAX( min, QMIN( p, max ) );
923 void QSplitterP::doResize()
925 QRect r = contentsRect();
927 int n = data->list.count();
928 QArray<QLayoutStruct> a( n );
929 for ( i = 0; i< n; i++ ) {
931 QSplitterPLayoutStruct *s = data->list.at(i);
932 if ( s->wid->isHidden() ) {
934 a[i].sizeHint = a[i].minimumSize = 0;
935 a[i].maximumSize = 0;
936 } else if ( s->isSplitter ) {
938 a[i].sizeHint = a[i].minimumSize = a[i].maximumSize = s->sizer;
940 } else if ( s->mode == KeepSize ) {
942 a[i].minimumSize = pick( minSize(s->wid) );
943 a[i].sizeHint = s->sizer;
944 a[i].maximumSize = pick( maxSize(s->wid) );
946 } else if ( s->mode == FollowSizeHint ) {
948 a[i].minimumSize = a[i].sizeHint = pick( s->wid->sizeHint() );
949 a[i].maximumSize = pick( maxSize(s->wid) );
951 } else { //proportional
952 a[i].stretch = s->sizer;
953 a[i].maximumSize = pick( maxSize(s->wid) );
954 a[i].sizeHint = a[i].minimumSize = pick( minSize(s->wid) );
959 qGeomCalc( a, 0, n, pick( r.topLeft() ), pick( r.size() ), 0 );
960 for ( i = 0; i< n; i++ ) {
961 QSplitterPLayoutStruct *s = data->list.at(i);
962 if ( orient == Horizontal )
963 s->wid->setGeometry( a[i].pos, r.top(), a[i].size, r.height() );
965 s->wid->setGeometry( r.left(), a[i].pos, r.width(), a[i].size );
971 void QSplitterP::recalc( bool update )
973 int fi = 2*frameWidth();
976 int maxt = QWIDGETSIZE_MAX;
978 int n = data->list.count();
981 The splitter before a hidden widget is always hidden.
982 The splitter before the first visible widget is hidden.
983 The splitter before any other visible widget is visible.
985 for ( int i = 0; i< n; i++ ) {
986 QSplitterPLayoutStruct *s = data->list.at(i);
987 if ( !s->isSplitter ) {
988 QSplitterPLayoutStruct *p = (i > 0) ? p = data->list.at( i-1 ) : 0;
989 if ( p && p->isSplitter )
990 if ( first || s->wid->isHidden() )
991 p->wid->hide(); //may trigger new recalc
993 p->wid->show(); //may trigger new recalc
994 if ( !s->wid->isHidden() )
1000 for ( int j = 0; j< n; j++ ) {
1001 QSplitterPLayoutStruct *s = data->list.at(j);
1002 if ( !s->wid->isHidden() ) {
1004 if ( s->isSplitter ) {
1008 QSize minS = minSize(s->wid);
1009 minl += pick( minS );
1010 maxl += pick( maxSize(s->wid) );
1011 mint = QMAX( mint, trans( minS ));
1012 int tm = trans( maxSize(s->wid) );
1014 maxt = QMIN( maxt, tm );
1021 maxl = QMIN( maxl, QWIDGETSIZE_MAX );
1025 if ( orient == Horizontal ) {
1026 setMaximumSize( maxl, maxt );
1027 setMinimumSize( minl, mint );
1029 setMaximumSize( maxt, maxl );
1030 setMinimumSize( mint, minl );
1036 /*! \enum QSplitter::ResizeMode
1038 This enum type describes how QSplitter will resize each of its child widgets. The currently defined values are: <ul>
1040 <li> \c Stretch - the widget will be resized when the splitter
1043 <li> \c KeepSize - QSplitter will try to keep this widget's size
1046 <li> \c FollowSizeHint - QSplitter will resize the widget when its
1054 Sets resize mode of \a w to \a mode.
1059 void QSplitterP::setResizeMode( QWidget *w, ResizeMode mode )
1061 processChildEvents();
1062 QSplitterPLayoutStruct *s = data->list.first();
1064 if ( s->wid == w ) {
1068 s = data->list.next();
1070 s = addWidget( w, TRUE );
1076 Returns TRUE if opaque resize is on, FALSE otherwise.
1078 \sa setOpaqueResize()
1081 bool QSplitterP::opaqueResize() const
1083 return data->opaque;
1088 Sets opaque resize to \a on. Opaque resize is initially turned off.
1093 void QSplitterP::setOpaqueResize( bool on )
1100 Moves \a w to the leftmost/top position.
1103 void QSplitterP::moveToFirst( QWidget *w )
1105 processChildEvents();
1107 QSplitterPLayoutStruct *s = data->list.first();
1109 if ( s->wid == w ) {
1111 QSplitterPLayoutStruct *p = data->list.prev();
1112 if ( p ) { // not already at first place
1113 data->list.take(); //take p
1114 data->list.take(); // take s
1115 data->list.insert( 0, p );
1116 data->list.insert( 0, s );
1120 s = data->list.next();
1123 addWidget( w, TRUE );
1129 Moves \a w to the rightmost/bottom position.
1132 void QSplitterP::moveToLast( QWidget *w )
1134 processChildEvents();
1136 QSplitterPLayoutStruct *s = data->list.first();
1138 if ( s->wid == w ) {
1140 data->list.take(); // take s
1141 QSplitterPLayoutStruct *p = data->list.current();
1142 if ( p ) { // the splitter handle after s
1143 data->list.take(); //take p
1144 data->list.append( p );
1146 data->list.append( s );
1149 s = data->list.next();
1157 void QSplitterP::recalcId()
1159 int n = data->list.count();
1160 for ( int i = 0; i < n; i++ ) {
1161 QSplitterPLayoutStruct *s = data->list.at(i);
1162 if ( s->isSplitter )
1163 ((QSplitterPHandle*)s->wid)->setId(i);
1170 QSize QSplitterP::sizeHint() const
1176 const QObjectList * c = children();
1177 QObjectListIt it( *c );
1180 while( (o=it.current()) != 0 ) {
1182 if ( o->isWidgetType() &&
1183 !((QWidget*)o)->isHidden() ) {
1184 QSize s = ((QWidget*)o)->sizeHint();
1185 if ( s.isValid() ) {
1187 t = QMAX( t, trans( s ) );
1192 return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
1200 QSize QSplitterP::minimumSizeHint() const
1206 const QObjectList * c = children();
1207 QObjectListIt it( *c );
1210 while( (o=it.current()) != 0 ) {
1212 if ( o->isWidgetType() &&
1213 !((QWidget*)o)->isHidden() ) {
1214 QSize s = minSize((QWidget*)o);
1215 if ( s.isValid() ) {
1217 t = QMAX( t, trans( s ) );
1222 return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
1229 QSizePolicy QSplitterP::sizePolicy() const
1231 return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
1236 Calculates stretch parameters from current sizes
1239 void QSplitterP::storeSizes()
1241 QSplitterPLayoutStruct *s = data->list.first();
1243 if ( !s->isSplitter )
1244 s->sizer = pick( s->wid->size() );
1245 s = data->list.next();
1250 #if 0 // ### remove this code ASAP
1253 Hides \a w if \a hide is TRUE, and updates the splitter.
1255 \warning Due to a limitation in the current implementation,
1256 calling QWidget::hide() will not work.
1259 void QSplitterP::setHidden( QWidget *w, bool hide )
1263 } else if ( w == w2 ) {
1267 qWarning( "QSplitterP::setHidden(), unknown widget" );
1280 Returns the hidden status of \a w
1283 bool QSplitterP::isHidden( QWidget *w ) const
1291 qWarning( "QSplitterP::isHidden(), unknown widget" );
1299 Returns a list of the size parameters of all the widgets in this
1302 Giving the values to setSizes() will give a splitter with the same
1306 QValueList<int> QSplitterP::sizes() const
1308 if ( !testWState(WState_Polished) ) {
1309 QWidget* that = (QWidget*) this;
1312 QValueList<int> list;
1313 QSplitterPLayoutStruct *s = data->list.first();
1315 if ( !s->isSplitter )
1316 list.append( s->sizer );
1317 s = data->list.next();
1325 Sets the size parameters to the values given in \a list.
1326 If the splitterP is horizontal, the values set the sizes from
1327 left to right. If it is vertical, the sizes are applied from
1329 Extra values in \a list are ignored.
1331 If \a list contains too few values, the result is undefined
1332 but the program will still be well-behaved.
1335 void QSplitterP::setSizes( QValueList<int> list )
1337 processChildEvents();
1338 QValueList<int>::Iterator it = list.begin();
1339 QSplitterPLayoutStruct *s = data->list.first();
1340 while ( s && it != list.end() ) {
1341 if ( !s->isSplitter ) {
1345 s = data->list.next();
1352 Gets all posted child events, ensuring that the internal state of
1353 the splitter is consistent with the programmer's idea.
1356 void QSplitterP::processChildEvents()
1358 QApplication::sendPostedEvents( this, QEvent::ChildInserted );
1366 void QSplitterP::styleChange( QStyle& old )
1368 #if QT_VERSION < 300
1369 int sw = style().splitterWidth();
1371 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); //qt3.x
1373 QSplitterPLayoutStruct *s = data->list.first();
1375 if ( s->isSplitter )
1377 s = data->list.next();
1380 QFrame::styleChange( old );
1384 bool QSplitterP::isCompressEnabled() const
1386 return compress_flag;
1389 void QSplitterP::setCompressEnabled(bool on) {
1393 void QSplitterP::updateSplitterHandles() const {
1394 QSplitterPLayoutStruct *s = data->list.first();
1396 if ( s->isSplitter )
1397 ((QSplitterPHandle*)s->wid)->updateButtonState();
1398 s = data->list.next();