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>
52 #include <private/qlayoutengine_p.h>
57 #include <qptrlist.h> //qt3.x
58 #include <qmemarray.h> //qt3.x
59 #include <qstyle.h> //qt3.x
62 #include <qobjectlist.h>
63 #include <qapplication.h> //sendPostedEvents
66 #define SPLITTER_ICON_WIDTH 10
67 #define SPLITTER_ICON_HEIGHT 12
69 static int mouseOffset;
70 static int opaqueOldPos = -1; //### there's only one mouse, but this is a bit risky
72 static const char* splitter_left_xpm[] = {
74 " s none m none c none",
75 ". s iconColor1 m black c black",
83 static const char* splitter_right_xpm[] = {
85 " s iconColor1 m black c black",
86 ". s none m none c none",
94 static const char* splitter_up_xpm[] = {
96 " s none m none c none",
97 ". s iconColor1 m black c black",
105 static const char* splitter_down_xpm[] = {
107 " s iconColor1 m black c black",
108 ". s none m none c none",
116 QSplitterPHandle::QSplitterPHandle( Qt::Orientation o,
117 QSplitterP *parent, const char * name )
118 : QWidget( parent, name )
122 left = new QPushButton(this);
123 right = new QPushButton(this);
124 unleft = new QPushButton(this);
125 unright = new QPushButton(this);
129 left->setAutoDefault(false); unleft->setAutoDefault(false);
130 right->setAutoDefault(false); unright->setAutoDefault(false);
131 left->setFlat(true); right->setFlat(true); unleft->setFlat(true); unright->setFlat(true);
132 left->setCursor( arrowCursor ); right->setCursor( arrowCursor );
133 unleft->setCursor( arrowCursor ); unright->setCursor( arrowCursor );
135 connect(left, SIGNAL(clicked()), this, SLOT(onBeforeCompress()));
136 connect(right, SIGNAL(clicked()), this, SLOT(onAfterCompress()));
137 connect(unleft, SIGNAL(clicked()), this, SLOT(onBeforeUnCompress()));
138 connect(unright, SIGNAL(clicked()), this, SLOT(onAfterUnCompress()));
141 void QSplitterPHandle::onBeforeCompress() {
142 oldpos = s->pick(pos());
143 int pos = s->pick(s->widgetBefore(id())->pos());
144 s->compress(s->widgetBefore(id()));
145 s->moveSplitter(pos, id());
146 s->updateSplitterHandles();
149 void QSplitterPHandle::onBeforeUnCompress() {
150 s->unCompress(s->widgetBefore(id()));
151 s->moveSplitter(oldpos, id());
152 s->updateSplitterHandles();
155 void QSplitterPHandle::onAfterCompress() {
156 oldpos = s->pick(pos());
157 int pos = s->pick(s->widgetAfter(id())->pos()) + s->pick(s->widgetAfter(id())->size()) - s->pick(size());
158 s->compress(s->widgetAfter(id()));
159 s->moveSplitter(pos, id());
160 s->updateSplitterHandles();
163 void QSplitterPHandle::onAfterUnCompress() {
164 s->unCompress(s->widgetAfter(id()));
165 s->moveSplitter(oldpos, id());
166 s->updateSplitterHandles();
169 // VSR 21/11/02 -> ================================
170 void QSplitterPHandle::compressAfter()
175 void QSplitterPHandle::unCompressAfter()
180 void QSplitterPHandle::compressBefore()
185 void QSplitterPHandle::unCompressBefore()
187 onBeforeUnCompress();
189 // VSR 21/11/02 <- ================================
191 QSizePolicy QSplitterPHandle::sizePolicy() const
194 return QWidget::sizePolicy();
197 QSize QSplitterPHandle::sizeHint() const
200 int sw = style().splitterWidth();
201 return QSize(sw,sw).expandedTo( QApplication::globalStrut() );
203 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this);
204 return (style().sizeFromContents(QStyle::CT_Splitter, s, QSize(sw, sw)).
205 expandedTo(QApplication::globalStrut()));
209 void QSplitterPHandle::setOrientation( Qt::Orientation o )
213 if ( o == QSplitterP::Horizontal )
214 setCursor( splitHCursor );
216 setCursor( splitVCursor );
220 if ( orient == QSplitterP::Horizontal )
222 lp = QPixmap(splitter_left_xpm);
223 rp = QPixmap(splitter_right_xpm);
227 lp = QPixmap(splitter_up_xpm);
228 rp = QPixmap(splitter_down_xpm);
231 right->setPixmap(rp);
232 unleft->setPixmap(rp);
233 unright->setPixmap(lp);
236 void QSplitterPHandle::mouseMoveEvent( QMouseEvent *e )
238 if ( !(e->state()&LeftButton) )
240 QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()))
243 s->moveSplitter( pos, id() );
245 int min = pos; int max = pos;
246 s->getRange( id(), &min, &max );
247 s->setRubberband( QMAX( min, QMIN(max, pos )));
251 void QSplitterPHandle::mousePressEvent( QMouseEvent *e )
253 if ( e->button() == LeftButton )
254 mouseOffset = s->pick(e->pos());
257 void QSplitterPHandle::mouseReleaseEvent( QMouseEvent *e )
259 if ( !opaque() && e->button() == LeftButton ) {
260 QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()));
261 s->setRubberband( -1 );
262 s->moveSplitter( pos, id() );
266 void QSplitterPHandle::paintEvent( QPaintEvent * )
270 s->drawSplitter( &p, 0, 0, width(), height() );
273 void QSplitterPHandle::updateButtonState() {
274 if (!s->isCompressEnabled()) {
281 if ( orient == QSplitterP::Horizontal )
283 left->setGeometry( QRect( QPoint( (width() - SPLITTER_ICON_WIDTH)/2, 0 ),
284 QSize ( SPLITTER_ICON_WIDTH, SPLITTER_ICON_HEIGHT ) ) );
285 right->setGeometry( QRect( QPoint( (width() - SPLITTER_ICON_WIDTH)/2, SPLITTER_ICON_HEIGHT ),
286 QSize ( SPLITTER_ICON_WIDTH, SPLITTER_ICON_HEIGHT ) ) );
287 unleft->setGeometry( left->geometry() );
288 unright->setGeometry( right->geometry() );
292 left->setGeometry( QRect( QPoint( 0, (height() - SPLITTER_ICON_WIDTH)/2 ),
293 QSize ( SPLITTER_ICON_HEIGHT, SPLITTER_ICON_WIDTH ) ) );
294 right->setGeometry( QRect( QPoint( SPLITTER_ICON_HEIGHT, (height() - SPLITTER_ICON_WIDTH)/2),
295 QSize ( SPLITTER_ICON_HEIGHT, SPLITTER_ICON_WIDTH ) ) );
296 unleft->setGeometry( left->geometry() );
297 unright->setGeometry( right->geometry() );
299 if ( s->isCompressed( s->widgetBefore( id() ) ) ) {
302 right->setEnabled(false);
307 right->setEnabled(true);
309 if ( s->isCompressed( s->widgetAfter( id() ) ) ) {
312 left->setEnabled(false);
317 left->setEnabled(true);
322 class QSplitterPLayoutStruct
325 QSplitterP::ResizeMode mode;
334 QSplitterPData() : opaque( FALSE ), firstShow( TRUE ) {}
336 QList<QSplitterPLayoutStruct> list;
344 \class QSplitter qsplitter.h
345 \brief The QSplitter class implements a splitter widget.
349 A splitter lets the user control the size of child widgets by
350 dragging the boundary between the children. Any number of widgets
353 To show a QListBox, a QListView and a QMultiLineEdit side by side:
356 QSplitter *split = new QSplitter( parent );
357 QListBox *lb = new QListBox( split );
358 QListView *lv = new QListView( split );
359 QMultiLineEdit *ed = new QMultiLineEdit( split );
362 In QSplitter the boundary can be either horizontal or vertical. The
363 default is horizontal (the children are side by side) and you
364 can use setOrientation( QSplitter::Vertical ) to set it to vertical.
366 By default, all widgets can be as large or as small as the user
367 wishes, down to \link QWidget::minimumSizeHint() minimumSizeHint()\endlink.
368 You can naturally use setMinimumSize() and/or
369 setMaximumSize() on the children. Use setResizeMode() to specify that
370 a widget should keep its size when the splitter is resized.
372 QSplitter normally resizes the children only at the end of a
373 resize operation, but if you call setOpaqueResize( TRUE ), the
374 widgets are resized as often as possible.
376 The initial distribution of size between the widgets is determined
377 by the initial size of each widget. You can also use setSizes() to
378 set the sizes of all the widgets. The function sizes() returns the
379 sizes set by the user.
381 If you hide() a child, its space will be distributed among the other
382 children. When you show() it again, it will be reinstated.
384 <img src=qsplitter-m.png> <img src=qsplitter-w.png>
391 QSize QSplitterP::minSize( const QWidget *w ) const
393 if ( isCompressed(w) && (data->list.count() > 1 ) ) return QSize(0,0);
394 QSize min = w->minimumSize();
396 if ( min.height() <= 0 || min.width() <= 0 )
397 s = w->minimumSizeHint();
398 if ( min.height() > 0 )
399 s.setHeight( min.height() );
400 if ( min.width() > 0 )
401 s.setWidth( min.width() );
402 return s.expandedTo(QSize(0,0));
405 QSize QSplitterP::maxSize( const QWidget* w ) const
407 if ( isCompressed(w) && (data->list.count() > 1 ) ) return QSize(0,0);
408 else return w->maximumSize();
412 Constructs a horizontal splitter.
415 QSplitterP::QSplitterP( QWidget *parent, const char *name )
416 :QFrame(parent,name,WPaintUnclipped)
424 Constructs splitter with orientation \a o.
427 QSplitterP::QSplitterP( Orientation o, QWidget *parent, const char *name )
428 :QFrame(parent,name,WPaintUnclipped)
436 Destructs the splitter.
439 QSplitterP::~QSplitterP()
441 data->list.setAutoDelete( TRUE );
446 void QSplitterP::init()
448 data = new QSplitterPData;
449 if ( orient == Horizontal )
450 setSizePolicy( QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Minimum) );
452 setSizePolicy( QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Fixed) );
453 compressed_widgets.clear();
454 compress_flag = false;
459 \fn void QSplitter::refresh()
461 Updates the splitter state. You should not need to call this
462 function during normal use of the splitter.
466 /*! Sets the orientation to \a o. By default the orientation is
467 horizontal (the widgets are side by side).
472 void QSplitterP::setOrientation( Orientation o )
478 if ( orient == Horizontal )
479 setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) );
481 setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
483 QSplitterPLayoutStruct *s = data->list.first();
486 ((QSplitterPHandle*)s->wid)->setOrientation( o );
487 s = data->list.next(); // ### next at end of loop, no iterator
489 recalc( isVisible() );
494 \fn Orientation QSplitter::orientation() const
496 Returns the orientation (\c Horizontal or \c Vertical) of the splitter.
503 void QSplitterP::resizeEvent( QResizeEvent * )
510 Inserts the widget \a w at the end, or at the beginning if \a first is TRUE
512 It is the responsibility of the caller of this function to make sure
513 that \a w is not already in the splitter, and to call recalcId if
514 needed. (If \a first is TRUE, then recalcId is very probably
518 QSplitterPLayoutStruct *QSplitterP::addWidget( QWidget *w, bool first )
520 QSplitterPLayoutStruct *s;
521 QSplitterPHandle *newHandle = 0;
522 if ( data->list.count() > 0 ) {
523 s = new QSplitterPLayoutStruct;
525 newHandle = new QSplitterPHandle( orientation(), this );
527 newHandle->setId(data->list.count());
528 s->isSplitter = TRUE;
529 s->sizer = pick( newHandle->sizeHint() );
531 data->list.insert( 0, s );
533 data->list.append( s );
535 s = new QSplitterPLayoutStruct;
538 if ( !testWState( WState_Resized ) && w->sizeHint().isValid() )
539 s->sizer = pick( w->sizeHint() );
541 s->sizer = pick( w->size() );
542 s->isSplitter = FALSE;
544 data->list.insert( 0, s );
546 data->list.append( s );
547 if ( newHandle && isVisible() )
548 newHandle->show(); //will trigger sending of post events
554 Tells the splitter that a child widget has been inserted/removed.
557 void QSplitterP::childEvent( QChildEvent *c )
559 if ( c->type() == QEvent::ChildInserted ) {
560 if ( !c->child()->isWidgetType() )
563 if ( ((QWidget*)c->child())->testWFlags( WType_TopLevel ) )
566 QSplitterPLayoutStruct *s = data->list.first();
568 if ( s->wid == c->child() )
570 s = data->list.next();
572 addWidget( (QWidget*)c->child() );
573 recalc( isVisible() );
575 } else if ( c->type() == QEvent::ChildRemoved ) {
576 QSplitterPLayoutStruct *p = 0;
577 if ( data->list.count() > 1 )
578 p = data->list.at(1); //remove handle _after_ first widget.
579 QSplitterPLayoutStruct *s = data->list.first();
581 if ( s->wid == c->child() ) {
582 data->list.removeRef( s );
584 if ( p && p->isSplitter ) {
585 data->list.removeRef( p );
586 delete p->wid; //will call childEvent
594 s = data->list.next();
601 Shows a rubber band at position \a p. If \a p is negative, the
602 rubber band is removed.
605 void QSplitterP::setRubberband( int p )
607 QPainter paint( this );
608 paint.setPen( gray );
609 paint.setBrush( gray );
610 paint.setRasterOp( XorROP );
611 QRect r = contentsRect();
612 const int rBord = 3; //Themable????
614 const int sw = style().splitterWidth();
616 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); //qt3.x
618 if ( orient == Horizontal ) {
619 if ( opaqueOldPos >= 0 )
620 paint.drawRect( opaqueOldPos + sw/2 - rBord , r.y(),
621 2*rBord, r.height() );
623 paint.drawRect( p + sw/2 - rBord, r.y(), 2*rBord, r.height() );
625 if ( opaqueOldPos >= 0 )
626 paint.drawRect( r.x(), opaqueOldPos + sw/2 - rBord,
627 r.width(), 2*rBord );
629 paint.drawRect( r.x(), p + sw/2 - rBord, r.width(), 2*rBord );
637 bool QSplitterP::event( QEvent *e )
639 if ( e->type() == QEvent::LayoutHint || ( e->type() == QEvent::Show && data->firstShow ) ) {
640 recalc( isVisible() );
641 if ( e->type() == QEvent::Show )
642 data->firstShow = FALSE;
644 return QWidget::event( e );
649 Draws the splitter handle in the rectangle described by \a x, \a y,
650 \a w, \a h using painter \a p.
651 \sa QStyle::drawSplitter
654 void QSplitterP::drawSplitter( QPainter *p,
655 QCOORD x, QCOORD y, QCOORD w, QCOORD h )
658 style().drawSplitter( p, x, y, w, h, colorGroup(), orient );
660 style().drawPrimitive(QStyle::PE_Splitter, p, QRect(x, y, w, h), colorGroup(),
661 (orientation() == Qt::Horizontal ?
662 QStyle::Style_Horizontal : 0));
668 Returns the id of the splitter to the right of or below the widget \a w,
669 or 0 if there is no such splitter.
670 (ie. it is either not in this QSplitter, or it is at the end).
673 int QSplitterP::idAfter( QWidget* w ) const
675 QSplitterPLayoutStruct *s = data->list.first();
678 if ( s->isSplitter && seen_w )
679 return data->list.at();
680 if ( !s->isSplitter && s->wid == w )
682 s = data->list.next();
687 // VSR 21/11/02 -> ================================
688 QSplitterPHandle* QSplitterP::getHandleAfter(QWidget* w)
690 QSplitterPLayoutStruct *s = data->list.first();
693 if ( s->isSplitter && seen_w )
694 return (QSplitterPHandle*)s->wid;
695 if ( !s->isSplitter && s->wid == w )
697 s = data->list.next();
702 QSplitterPHandle* QSplitterP::getHandleBefore(QWidget* w)
704 QSplitterPLayoutStruct *s = data->list.first();
705 QSplitterPHandle* h = 0;
708 h = (QSplitterPHandle*)s;
709 if ( !s->isSplitter && s->wid == w )
711 s = data->list.next();
715 // VSR 21/11/02 <- ================================
717 QWidget* QSplitterP::widgetBefore( int id ) const
719 QSplitterPLayoutStruct *s = data->list.first();
722 if ( !s->isSplitter ) {
724 if (idAfter(w) == id) return w;
726 s = data->list.next();
731 QWidget* QSplitterP::widgetAfter( int id ) const
733 QSplitterPLayoutStruct *s = data->list.first();
736 if ( !s->isSplitter && seen_s )
738 if ( s->isSplitter && data->list.at() == id )
740 s = data->list.next();
745 void QSplitterP::unCompress(QWidget* w) {
746 compressed_widgets.remove(w);
749 void QSplitterP::compress(QWidget* w)
751 if (!isCompressed(w)) compressed_widgets.append(w);
754 bool QSplitterP::isCompressed(const QWidget* w) const {
755 QWidget* t = (QWidget*)w;
756 if (compressed_widgets.containsRef(t)==0) return false;
761 Moves the left/top edge of the splitter handle with id \a id as
762 close as possible to \a p which is the distance from the left (or
763 top) edge of the widget.
767 void QSplitterP::moveSplitter( QCOORD p, int id )
769 p = adjustPos( p, id );
771 QSplitterPLayoutStruct *s = data->list.at(id);
772 int oldP = orient == Horizontal? s->wid->x() : s->wid->y();
773 bool upLeft = p < oldP;
775 moveAfter( p, id, upLeft );
776 moveBefore( p-1, id-1, upLeft );
782 void QSplitterP::setG( QWidget *w, int p, int s )
784 if ( orient == Horizontal )
785 w->setGeometry( p, contentsRect().y(), s, contentsRect().height() );
787 w->setGeometry( contentsRect().x(), p, contentsRect().width(), s );
792 Places the right/bottom edge of the widget at \a id at position \a pos.
797 void QSplitterP::moveBefore( int pos, int id, bool upLeft )
799 QSplitterPLayoutStruct *s = data->list.at(id);
803 if ( w->isHidden() ) {
804 moveBefore( pos, id-1, upLeft );
805 } else if ( s->isSplitter ) {
808 setG( w, pos-dd+1, dd );
809 moveBefore( pos-dd, id-1, upLeft );
811 moveBefore( pos-dd, id-1, upLeft );
812 setG( w, pos-dd+1, dd );
815 int left = pick( w->pos() );
816 int dd = pos - left + 1;
817 dd = QMAX( pick(minSize(w)), QMIN(dd, pick(maxSize(w))));
818 int newLeft = pos-dd+1;
819 setG( w, newLeft, dd );
820 if ( left != newLeft )
821 moveBefore( newLeft-1, id-1, upLeft );
827 Places the left/top edge of the widget at \a id at position \a pos.
832 void QSplitterP::moveAfter( int pos, int id, bool upLeft )
834 QSplitterPLayoutStruct *s = id < int(data->list.count()) ?
835 data->list.at(id) : 0;
839 if ( w->isHidden() ) {
840 moveAfter( pos, id+1, upLeft );
841 } else if ( pick( w->pos() ) == pos ) {
842 //No need to do anything if it's already there.
844 } else if ( s->isSplitter ) {
848 moveAfter( pos+dd, id+1, upLeft );
850 moveAfter( pos+dd, id+1, upLeft );
854 int right = pick( w->geometry().bottomRight() );
855 int ddd = pick( QSize(contentsRect().width(), contentsRect().height() ) ) - pos;
856 int dd = QMIN(right - pos + 1, ddd);
857 dd = QMAX( pick(minSize(w)), QMIN(dd, pick(maxSize(w))));
858 int newRight = pos+dd-1;
860 moveAfter( newRight+1, id+1, upLeft );
866 Returns the valid range of the splitter with id \a id in \a min and \a max.
871 void QSplitterP::getRange( int id, int *min, int *max )
873 int minB = 0; //before
876 int maxA = 0; //after
877 int n = data->list.count();
878 if ( id < 0 || id >= n )
881 for ( i = 0; i < id; i++ ) {
882 QSplitterPLayoutStruct *s = data->list.at(i);
883 if ( s->isSplitter ) {
887 minB += pick( minSize(s->wid) );
888 maxB += pick( maxSize(s->wid) );
891 for ( i = id; i < n; i++ ) {
892 QSplitterPLayoutStruct *s = data->list.at(i);
893 if ( s->isSplitter ) {
897 minA += pick( minSize(s->wid) );
898 maxA += pick( maxSize(s->wid) );
901 QRect r = contentsRect();
903 *min = pick(r.topLeft()) + QMAX( minB, pick(r.size())-maxA );
905 *max = pick(r.topLeft()) + QMIN( maxB, pick(r.size())-minA );
911 Returns the legal position closest to \a p of the splitter with id \a id.
916 int QSplitterP::adjustPos( int p, int id )
920 getRange( id, &min, &max );
921 p = QMAX( min, QMIN( p, max ) );
927 void QSplitterP::doResize()
929 QRect r = contentsRect();
931 int n = data->list.count();
932 QArray<QLayoutStruct> a( n );
933 for ( i = 0; i< n; i++ ) {
935 QSplitterPLayoutStruct *s = data->list.at(i);
936 if ( s->wid->isHidden() ) {
938 a[i].sizeHint = a[i].minimumSize = 0;
939 a[i].maximumSize = 0;
940 } else if ( s->isSplitter ) {
942 a[i].sizeHint = a[i].minimumSize = a[i].maximumSize = s->sizer;
944 } else if ( s->mode == KeepSize ) {
946 a[i].minimumSize = pick( minSize(s->wid) );
947 a[i].sizeHint = s->sizer;
948 a[i].maximumSize = pick( maxSize(s->wid) );
950 } else if ( s->mode == FollowSizeHint ) {
952 a[i].minimumSize = a[i].sizeHint = pick( s->wid->sizeHint() );
953 a[i].maximumSize = pick( maxSize(s->wid) );
955 } else { //proportional
956 a[i].stretch = s->sizer;
957 a[i].maximumSize = pick( maxSize(s->wid) );
958 a[i].sizeHint = a[i].minimumSize = pick( minSize(s->wid) );
963 qGeomCalc( a, 0, n, pick( r.topLeft() ), pick( r.size() ), 0 );
964 for ( i = 0; i< n; i++ ) {
965 QSplitterPLayoutStruct *s = data->list.at(i);
966 if ( orient == Horizontal )
967 s->wid->setGeometry( a[i].pos, r.top(), a[i].size, r.height() );
969 s->wid->setGeometry( r.left(), a[i].pos, r.width(), a[i].size );
975 void QSplitterP::recalc( bool update )
977 int fi = 2*frameWidth();
980 int maxt = QWIDGETSIZE_MAX;
982 int n = data->list.count();
985 The splitter before a hidden widget is always hidden.
986 The splitter before the first visible widget is hidden.
987 The splitter before any other visible widget is visible.
989 for ( int i = 0; i< n; i++ ) {
990 QSplitterPLayoutStruct *s = data->list.at(i);
991 if ( !s->isSplitter ) {
992 QSplitterPLayoutStruct *p = (i > 0) ? p = data->list.at( i-1 ) : 0;
993 if ( p && p->isSplitter )
994 if ( first || s->wid->isHidden() )
995 p->wid->hide(); //may trigger new recalc
997 p->wid->show(); //may trigger new recalc
998 if ( !s->wid->isHidden() )
1004 for ( int j = 0; j< n; j++ ) {
1005 QSplitterPLayoutStruct *s = data->list.at(j);
1006 if ( !s->wid->isHidden() ) {
1008 if ( s->isSplitter ) {
1012 QSize minS = minSize(s->wid);
1013 minl += pick( minS );
1014 maxl += pick( maxSize(s->wid) );
1015 mint = QMAX( mint, trans( minS ));
1016 int tm = trans( maxSize(s->wid) );
1018 maxt = QMIN( maxt, tm );
1025 maxl = QMIN( maxl, QWIDGETSIZE_MAX );
1029 if ( orient == Horizontal ) {
1030 setMaximumSize( maxl, maxt );
1031 setMinimumSize( minl, mint );
1033 setMaximumSize( maxt, maxl );
1034 setMinimumSize( mint, minl );
1040 /*! \enum QSplitter::ResizeMode
1042 This enum type describes how QSplitter will resize each of its child widgets. The currently defined values are: <ul>
1044 <li> \c Stretch - the widget will be resized when the splitter
1047 <li> \c KeepSize - QSplitter will try to keep this widget's size
1050 <li> \c FollowSizeHint - QSplitter will resize the widget when its
1058 Sets resize mode of \a w to \a mode.
1063 void QSplitterP::setResizeMode( QWidget *w, ResizeMode mode )
1065 processChildEvents();
1066 QSplitterPLayoutStruct *s = data->list.first();
1068 if ( s->wid == w ) {
1072 s = data->list.next();
1074 s = addWidget( w, TRUE );
1080 Returns TRUE if opaque resize is on, FALSE otherwise.
1082 \sa setOpaqueResize()
1085 bool QSplitterP::opaqueResize() const
1087 return data->opaque;
1092 Sets opaque resize to \a on. Opaque resize is initially turned off.
1097 void QSplitterP::setOpaqueResize( bool on )
1104 Moves \a w to the leftmost/top position.
1107 void QSplitterP::moveToFirst( QWidget *w )
1109 processChildEvents();
1111 QSplitterPLayoutStruct *s = data->list.first();
1113 if ( s->wid == w ) {
1115 QSplitterPLayoutStruct *p = data->list.prev();
1116 if ( p ) { // not already at first place
1117 data->list.take(); //take p
1118 data->list.take(); // take s
1119 data->list.insert( 0, p );
1120 data->list.insert( 0, s );
1124 s = data->list.next();
1127 addWidget( w, TRUE );
1133 Moves \a w to the rightmost/bottom position.
1136 void QSplitterP::moveToLast( QWidget *w )
1138 processChildEvents();
1140 QSplitterPLayoutStruct *s = data->list.first();
1142 if ( s->wid == w ) {
1144 data->list.take(); // take s
1145 QSplitterPLayoutStruct *p = data->list.current();
1146 if ( p ) { // the splitter handle after s
1147 data->list.take(); //take p
1148 data->list.append( p );
1150 data->list.append( s );
1153 s = data->list.next();
1161 void QSplitterP::recalcId()
1163 int n = data->list.count();
1164 for ( int i = 0; i < n; i++ ) {
1165 QSplitterPLayoutStruct *s = data->list.at(i);
1166 if ( s->isSplitter )
1167 ((QSplitterPHandle*)s->wid)->setId(i);
1174 QSize QSplitterP::sizeHint() const
1180 const QObjectList * c = children();
1181 QObjectListIt it( *c );
1184 while( (o=it.current()) != 0 ) {
1186 if ( o->isWidgetType() &&
1187 !((QWidget*)o)->isHidden() ) {
1188 QSize s = ((QWidget*)o)->sizeHint();
1189 if ( s.isValid() ) {
1191 t = QMAX( t, trans( s ) );
1196 return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
1204 QSize QSplitterP::minimumSizeHint() const
1210 const QObjectList * c = children();
1211 QObjectListIt it( *c );
1214 while( (o=it.current()) != 0 ) {
1216 if ( o->isWidgetType() &&
1217 !((QWidget*)o)->isHidden() ) {
1218 QSize s = minSize((QWidget*)o);
1219 if ( s.isValid() ) {
1221 t = QMAX( t, trans( s ) );
1226 return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
1233 QSizePolicy QSplitterP::sizePolicy() const
1235 return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
1240 Calculates stretch parameters from current sizes
1243 void QSplitterP::storeSizes()
1245 QSplitterPLayoutStruct *s = data->list.first();
1247 if ( !s->isSplitter )
1248 s->sizer = pick( s->wid->size() );
1249 s = data->list.next();
1254 #if 0 // ### remove this code ASAP
1257 Hides \a w if \a hide is TRUE, and updates the splitter.
1259 \warning Due to a limitation in the current implementation,
1260 calling QWidget::hide() will not work.
1263 void QSplitterP::setHidden( QWidget *w, bool hide )
1267 } else if ( w == w2 ) {
1271 qWarning( "QSplitterP::setHidden(), unknown widget" );
1284 Returns the hidden status of \a w
1287 bool QSplitterP::isHidden( QWidget *w ) const
1295 qWarning( "QSplitterP::isHidden(), unknown widget" );
1303 Returns a list of the size parameters of all the widgets in this
1306 Giving the values to setSizes() will give a splitter with the same
1310 QValueList<int> QSplitterP::sizes() const
1312 if ( !testWState(WState_Polished) ) {
1313 QWidget* that = (QWidget*) this;
1316 QValueList<int> list;
1317 QSplitterPLayoutStruct *s = data->list.first();
1319 if ( !s->isSplitter )
1320 list.append( s->sizer );
1321 s = data->list.next();
1329 Sets the size parameters to the values given in \a list.
1330 If the splitterP is horizontal, the values set the sizes from
1331 left to right. If it is vertical, the sizes are applied from
1333 Extra values in \a list are ignored.
1335 If \a list contains too few values, the result is undefined
1336 but the program will still be well-behaved.
1339 void QSplitterP::setSizes( QValueList<int> list )
1341 processChildEvents();
1342 QValueList<int>::Iterator it = list.begin();
1343 QSplitterPLayoutStruct *s = data->list.first();
1344 while ( s && it != list.end() ) {
1345 if ( !s->isSplitter ) {
1349 s = data->list.next();
1356 Gets all posted child events, ensuring that the internal state of
1357 the splitter is consistent with the programmer's idea.
1360 void QSplitterP::processChildEvents()
1362 QApplication::sendPostedEvents( this, QEvent::ChildInserted );
1370 void QSplitterP::styleChange( QStyle& old )
1372 #if QT_VERSION < 300
1373 int sw = style().splitterWidth();
1375 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); //qt3.x
1377 QSplitterPLayoutStruct *s = data->list.first();
1379 if ( s->isSplitter )
1381 s = data->list.next();
1384 QFrame::styleChange( old );
1388 bool QSplitterP::isCompressEnabled() const
1390 return compress_flag;
1393 void QSplitterP::setCompressEnabled(bool on) {
1397 void QSplitterP::updateSplitterHandles() const {
1398 QSplitterPLayoutStruct *s = data->list.first();
1400 if ( s->isSplitter )
1401 ((QSplitterPHandle*)s->wid)->updateButtonState();
1402 s = data->list.next();