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 connect(left, SIGNAL(clicked()), this, SLOT(onBeforeCompress()));
135 connect(right, SIGNAL(clicked()), this, SLOT(onAfterCompress()));
136 connect(unleft, SIGNAL(clicked()), this, SLOT(onBeforeUnCompress()));
137 connect(unright, SIGNAL(clicked()), this, SLOT(onAfterUnCompress()));
140 void QSplitterPHandle::onBeforeCompress() {
141 oldpos = s->pick(pos());
142 int pos = s->pick(s->widgetBefore(id())->pos());
143 s->compress(s->widgetBefore(id()));
144 s->moveSplitter(pos, id());
145 s->updateSplitterHandles();
148 void QSplitterPHandle::onBeforeUnCompress() {
149 s->unCompress(s->widgetBefore(id()));
150 s->moveSplitter(oldpos, id());
151 s->updateSplitterHandles();
154 void QSplitterPHandle::onAfterCompress() {
155 oldpos = s->pick(pos());
156 int pos = s->pick(s->widgetAfter(id())->pos()) + s->pick(s->widgetAfter(id())->size()) - s->pick(size());
157 s->compress(s->widgetAfter(id()));
158 s->moveSplitter(pos, id());
159 s->updateSplitterHandles();
162 void QSplitterPHandle::onAfterUnCompress() {
163 s->unCompress(s->widgetAfter(id()));
164 s->moveSplitter(oldpos, id());
165 s->updateSplitterHandles();
168 // VSR 21/11/02 -> ================================
169 void QSplitterPHandle::compressAfter()
174 void QSplitterPHandle::unCompressAfter()
179 void QSplitterPHandle::compressBefore()
184 void QSplitterPHandle::unCompressBefore()
186 onBeforeUnCompress();
188 // VSR 21/11/02 <- ================================
190 QSizePolicy QSplitterPHandle::sizePolicy() const
193 return QWidget::sizePolicy();
196 QSize QSplitterPHandle::sizeHint() const
199 int sw = style().splitterWidth();
200 return QSize(sw,sw).expandedTo( QApplication::globalStrut() );
202 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this);
203 return (style().sizeFromContents(QStyle::CT_Splitter, s, QSize(sw, sw)).
204 expandedTo(QApplication::globalStrut()));
208 void QSplitterPHandle::setOrientation( Qt::Orientation o )
212 if ( o == QSplitterP::Horizontal )
213 setCursor( splitHCursor );
215 setCursor( splitVCursor );
219 if ( orient == QSplitterP::Horizontal )
221 lp = QPixmap(splitter_left_xpm);
222 rp = QPixmap(splitter_right_xpm);
226 lp = QPixmap(splitter_up_xpm);
227 rp = QPixmap(splitter_down_xpm);
230 right->setPixmap(rp);
231 unleft->setPixmap(rp);
232 unright->setPixmap(lp);
235 void QSplitterPHandle::mouseMoveEvent( QMouseEvent *e )
237 if ( !(e->state()&LeftButton) )
239 QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()))
242 s->moveSplitter( pos, id() );
244 int min = pos; int max = pos;
245 s->getRange( id(), &min, &max );
246 s->setRubberband( QMAX( min, QMIN(max, pos )));
250 void QSplitterPHandle::mousePressEvent( QMouseEvent *e )
252 if ( e->button() == LeftButton )
253 mouseOffset = s->pick(e->pos());
256 void QSplitterPHandle::mouseReleaseEvent( QMouseEvent *e )
258 if ( !opaque() && e->button() == LeftButton ) {
259 QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()));
260 s->setRubberband( -1 );
261 s->moveSplitter( pos, id() );
265 void QSplitterPHandle::paintEvent( QPaintEvent * )
269 s->drawSplitter( &p, 0, 0, width(), height() );
272 void QSplitterPHandle::updateButtonState() {
273 if (!s->isCompressEnabled()) {
280 if ( orient == QSplitterP::Horizontal )
282 left->setGeometry( QRect( QPoint( (width() - SPLITTER_ICON_WIDTH)/2, 0 ),
283 QSize ( SPLITTER_ICON_WIDTH, SPLITTER_ICON_HEIGHT ) ) );
284 right->setGeometry( QRect( QPoint( (width() - SPLITTER_ICON_WIDTH)/2, SPLITTER_ICON_HEIGHT ),
285 QSize ( SPLITTER_ICON_WIDTH, SPLITTER_ICON_HEIGHT ) ) );
286 unleft->setGeometry( left->geometry() );
287 unright->setGeometry( right->geometry() );
291 left->setGeometry( QRect( QPoint( 0, (height() - SPLITTER_ICON_WIDTH)/2 ),
292 QSize ( SPLITTER_ICON_HEIGHT, SPLITTER_ICON_WIDTH ) ) );
293 right->setGeometry( QRect( QPoint( SPLITTER_ICON_HEIGHT, (height() - SPLITTER_ICON_WIDTH)/2),
294 QSize ( SPLITTER_ICON_HEIGHT, SPLITTER_ICON_WIDTH ) ) );
295 unleft->setGeometry( left->geometry() );
296 unright->setGeometry( right->geometry() );
298 if ( s->isCompressed( s->widgetBefore( id() ) ) ) {
301 right->setEnabled(false);
306 right->setEnabled(true);
308 if ( s->isCompressed( s->widgetAfter( id() ) ) ) {
311 left->setEnabled(false);
316 left->setEnabled(true);
321 class QSplitterPLayoutStruct
324 QSplitterP::ResizeMode mode;
333 QSplitterPData() : opaque( FALSE ), firstShow( TRUE ) {}
335 QList<QSplitterPLayoutStruct> list;
343 \class QSplitter qsplitter.h
344 \brief The QSplitter class implements a splitter widget.
348 A splitter lets the user control the size of child widgets by
349 dragging the boundary between the children. Any number of widgets
352 To show a QListBox, a QListView and a QMultiLineEdit side by side:
355 QSplitter *split = new QSplitter( parent );
356 QListBox *lb = new QListBox( split );
357 QListView *lv = new QListView( split );
358 QMultiLineEdit *ed = new QMultiLineEdit( split );
361 In QSplitter the boundary can be either horizontal or vertical. The
362 default is horizontal (the children are side by side) and you
363 can use setOrientation( QSplitter::Vertical ) to set it to vertical.
365 By default, all widgets can be as large or as small as the user
366 wishes, down to \link QWidget::minimumSizeHint() minimumSizeHint()\endlink.
367 You can naturally use setMinimumSize() and/or
368 setMaximumSize() on the children. Use setResizeMode() to specify that
369 a widget should keep its size when the splitter is resized.
371 QSplitter normally resizes the children only at the end of a
372 resize operation, but if you call setOpaqueResize( TRUE ), the
373 widgets are resized as often as possible.
375 The initial distribution of size between the widgets is determined
376 by the initial size of each widget. You can also use setSizes() to
377 set the sizes of all the widgets. The function sizes() returns the
378 sizes set by the user.
380 If you hide() a child, its space will be distributed among the other
381 children. When you show() it again, it will be reinstated.
383 <img src=qsplitter-m.png> <img src=qsplitter-w.png>
390 QSize QSplitterP::minSize( const QWidget *w ) const
392 if ( isCompressed(w) && (data->list.count() > 1 ) ) return QSize(0,0);
393 QSize min = w->minimumSize();
395 if ( min.height() <= 0 || min.width() <= 0 )
396 s = w->minimumSizeHint();
397 if ( min.height() > 0 )
398 s.setHeight( min.height() );
399 if ( min.width() > 0 )
400 s.setWidth( min.width() );
401 return s.expandedTo(QSize(0,0));
404 QSize QSplitterP::maxSize( const QWidget* w ) const
406 if ( isCompressed(w) && (data->list.count() > 1 ) ) return QSize(0,0);
407 else return w->maximumSize();
411 Constructs a horizontal splitter.
414 QSplitterP::QSplitterP( QWidget *parent, const char *name )
415 :QFrame(parent,name,WPaintUnclipped)
423 Constructs splitter with orientation \a o.
426 QSplitterP::QSplitterP( Orientation o, QWidget *parent, const char *name )
427 :QFrame(parent,name,WPaintUnclipped)
435 Destructs the splitter.
438 QSplitterP::~QSplitterP()
440 data->list.setAutoDelete( TRUE );
445 void QSplitterP::init()
447 data = new QSplitterPData;
448 if ( orient == Horizontal )
449 setSizePolicy( QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Minimum) );
451 setSizePolicy( QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Fixed) );
452 compressed_widgets.clear();
453 compress_flag = false;
458 \fn void QSplitter::refresh()
460 Updates the splitter state. You should not need to call this
461 function during normal use of the splitter.
465 /*! Sets the orientation to \a o. By default the orientation is
466 horizontal (the widgets are side by side).
471 void QSplitterP::setOrientation( Orientation o )
477 if ( orient == Horizontal )
478 setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) );
480 setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
482 QSplitterPLayoutStruct *s = data->list.first();
485 ((QSplitterPHandle*)s->wid)->setOrientation( o );
486 s = data->list.next(); // ### next at end of loop, no iterator
488 recalc( isVisible() );
493 \fn Orientation QSplitter::orientation() const
495 Returns the orientation (\c Horizontal or \c Vertical) of the splitter.
502 void QSplitterP::resizeEvent( QResizeEvent * )
509 Inserts the widget \a w at the end, or at the beginning if \a first is TRUE
511 It is the responsibility of the caller of this function to make sure
512 that \a w is not already in the splitter, and to call recalcId if
513 needed. (If \a first is TRUE, then recalcId is very probably
517 QSplitterPLayoutStruct *QSplitterP::addWidget( QWidget *w, bool first )
519 QSplitterPLayoutStruct *s;
520 QSplitterPHandle *newHandle = 0;
521 if ( data->list.count() > 0 ) {
522 s = new QSplitterPLayoutStruct;
524 newHandle = new QSplitterPHandle( orientation(), this );
526 newHandle->setId(data->list.count());
527 s->isSplitter = TRUE;
528 s->sizer = pick( newHandle->sizeHint() );
530 data->list.insert( 0, s );
532 data->list.append( s );
534 s = new QSplitterPLayoutStruct;
537 if ( !testWState( WState_Resized ) && w->sizeHint().isValid() )
538 s->sizer = pick( w->sizeHint() );
540 s->sizer = pick( w->size() );
541 s->isSplitter = FALSE;
543 data->list.insert( 0, s );
545 data->list.append( s );
546 if ( newHandle && isVisible() )
547 newHandle->show(); //will trigger sending of post events
553 Tells the splitter that a child widget has been inserted/removed.
556 void QSplitterP::childEvent( QChildEvent *c )
558 if ( c->type() == QEvent::ChildInserted ) {
559 if ( !c->child()->isWidgetType() )
562 if ( ((QWidget*)c->child())->testWFlags( WType_TopLevel ) )
565 QSplitterPLayoutStruct *s = data->list.first();
567 if ( s->wid == c->child() )
569 s = data->list.next();
571 addWidget( (QWidget*)c->child() );
572 recalc( isVisible() );
574 } else if ( c->type() == QEvent::ChildRemoved ) {
575 QSplitterPLayoutStruct *p = 0;
576 if ( data->list.count() > 1 )
577 p = data->list.at(1); //remove handle _after_ first widget.
578 QSplitterPLayoutStruct *s = data->list.first();
580 if ( s->wid == c->child() ) {
581 data->list.removeRef( s );
583 if ( p && p->isSplitter ) {
584 data->list.removeRef( p );
585 delete p->wid; //will call childEvent
593 s = data->list.next();
600 Shows a rubber band at position \a p. If \a p is negative, the
601 rubber band is removed.
604 void QSplitterP::setRubberband( int p )
606 QPainter paint( this );
607 paint.setPen( gray );
608 paint.setBrush( gray );
609 paint.setRasterOp( XorROP );
610 QRect r = contentsRect();
611 const int rBord = 3; //Themable????
613 const int sw = style().splitterWidth();
615 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); //qt3.x
617 if ( orient == Horizontal ) {
618 if ( opaqueOldPos >= 0 )
619 paint.drawRect( opaqueOldPos + sw/2 - rBord , r.y(),
620 2*rBord, r.height() );
622 paint.drawRect( p + sw/2 - rBord, r.y(), 2*rBord, r.height() );
624 if ( opaqueOldPos >= 0 )
625 paint.drawRect( r.x(), opaqueOldPos + sw/2 - rBord,
626 r.width(), 2*rBord );
628 paint.drawRect( r.x(), p + sw/2 - rBord, r.width(), 2*rBord );
636 bool QSplitterP::event( QEvent *e )
638 if ( e->type() == QEvent::LayoutHint || ( e->type() == QEvent::Show && data->firstShow ) ) {
639 recalc( isVisible() );
640 if ( e->type() == QEvent::Show )
641 data->firstShow = FALSE;
643 return QWidget::event( e );
648 Draws the splitter handle in the rectangle described by \a x, \a y,
649 \a w, \a h using painter \a p.
650 \sa QStyle::drawSplitter
653 void QSplitterP::drawSplitter( QPainter *p,
654 QCOORD x, QCOORD y, QCOORD w, QCOORD h )
657 style().drawSplitter( p, x, y, w, h, colorGroup(), orient );
659 style().drawPrimitive(QStyle::PE_Splitter, p, QRect(x, y, w, h), colorGroup(),
660 (orientation() == Qt::Horizontal ?
661 QStyle::Style_Horizontal : 0));
667 Returns the id of the splitter to the right of or below the widget \a w,
668 or 0 if there is no such splitter.
669 (ie. it is either not in this QSplitter, or it is at the end).
672 int QSplitterP::idAfter( QWidget* w ) const
674 QSplitterPLayoutStruct *s = data->list.first();
677 if ( s->isSplitter && seen_w )
678 return data->list.at();
679 if ( !s->isSplitter && s->wid == w )
681 s = data->list.next();
686 // VSR 21/11/02 -> ================================
687 QSplitterPHandle* QSplitterP::getHandleAfter(QWidget* w)
689 QSplitterPLayoutStruct *s = data->list.first();
692 if ( s->isSplitter && seen_w )
693 return (QSplitterPHandle*)s->wid;
694 if ( !s->isSplitter && s->wid == w )
696 s = data->list.next();
701 QSplitterPHandle* QSplitterP::getHandleBefore(QWidget* w)
703 QSplitterPLayoutStruct *s = data->list.first();
704 QSplitterPHandle* h = 0;
707 h = (QSplitterPHandle*)s;
708 if ( !s->isSplitter && s->wid == w )
710 s = data->list.next();
714 // VSR 21/11/02 <- ================================
716 QWidget* QSplitterP::widgetBefore( int id ) const
718 QSplitterPLayoutStruct *s = data->list.first();
721 if ( !s->isSplitter ) {
723 if (idAfter(w) == id) return w;
725 s = data->list.next();
730 QWidget* QSplitterP::widgetAfter( int id ) const
732 QSplitterPLayoutStruct *s = data->list.first();
735 if ( !s->isSplitter && seen_s )
737 if ( s->isSplitter && data->list.at() == id )
739 s = data->list.next();
744 void QSplitterP::unCompress(QWidget* w) {
745 compressed_widgets.remove(w);
748 void QSplitterP::compress(QWidget* w)
750 if (!isCompressed(w)) compressed_widgets.append(w);
753 bool QSplitterP::isCompressed(const QWidget* w) const {
754 QWidget* t = (QWidget*)w;
755 if (compressed_widgets.containsRef(t)==0) return false;
760 Moves the left/top edge of the splitter handle with id \a id as
761 close as possible to \a p which is the distance from the left (or
762 top) edge of the widget.
766 void QSplitterP::moveSplitter( QCOORD p, int id )
768 p = adjustPos( p, id );
770 QSplitterPLayoutStruct *s = data->list.at(id);
771 int oldP = orient == Horizontal? s->wid->x() : s->wid->y();
772 bool upLeft = p < oldP;
774 moveAfter( p, id, upLeft );
775 moveBefore( p-1, id-1, upLeft );
781 void QSplitterP::setG( QWidget *w, int p, int s )
783 if ( orient == Horizontal )
784 w->setGeometry( p, contentsRect().y(), s, contentsRect().height() );
786 w->setGeometry( contentsRect().x(), p, contentsRect().width(), s );
791 Places the right/bottom edge of the widget at \a id at position \a pos.
796 void QSplitterP::moveBefore( int pos, int id, bool upLeft )
798 QSplitterPLayoutStruct *s = data->list.at(id);
802 if ( w->isHidden() ) {
803 moveBefore( pos, id-1, upLeft );
804 } else if ( s->isSplitter ) {
807 setG( w, pos-dd+1, dd );
808 moveBefore( pos-dd, id-1, upLeft );
810 moveBefore( pos-dd, id-1, upLeft );
811 setG( w, pos-dd+1, dd );
814 int left = pick( w->pos() );
815 int dd = pos - left + 1;
816 dd = QMAX( pick(minSize(w)), QMIN(dd, pick(maxSize(w))));
817 int newLeft = pos-dd+1;
818 setG( w, newLeft, dd );
819 if ( left != newLeft )
820 moveBefore( newLeft-1, id-1, upLeft );
826 Places the left/top edge of the widget at \a id at position \a pos.
831 void QSplitterP::moveAfter( int pos, int id, bool upLeft )
833 QSplitterPLayoutStruct *s = id < int(data->list.count()) ?
834 data->list.at(id) : 0;
838 if ( w->isHidden() ) {
839 moveAfter( pos, id+1, upLeft );
840 } else if ( pick( w->pos() ) == pos ) {
841 //No need to do anything if it's already there.
843 } else if ( s->isSplitter ) {
847 moveAfter( pos+dd, id+1, upLeft );
849 moveAfter( pos+dd, id+1, upLeft );
853 int right = pick( w->geometry().bottomRight() );
854 int ddd = pick( QSize(contentsRect().width(), contentsRect().height() ) ) - pos;
855 int dd = QMIN(right - pos + 1, ddd);
856 dd = QMAX( pick(minSize(w)), QMIN(dd, pick(maxSize(w))));
857 int newRight = pos+dd-1;
859 moveAfter( newRight+1, id+1, upLeft );
865 Returns the valid range of the splitter with id \a id in \a min and \a max.
870 void QSplitterP::getRange( int id, int *min, int *max )
872 int minB = 0; //before
875 int maxA = 0; //after
876 int n = data->list.count();
877 if ( id < 0 || id >= n )
880 for ( i = 0; i < id; i++ ) {
881 QSplitterPLayoutStruct *s = data->list.at(i);
882 if ( s->isSplitter ) {
886 minB += pick( minSize(s->wid) );
887 maxB += pick( maxSize(s->wid) );
890 for ( i = id; i < n; i++ ) {
891 QSplitterPLayoutStruct *s = data->list.at(i);
892 if ( s->isSplitter ) {
896 minA += pick( minSize(s->wid) );
897 maxA += pick( maxSize(s->wid) );
900 QRect r = contentsRect();
902 *min = pick(r.topLeft()) + QMAX( minB, pick(r.size())-maxA );
904 *max = pick(r.topLeft()) + QMIN( maxB, pick(r.size())-minA );
910 Returns the legal position closest to \a p of the splitter with id \a id.
915 int QSplitterP::adjustPos( int p, int id )
919 getRange( id, &min, &max );
920 p = QMAX( min, QMIN( p, max ) );
926 void QSplitterP::doResize()
928 QRect r = contentsRect();
930 int n = data->list.count();
931 QArray<QLayoutStruct> a( n );
932 for ( i = 0; i< n; i++ ) {
934 QSplitterPLayoutStruct *s = data->list.at(i);
935 if ( s->wid->isHidden() ) {
937 a[i].sizeHint = a[i].minimumSize = 0;
938 a[i].maximumSize = 0;
939 } else if ( s->isSplitter ) {
941 a[i].sizeHint = a[i].minimumSize = a[i].maximumSize = s->sizer;
943 } else if ( s->mode == KeepSize ) {
945 a[i].minimumSize = pick( minSize(s->wid) );
946 a[i].sizeHint = s->sizer;
947 a[i].maximumSize = pick( maxSize(s->wid) );
949 } else if ( s->mode == FollowSizeHint ) {
951 a[i].minimumSize = a[i].sizeHint = pick( s->wid->sizeHint() );
952 a[i].maximumSize = pick( maxSize(s->wid) );
954 } else { //proportional
955 a[i].stretch = s->sizer;
956 a[i].maximumSize = pick( maxSize(s->wid) );
957 a[i].sizeHint = a[i].minimumSize = pick( minSize(s->wid) );
962 qGeomCalc( a, 0, n, pick( r.topLeft() ), pick( r.size() ), 0 );
963 for ( i = 0; i< n; i++ ) {
964 QSplitterPLayoutStruct *s = data->list.at(i);
965 if ( orient == Horizontal )
966 s->wid->setGeometry( a[i].pos, r.top(), a[i].size, r.height() );
968 s->wid->setGeometry( r.left(), a[i].pos, r.width(), a[i].size );
974 void QSplitterP::recalc( bool update )
976 int fi = 2*frameWidth();
979 int maxt = QWIDGETSIZE_MAX;
981 int n = data->list.count();
984 The splitter before a hidden widget is always hidden.
985 The splitter before the first visible widget is hidden.
986 The splitter before any other visible widget is visible.
988 for ( int i = 0; i< n; i++ ) {
989 QSplitterPLayoutStruct *s = data->list.at(i);
990 if ( !s->isSplitter ) {
991 QSplitterPLayoutStruct *p = (i > 0) ? p = data->list.at( i-1 ) : 0;
992 if ( p && p->isSplitter )
993 if ( first || s->wid->isHidden() )
994 p->wid->hide(); //may trigger new recalc
996 p->wid->show(); //may trigger new recalc
997 if ( !s->wid->isHidden() )
1003 for ( int j = 0; j< n; j++ ) {
1004 QSplitterPLayoutStruct *s = data->list.at(j);
1005 if ( !s->wid->isHidden() ) {
1007 if ( s->isSplitter ) {
1011 QSize minS = minSize(s->wid);
1012 minl += pick( minS );
1013 maxl += pick( maxSize(s->wid) );
1014 mint = QMAX( mint, trans( minS ));
1015 int tm = trans( maxSize(s->wid) );
1017 maxt = QMIN( maxt, tm );
1024 maxl = QMIN( maxl, QWIDGETSIZE_MAX );
1028 if ( orient == Horizontal ) {
1029 setMaximumSize( maxl, maxt );
1030 setMinimumSize( minl, mint );
1032 setMaximumSize( maxt, maxl );
1033 setMinimumSize( mint, minl );
1039 /*! \enum QSplitter::ResizeMode
1041 This enum type describes how QSplitter will resize each of its child widgets. The currently defined values are: <ul>
1043 <li> \c Stretch - the widget will be resized when the splitter
1046 <li> \c KeepSize - QSplitter will try to keep this widget's size
1049 <li> \c FollowSizeHint - QSplitter will resize the widget when its
1057 Sets resize mode of \a w to \a mode.
1062 void QSplitterP::setResizeMode( QWidget *w, ResizeMode mode )
1064 processChildEvents();
1065 QSplitterPLayoutStruct *s = data->list.first();
1067 if ( s->wid == w ) {
1071 s = data->list.next();
1073 s = addWidget( w, TRUE );
1079 Returns TRUE if opaque resize is on, FALSE otherwise.
1081 \sa setOpaqueResize()
1084 bool QSplitterP::opaqueResize() const
1086 return data->opaque;
1091 Sets opaque resize to \a on. Opaque resize is initially turned off.
1096 void QSplitterP::setOpaqueResize( bool on )
1103 Moves \a w to the leftmost/top position.
1106 void QSplitterP::moveToFirst( QWidget *w )
1108 processChildEvents();
1110 QSplitterPLayoutStruct *s = data->list.first();
1112 if ( s->wid == w ) {
1114 QSplitterPLayoutStruct *p = data->list.prev();
1115 if ( p ) { // not already at first place
1116 data->list.take(); //take p
1117 data->list.take(); // take s
1118 data->list.insert( 0, p );
1119 data->list.insert( 0, s );
1123 s = data->list.next();
1126 addWidget( w, TRUE );
1132 Moves \a w to the rightmost/bottom position.
1135 void QSplitterP::moveToLast( QWidget *w )
1137 processChildEvents();
1139 QSplitterPLayoutStruct *s = data->list.first();
1141 if ( s->wid == w ) {
1143 data->list.take(); // take s
1144 QSplitterPLayoutStruct *p = data->list.current();
1145 if ( p ) { // the splitter handle after s
1146 data->list.take(); //take p
1147 data->list.append( p );
1149 data->list.append( s );
1152 s = data->list.next();
1160 void QSplitterP::recalcId()
1162 int n = data->list.count();
1163 for ( int i = 0; i < n; i++ ) {
1164 QSplitterPLayoutStruct *s = data->list.at(i);
1165 if ( s->isSplitter )
1166 ((QSplitterPHandle*)s->wid)->setId(i);
1173 QSize QSplitterP::sizeHint() const
1179 const QObjectList * c = children();
1180 QObjectListIt it( *c );
1183 while( (o=it.current()) != 0 ) {
1185 if ( o->isWidgetType() &&
1186 !((QWidget*)o)->isHidden() ) {
1187 QSize s = ((QWidget*)o)->sizeHint();
1188 if ( s.isValid() ) {
1190 t = QMAX( t, trans( s ) );
1195 return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
1203 QSize QSplitterP::minimumSizeHint() const
1209 const QObjectList * c = children();
1210 QObjectListIt it( *c );
1213 while( (o=it.current()) != 0 ) {
1215 if ( o->isWidgetType() &&
1216 !((QWidget*)o)->isHidden() ) {
1217 QSize s = minSize((QWidget*)o);
1218 if ( s.isValid() ) {
1220 t = QMAX( t, trans( s ) );
1225 return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
1232 QSizePolicy QSplitterP::sizePolicy() const
1234 return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
1239 Calculates stretch parameters from current sizes
1242 void QSplitterP::storeSizes()
1244 QSplitterPLayoutStruct *s = data->list.first();
1246 if ( !s->isSplitter )
1247 s->sizer = pick( s->wid->size() );
1248 s = data->list.next();
1253 #if 0 // ### remove this code ASAP
1256 Hides \a w if \a hide is TRUE, and updates the splitter.
1258 \warning Due to a limitation in the current implementation,
1259 calling QWidget::hide() will not work.
1262 void QSplitterP::setHidden( QWidget *w, bool hide )
1266 } else if ( w == w2 ) {
1270 qWarning( "QSplitterP::setHidden(), unknown widget" );
1283 Returns the hidden status of \a w
1286 bool QSplitterP::isHidden( QWidget *w ) const
1294 qWarning( "QSplitterP::isHidden(), unknown widget" );
1302 Returns a list of the size parameters of all the widgets in this
1305 Giving the values to setSizes() will give a splitter with the same
1309 QValueList<int> QSplitterP::sizes() const
1311 if ( !testWState(WState_Polished) ) {
1312 QWidget* that = (QWidget*) this;
1315 QValueList<int> list;
1316 QSplitterPLayoutStruct *s = data->list.first();
1318 if ( !s->isSplitter )
1319 list.append( s->sizer );
1320 s = data->list.next();
1328 Sets the size parameters to the values given in \a list.
1329 If the splitterP is horizontal, the values set the sizes from
1330 left to right. If it is vertical, the sizes are applied from
1332 Extra values in \a list are ignored.
1334 If \a list contains too few values, the result is undefined
1335 but the program will still be well-behaved.
1338 void QSplitterP::setSizes( QValueList<int> list )
1340 processChildEvents();
1341 QValueList<int>::Iterator it = list.begin();
1342 QSplitterPLayoutStruct *s = data->list.first();
1343 while ( s && it != list.end() ) {
1344 if ( !s->isSplitter ) {
1348 s = data->list.next();
1355 Gets all posted child events, ensuring that the internal state of
1356 the splitter is consistent with the programmer's idea.
1359 void QSplitterP::processChildEvents()
1361 QApplication::sendPostedEvents( this, QEvent::ChildInserted );
1369 void QSplitterP::styleChange( QStyle& old )
1371 #if QT_VERSION < 300
1372 int sw = style().splitterWidth();
1374 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); //qt3.x
1376 QSplitterPLayoutStruct *s = data->list.first();
1378 if ( s->isSplitter )
1380 s = data->list.next();
1383 QFrame::styleChange( old );
1387 bool QSplitterP::isCompressEnabled() const
1389 return compress_flag;
1392 void QSplitterP::setCompressEnabled(bool on) {
1396 void QSplitterP::updateSplitterHandles() const {
1397 QSplitterPLayoutStruct *s = data->list.first();
1399 if ( s->isSplitter )
1400 ((QSplitterPHandle*)s->wid)->updateButtonState();
1401 s = data->list.next();