1 // SALOME PatchQt : patch for Qt
3 // Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
24 // File : qsplitterP.cxx
28 /****************************************************************************
35 ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
37 ** This file is part of the widgets module of the Qt GUI Toolkit.
39 ** This file may be distributed under the terms of the Q Public License
40 ** as defined by Trolltech AS of Norway and appearing in the file
41 ** LICENSE.QPL included in the packaging of this file.
43 ** This file may be distributed and/or modified under the terms of the
44 ** GNU General Public License version 2 as published by the Free Software
45 ** Foundation and appearing in the file LICENSE.GPL included in the
46 ** packaging of this file.
48 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
49 ** licenses may use this file in accordance with the Qt Commercial License
50 ** Agreement provided with the Software.
52 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
53 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
55 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
56 ** information about Qt Commercial License Agreements.
57 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
58 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
60 ** Contact info@trolltech.com if any conditions of this licensing are
63 **********************************************************************/
64 #include "qsplitterP.h"
65 #ifndef QT_NO_COMPLEXWIDGETS
69 #include <qdrawutil.h>
71 #include <private/qlayoutengine_p.h>
76 #include <qptrlist.h> //qt3.x
77 #include <qmemarray.h> //qt3.x
78 #include <qstyle.h> //qt3.x
81 #include <qobjectlist.h>
82 #include <qapplication.h> //sendPostedEvents
84 #define SPLITTER_ICON_WIDTH 10
85 #define SPLITTER_ICON_HEIGHT 12
87 static int mouseOffset;
88 static int opaqueOldPos = -1; //### there's only one mouse, but this is a bit risky
90 static const char* splitter_left_xpm[] = {
92 " s none m none c none",
93 ". s iconColor1 m black c black",
101 static const char* splitter_right_xpm[] = {
103 " s iconColor1 m black c black",
104 ". s none m none c none",
112 static const char* splitter_up_xpm[] = {
114 " s none m none c none",
115 ". s iconColor1 m black c black",
123 static const char* splitter_down_xpm[] = {
125 " s iconColor1 m black c black",
126 ". s none m none c none",
134 QSplitterPHandle::QSplitterPHandle( Qt::Orientation o,
135 QSplitterP *parent, const char * name )
136 : QWidget( parent, name )
140 left = new QPushButton(this);
141 right = new QPushButton(this);
142 unleft = new QPushButton(this);
143 unright = new QPushButton(this);
147 left->setAutoDefault(false); unleft->setAutoDefault(false);
148 right->setAutoDefault(false); unright->setAutoDefault(false);
149 left->setFlat(true); right->setFlat(true); unleft->setFlat(true); unright->setFlat(true);
150 left->setCursor( arrowCursor ); right->setCursor( arrowCursor );
151 unleft->setCursor( arrowCursor ); unright->setCursor( arrowCursor );
153 // VSR 21/11/02 -> ================================
154 setMinimumSize( 1, 1 );
155 // VSR 21/11/02 <- ================================
157 connect(left, SIGNAL(clicked()), this, SLOT(onBeforeCompress()));
158 connect(right, SIGNAL(clicked()), this, SLOT(onAfterCompress()));
159 connect(unleft, SIGNAL(clicked()), this, SLOT(onBeforeUnCompress()));
160 connect(unright, SIGNAL(clicked()), this, SLOT(onAfterUnCompress()));
163 void QSplitterPHandle::onBeforeCompress() {
164 oldpos = s->pick(pos());
165 int pos = s->pick(s->widgetBefore(id())->pos());
166 s->compress(s->widgetBefore(id()));
167 s->moveSplitter(pos, id());
168 s->updateSplitterHandles();
171 void QSplitterPHandle::onBeforeUnCompress() {
172 s->unCompress(s->widgetBefore(id()));
173 s->moveSplitter(oldpos, id());
174 s->updateSplitterHandles();
177 void QSplitterPHandle::onAfterCompress() {
178 oldpos = s->pick(pos());
179 int pos = s->pick(s->widgetAfter(id())->pos()) + s->pick(s->widgetAfter(id())->size()) - s->pick(size());
180 s->compress(s->widgetAfter(id()));
181 s->moveSplitter(pos, id());
182 s->updateSplitterHandles();
185 void QSplitterPHandle::onAfterUnCompress() {
186 s->unCompress(s->widgetAfter(id()));
187 s->moveSplitter(oldpos, id());
188 s->updateSplitterHandles();
191 // VSR 21/11/02 -> ================================
192 void QSplitterPHandle::compressAfter()
197 void QSplitterPHandle::unCompressAfter()
202 void QSplitterPHandle::compressBefore()
207 void QSplitterPHandle::unCompressBefore()
209 onBeforeUnCompress();
211 // VSR 21/11/02 <- ================================
213 QSizePolicy QSplitterPHandle::sizePolicy() const
216 return QWidget::sizePolicy();
219 QSize QSplitterPHandle::sizeHint() const
222 int sw = style().splitterWidth();
223 return QSize(sw,sw).expandedTo( QApplication::globalStrut() );
225 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this);
226 return (style().sizeFromContents(QStyle::CT_Splitter, s, QSize(sw, sw)).
227 expandedTo(QApplication::globalStrut()));
231 void QSplitterPHandle::setOrientation( Qt::Orientation o )
235 if ( o == QSplitterP::Horizontal )
236 setCursor( splitHCursor );
238 setCursor( splitVCursor );
242 if ( orient == QSplitterP::Horizontal )
244 lp = QPixmap(splitter_left_xpm);
245 rp = QPixmap(splitter_right_xpm);
249 lp = QPixmap(splitter_up_xpm);
250 rp = QPixmap(splitter_down_xpm);
253 right->setPixmap(rp);
254 unleft->setPixmap(rp);
255 unright->setPixmap(lp);
258 void QSplitterPHandle::mouseMoveEvent( QMouseEvent *e )
260 if ( !(e->state()&LeftButton) )
262 QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()))
265 s->moveSplitter( pos, id() );
267 int min = pos; int max = pos;
268 s->getRange( id(), &min, &max );
269 s->setRubberband( QMAX( min, QMIN(max, pos )));
273 void QSplitterPHandle::mousePressEvent( QMouseEvent *e )
275 if ( e->button() == LeftButton )
276 mouseOffset = s->pick(e->pos());
279 void QSplitterPHandle::mouseReleaseEvent( QMouseEvent *e )
281 if ( !opaque() && e->button() == LeftButton ) {
282 QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()));
283 s->setRubberband( -1 );
284 s->moveSplitter( pos, id() );
288 void QSplitterPHandle::paintEvent( QPaintEvent * )
292 s->drawSplitter( &p, 0, 0, width(), height() );
295 void QSplitterPHandle::updateButtonState() {
296 if (!s->isCompressEnabled()) {
303 if ( orient == QSplitterP::Horizontal )
305 left->setGeometry( QRect( QPoint( (width() - SPLITTER_ICON_WIDTH)/2, 0 ),
306 QSize ( SPLITTER_ICON_WIDTH, SPLITTER_ICON_HEIGHT ) ) );
307 right->setGeometry( QRect( QPoint( (width() - SPLITTER_ICON_WIDTH)/2, SPLITTER_ICON_HEIGHT ),
308 QSize ( SPLITTER_ICON_WIDTH, SPLITTER_ICON_HEIGHT ) ) );
309 unleft->setGeometry( left->geometry() );
310 unright->setGeometry( right->geometry() );
314 left->setGeometry( QRect( QPoint( 0, (height() - SPLITTER_ICON_WIDTH)/2 ),
315 QSize ( SPLITTER_ICON_HEIGHT, SPLITTER_ICON_WIDTH ) ) );
316 right->setGeometry( QRect( QPoint( SPLITTER_ICON_HEIGHT, (height() - SPLITTER_ICON_WIDTH)/2),
317 QSize ( SPLITTER_ICON_HEIGHT, SPLITTER_ICON_WIDTH ) ) );
318 unleft->setGeometry( left->geometry() );
319 unright->setGeometry( right->geometry() );
321 if ( s->isCompressed( s->widgetBefore( id() ) ) ) {
324 right->setEnabled(false);
329 right->setEnabled(true);
331 if ( s->isCompressed( s->widgetAfter( id() ) ) ) {
334 left->setEnabled(false);
339 left->setEnabled(true);
344 class QSplitterPLayoutStruct
347 QSplitterP::ResizeMode mode;
356 QSplitterPData() : opaque( FALSE ), firstShow( TRUE ) {}
358 QList<QSplitterPLayoutStruct> list;
366 \class QSplitter qsplitter.h
367 \brief The QSplitter class implements a splitter widget.
371 A splitter lets the user control the size of child widgets by
372 dragging the boundary between the children. Any number of widgets
375 To show a QListBox, a QListView and a QMultiLineEdit side by side:
378 QSplitter *split = new QSplitter( parent );
379 QListBox *lb = new QListBox( split );
380 QListView *lv = new QListView( split );
381 QMultiLineEdit *ed = new QMultiLineEdit( split );
384 In QSplitter the boundary can be either horizontal or vertical. The
385 default is horizontal (the children are side by side) and you
386 can use setOrientation( QSplitter::Vertical ) to set it to vertical.
388 By default, all widgets can be as large or as small as the user
389 wishes, down to \link QWidget::minimumSizeHint() minimumSizeHint()\endlink.
390 You can naturally use setMinimumSize() and/or
391 setMaximumSize() on the children. Use setResizeMode() to specify that
392 a widget should keep its size when the splitter is resized.
394 QSplitter normally resizes the children only at the end of a
395 resize operation, but if you call setOpaqueResize( TRUE ), the
396 widgets are resized as often as possible.
398 The initial distribution of size between the widgets is determined
399 by the initial size of each widget. You can also use setSizes() to
400 set the sizes of all the widgets. The function sizes() returns the
401 sizes set by the user.
403 If you hide() a child, its space will be distributed among the other
404 children. When you show() it again, it will be reinstated.
406 <img src=qsplitter-m.png> <img src=qsplitter-w.png>
413 QSize QSplitterP::minSize( const QWidget *w ) const
415 if ( isCompressed(w) && (data->list.count() > 1 ) ) return QSize(0,0);
416 QSize min = w->minimumSize();
418 if ( min.height() <= 0 || min.width() <= 0 )
419 s = w->minimumSizeHint();
420 if ( min.height() > 0 )
421 s.setHeight( min.height() );
422 if ( min.width() > 0 )
423 s.setWidth( min.width() );
424 return s.expandedTo(QSize(0,0));
427 QSize QSplitterP::maxSize( const QWidget* w ) const
429 if ( isCompressed(w) && (data->list.count() > 1 ) ) return QSize(0,0);
430 else return w->maximumSize();
434 Constructs a horizontal splitter.
437 QSplitterP::QSplitterP( QWidget *parent, const char *name )
438 :QFrame(parent,name,WPaintUnclipped)
446 Constructs splitter with orientation \a o.
449 QSplitterP::QSplitterP( Orientation o, QWidget *parent, const char *name )
450 :QFrame(parent,name,WPaintUnclipped)
458 Destructs the splitter.
461 QSplitterP::~QSplitterP()
463 data->list.setAutoDelete( TRUE );
468 void QSplitterP::init()
470 data = new QSplitterPData;
471 if ( orient == Horizontal )
472 setSizePolicy( QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Minimum) );
474 setSizePolicy( QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Fixed) );
475 compressed_widgets.clear();
476 compress_flag = false;
481 \fn void QSplitter::refresh()
483 Updates the splitter state. You should not need to call this
484 function during normal use of the splitter.
488 /*! Sets the orientation to \a o. By default the orientation is
489 horizontal (the widgets are side by side).
494 void QSplitterP::setOrientation( Orientation o )
500 if ( orient == Horizontal )
501 setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) );
503 setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
505 QSplitterPLayoutStruct *s = data->list.first();
508 ((QSplitterPHandle*)s->wid)->setOrientation( o );
509 s = data->list.next(); // ### next at end of loop, no iterator
511 recalc( isVisible() );
516 \fn Orientation QSplitter::orientation() const
518 Returns the orientation (\c Horizontal or \c Vertical) of the splitter.
525 void QSplitterP::resizeEvent( QResizeEvent * )
532 Inserts the widget \a w at the end, or at the beginning if \a first is TRUE
534 It is the responsibility of the caller of this function to make sure
535 that \a w is not already in the splitter, and to call recalcId if
536 needed. (If \a first is TRUE, then recalcId is very probably
540 QSplitterPLayoutStruct *QSplitterP::addWidget( QWidget *w, bool first )
542 QSplitterPLayoutStruct *s;
543 QSplitterPHandle *newHandle = 0;
544 if ( data->list.count() > 0 ) {
545 s = new QSplitterPLayoutStruct;
547 newHandle = new QSplitterPHandle( orientation(), this );
549 newHandle->setId(data->list.count());
550 s->isSplitter = TRUE;
551 s->sizer = pick( newHandle->sizeHint() );
553 data->list.insert( 0, s );
555 data->list.append( s );
557 s = new QSplitterPLayoutStruct;
560 if ( !testWState( WState_Resized ) && w->sizeHint().isValid() )
561 s->sizer = pick( w->sizeHint() );
563 s->sizer = pick( w->size() );
564 s->isSplitter = FALSE;
566 data->list.insert( 0, s );
568 data->list.append( s );
569 if ( newHandle && isVisible() )
570 newHandle->show(); //will trigger sending of post events
576 Tells the splitter that a child widget has been inserted/removed.
579 void QSplitterP::childEvent( QChildEvent *c )
581 if ( c->type() == QEvent::ChildInserted ) {
582 if ( !c->child()->isWidgetType() )
585 if ( ((QWidget*)c->child())->testWFlags( WType_TopLevel ) )
588 QSplitterPLayoutStruct *s = data->list.first();
590 if ( s->wid == c->child() )
592 s = data->list.next();
594 addWidget( (QWidget*)c->child() );
595 recalc( isVisible() );
597 } else if ( c->type() == QEvent::ChildRemoved ) {
598 QSplitterPLayoutStruct *p = 0;
599 if ( data->list.count() > 1 )
600 p = data->list.at(1); //remove handle _after_ first widget.
601 QSplitterPLayoutStruct *s = data->list.first();
603 if ( s->wid == c->child() ) {
604 data->list.removeRef( s );
606 if ( p && p->isSplitter ) {
607 data->list.removeRef( p );
608 delete p->wid; //will call childEvent
616 s = data->list.next();
623 Shows a rubber band at position \a p. If \a p is negative, the
624 rubber band is removed.
627 void QSplitterP::setRubberband( int p )
629 QPainter paint( this );
630 paint.setPen( gray );
631 paint.setBrush( gray );
632 paint.setRasterOp( XorROP );
633 QRect r = contentsRect();
634 const int rBord = 3; //Themable????
636 const int sw = style().splitterWidth();
638 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); //qt3.x
640 if ( orient == Horizontal ) {
641 if ( opaqueOldPos >= 0 )
642 paint.drawRect( opaqueOldPos + sw/2 - rBord , r.y(),
643 2*rBord, r.height() );
645 paint.drawRect( p + sw/2 - rBord, r.y(), 2*rBord, r.height() );
647 if ( opaqueOldPos >= 0 )
648 paint.drawRect( r.x(), opaqueOldPos + sw/2 - rBord,
649 r.width(), 2*rBord );
651 paint.drawRect( r.x(), p + sw/2 - rBord, r.width(), 2*rBord );
659 bool QSplitterP::event( QEvent *e )
661 if ( e->type() == QEvent::LayoutHint || ( e->type() == QEvent::Show && data->firstShow ) ) {
662 recalc( isVisible() );
663 if ( e->type() == QEvent::Show )
664 data->firstShow = FALSE;
666 return QWidget::event( e );
671 Draws the splitter handle in the rectangle described by \a x, \a y,
672 \a w, \a h using painter \a p.
673 \sa QStyle::drawSplitter
676 void QSplitterP::drawSplitter( QPainter *p,
677 QCOORD x, QCOORD y, QCOORD w, QCOORD h )
680 style().drawSplitter( p, x, y, w, h, colorGroup(), orient );
682 style().drawPrimitive(QStyle::PE_Splitter, p, QRect(x, y, w, h), colorGroup(),
683 (orientation() == Qt::Horizontal ?
684 QStyle::Style_Horizontal : 0));
690 Returns the id of the splitter to the right of or below the widget \a w,
691 or 0 if there is no such splitter.
692 (ie. it is either not in this QSplitter, or it is at the end).
695 int QSplitterP::idAfter( QWidget* w ) const
697 QSplitterPLayoutStruct *s = data->list.first();
700 if ( s->isSplitter && seen_w )
701 return data->list.at();
702 if ( !s->isSplitter && s->wid == w )
704 s = data->list.next();
709 // VSR 21/11/02 -> ================================
710 QSplitterPHandle* QSplitterP::getHandleAfter(QWidget* w)
712 QSplitterPLayoutStruct *s = data->list.first();
715 if ( s->isSplitter && seen_w )
716 return (QSplitterPHandle*)s->wid;
717 if ( !s->isSplitter && s->wid == w )
719 s = data->list.next();
724 QSplitterPHandle* QSplitterP::getHandleBefore(QWidget* w)
726 QSplitterPLayoutStruct *s = data->list.first();
727 QSplitterPHandle* h = 0;
730 h = (QSplitterPHandle*)s;
731 if ( !s->isSplitter && s->wid == w )
733 s = data->list.next();
737 // VSR 21/11/02 <- ================================
739 QWidget* QSplitterP::widgetBefore( int id ) const
741 QSplitterPLayoutStruct *s = data->list.first();
744 if ( !s->isSplitter ) {
746 if (idAfter(w) == id) return w;
748 s = data->list.next();
753 QWidget* QSplitterP::widgetAfter( int id ) const
755 QSplitterPLayoutStruct *s = data->list.first();
758 if ( !s->isSplitter && seen_s )
760 if ( s->isSplitter && data->list.at() == id )
762 s = data->list.next();
767 void QSplitterP::unCompress(QWidget* w) {
768 compressed_widgets.remove(w);
771 void QSplitterP::compress(QWidget* w)
773 if (!isCompressed(w)) compressed_widgets.append(w);
776 bool QSplitterP::isCompressed(const QWidget* w) const {
777 QWidget* t = (QWidget*)w;
778 if (compressed_widgets.containsRef(t)==0) return false;
783 Moves the left/top edge of the splitter handle with id \a id as
784 close as possible to \a p which is the distance from the left (or
785 top) edge of the widget.
789 void QSplitterP::moveSplitter( QCOORD p, int id )
791 p = adjustPos( p, id );
793 QSplitterPLayoutStruct *s = data->list.at(id);
794 int oldP = orient == Horizontal? s->wid->x() : s->wid->y();
795 bool upLeft = p < oldP;
797 moveAfter( p, id, upLeft );
798 moveBefore( p-1, id-1, upLeft );
804 void QSplitterP::setG( QWidget *w, int p, int s )
806 if ( orient == Horizontal )
807 w->setGeometry( p, contentsRect().y(), s, contentsRect().height() );
809 w->setGeometry( contentsRect().x(), p, contentsRect().width(), s );
814 Places the right/bottom edge of the widget at \a id at position \a pos.
819 void QSplitterP::moveBefore( int pos, int id, bool upLeft )
821 QSplitterPLayoutStruct *s = data->list.at(id);
825 if ( w->isHidden() ) {
826 moveBefore( pos, id-1, upLeft );
827 } else if ( s->isSplitter ) {
830 setG( w, pos-dd+1, dd );
831 moveBefore( pos-dd, id-1, upLeft );
833 moveBefore( pos-dd, id-1, upLeft );
834 setG( w, pos-dd+1, dd );
837 int left = pick( w->pos() );
838 int dd = pos - left + 1;
839 dd = QMAX( pick(minSize(w)), QMIN(dd, pick(maxSize(w))));
840 int newLeft = pos-dd+1;
841 setG( w, newLeft, dd );
842 if ( left != newLeft )
843 moveBefore( newLeft-1, id-1, upLeft );
849 Places the left/top edge of the widget at \a id at position \a pos.
854 void QSplitterP::moveAfter( int pos, int id, bool upLeft )
856 QSplitterPLayoutStruct *s = id < int(data->list.count()) ?
857 data->list.at(id) : 0;
861 if ( w->isHidden() ) {
862 moveAfter( pos, id+1, upLeft );
863 } else if ( pick( w->pos() ) == pos ) {
864 //No need to do anything if it's already there.
866 } else if ( s->isSplitter ) {
870 moveAfter( pos+dd, id+1, upLeft );
872 moveAfter( pos+dd, id+1, upLeft );
876 int right = pick( w->geometry().bottomRight() );
878 int dd = right - pos + 1;
879 dd = QMAX( pick(minSize(w)), QMIN(dd, pick(maxSize(w))));
880 int newRight = pos+dd-1;
882 moveAfter( newRight+1, id+1, upLeft );
888 Returns the valid range of the splitter with id \a id in \a min and \a max.
893 void QSplitterP::getRange( int id, int *min, int *max )
895 int minB = 0; //before
898 int maxA = 0; //after
899 int n = data->list.count();
900 if ( id < 0 || id >= n )
903 for ( i = 0; i < id; i++ ) {
904 QSplitterPLayoutStruct *s = data->list.at(i);
905 if ( s->isSplitter ) {
909 minB += pick( minSize(s->wid) );
910 maxB += pick( maxSize(s->wid) );
913 for ( i = id; i < n; i++ ) {
914 QSplitterPLayoutStruct *s = data->list.at(i);
915 if ( s->isSplitter ) {
919 minA += pick( minSize(s->wid) );
920 maxA += pick( maxSize(s->wid) );
923 QRect r = contentsRect();
925 *min = pick(r.topLeft()) + QMAX( minB, pick(r.size())-maxA );
927 *max = pick(r.topLeft()) + QMIN( maxB, pick(r.size())-minA );
933 Returns the legal position closest to \a p of the splitter with id \a id.
938 int QSplitterP::adjustPos( int p, int id )
942 getRange( id, &min, &max );
943 p = QMAX( min, QMIN( p, max ) );
949 void QSplitterP::doResize()
951 QRect r = contentsRect();
953 int n = data->list.count();
954 QArray<QLayoutStruct> a( n );
955 for ( i = 0; i< n; i++ ) {
957 QSplitterPLayoutStruct *s = data->list.at(i);
958 if ( s->wid->isHidden() ) {
960 a[i].sizeHint = a[i].minimumSize = 0;
961 a[i].maximumSize = 0;
962 } else if ( s->isSplitter ) {
964 a[i].sizeHint = a[i].minimumSize = a[i].maximumSize = s->sizer;
966 } else if ( s->mode == KeepSize ) {
968 a[i].minimumSize = pick( minSize(s->wid) );
969 a[i].sizeHint = s->sizer;
970 a[i].maximumSize = pick( maxSize(s->wid) );
972 } else if ( s->mode == FollowSizeHint ) {
974 a[i].minimumSize = a[i].sizeHint = pick( s->wid->sizeHint() );
975 a[i].maximumSize = pick( maxSize(s->wid) );
977 } else { //proportional
978 a[i].stretch = s->sizer;
979 a[i].maximumSize = pick( maxSize(s->wid) );
980 a[i].sizeHint = a[i].minimumSize = pick( minSize(s->wid) );
985 qGeomCalc( a, 0, n, pick( r.topLeft() ), pick( r.size() ), 0 );
986 for ( i = 0; i< n; i++ ) {
987 QSplitterPLayoutStruct *s = data->list.at(i);
988 if ( orient == Horizontal )
989 s->wid->setGeometry( a[i].pos, r.top(), a[i].size, r.height() );
991 s->wid->setGeometry( r.left(), a[i].pos, r.width(), a[i].size );
997 void QSplitterP::recalc( bool update )
999 int fi = 2*frameWidth();
1002 int maxt = QWIDGETSIZE_MAX;
1004 int n = data->list.count();
1007 The splitter before a hidden widget is always hidden.
1008 The splitter before the first visible widget is hidden.
1009 The splitter before any other visible widget is visible.
1011 for ( int i = 0; i< n; i++ ) {
1012 QSplitterPLayoutStruct *s = data->list.at(i);
1013 if ( !s->isSplitter ) {
1014 QSplitterPLayoutStruct *p = (i > 0) ? p = data->list.at( i-1 ) : 0;
1015 if ( p && p->isSplitter )
1016 if ( first || s->wid->isHidden() )
1017 p->wid->hide(); //may trigger new recalc
1019 p->wid->show(); //may trigger new recalc
1020 if ( !s->wid->isHidden() )
1026 for ( int j = 0; j< n; j++ ) {
1027 QSplitterPLayoutStruct *s = data->list.at(j);
1028 if ( !s->wid->isHidden() ) {
1030 if ( s->isSplitter ) {
1034 QSize minS = minSize(s->wid);
1035 minl += pick( minS );
1036 maxl += pick( maxSize(s->wid) );
1037 mint = QMAX( mint, trans( minS ));
1038 int tm = trans( maxSize(s->wid) );
1040 maxt = QMIN( maxt, tm );
1047 maxl = QMIN( maxl, QWIDGETSIZE_MAX );
1051 if ( orient == Horizontal ) {
1052 setMaximumSize( maxl, maxt );
1053 setMinimumSize( minl, mint );
1055 setMaximumSize( maxt, maxl );
1056 setMinimumSize( mint, minl );
1062 /*! \enum QSplitter::ResizeMode
1064 This enum type describes how QSplitter will resize each of its child widgets. The currently defined values are: <ul>
1066 <li> \c Stretch - the widget will be resized when the splitter
1069 <li> \c KeepSize - QSplitter will try to keep this widget's size
1072 <li> \c FollowSizeHint - QSplitter will resize the widget when its
1080 Sets resize mode of \a w to \a mode.
1085 void QSplitterP::setResizeMode( QWidget *w, ResizeMode mode )
1087 processChildEvents();
1088 QSplitterPLayoutStruct *s = data->list.first();
1090 if ( s->wid == w ) {
1094 s = data->list.next();
1096 s = addWidget( w, TRUE );
1102 Returns TRUE if opaque resize is on, FALSE otherwise.
1104 \sa setOpaqueResize()
1107 bool QSplitterP::opaqueResize() const
1109 return data->opaque;
1114 Sets opaque resize to \a on. Opaque resize is initially turned off.
1119 void QSplitterP::setOpaqueResize( bool on )
1126 Moves \a w to the leftmost/top position.
1129 void QSplitterP::moveToFirst( QWidget *w )
1131 processChildEvents();
1133 QSplitterPLayoutStruct *s = data->list.first();
1135 if ( s->wid == w ) {
1137 QSplitterPLayoutStruct *p = data->list.prev();
1138 if ( p ) { // not already at first place
1139 data->list.take(); //take p
1140 data->list.take(); // take s
1141 data->list.insert( 0, p );
1142 data->list.insert( 0, s );
1146 s = data->list.next();
1149 addWidget( w, TRUE );
1155 Moves \a w to the rightmost/bottom position.
1158 void QSplitterP::moveToLast( QWidget *w )
1160 processChildEvents();
1162 QSplitterPLayoutStruct *s = data->list.first();
1164 if ( s->wid == w ) {
1166 data->list.take(); // take s
1167 QSplitterPLayoutStruct *p = data->list.current();
1168 if ( p ) { // the splitter handle after s
1169 data->list.take(); //take p
1170 data->list.append( p );
1172 data->list.append( s );
1175 s = data->list.next();
1183 void QSplitterP::recalcId()
1185 int n = data->list.count();
1186 for ( int i = 0; i < n; i++ ) {
1187 QSplitterPLayoutStruct *s = data->list.at(i);
1188 if ( s->isSplitter )
1189 ((QSplitterPHandle*)s->wid)->setId(i);
1196 QSize QSplitterP::sizeHint() const
1202 const QObjectList * c = children();
1203 QObjectListIt it( *c );
1206 while( (o=it.current()) != 0 ) {
1208 if ( o->isWidgetType() &&
1209 !((QWidget*)o)->isHidden() ) {
1210 QSize s = ((QWidget*)o)->sizeHint();
1211 if ( s.isValid() ) {
1213 t = QMAX( t, trans( s ) );
1218 return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
1226 QSize QSplitterP::minimumSizeHint() const
1232 const QObjectList * c = children();
1233 QObjectListIt it( *c );
1236 while( (o=it.current()) != 0 ) {
1238 if ( o->isWidgetType() &&
1239 !((QWidget*)o)->isHidden() ) {
1240 QSize s = minSize((QWidget*)o);
1241 if ( s.isValid() ) {
1243 t = QMAX( t, trans( s ) );
1248 return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
1255 QSizePolicy QSplitterP::sizePolicy() const
1257 return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
1262 Calculates stretch parameters from current sizes
1265 void QSplitterP::storeSizes()
1267 QSplitterPLayoutStruct *s = data->list.first();
1269 if ( !s->isSplitter )
1270 s->sizer = pick( s->wid->size() );
1271 s = data->list.next();
1276 #if 0 // ### remove this code ASAP
1279 Hides \a w if \a hide is TRUE, and updates the splitter.
1281 \warning Due to a limitation in the current implementation,
1282 calling QWidget::hide() will not work.
1285 void QSplitterP::setHidden( QWidget *w, bool hide )
1289 } else if ( w == w2 ) {
1293 qWarning( "QSplitterP::setHidden(), unknown widget" );
1306 Returns the hidden status of \a w
1309 bool QSplitterP::isHidden( QWidget *w ) const
1317 qWarning( "QSplitterP::isHidden(), unknown widget" );
1325 Returns a list of the size parameters of all the widgets in this
1328 Giving the values to setSizes() will give a splitter with the same
1332 QValueList<int> QSplitterP::sizes() const
1334 if ( !testWState(WState_Polished) ) {
1335 QWidget* that = (QWidget*) this;
1338 QValueList<int> list;
1339 QSplitterPLayoutStruct *s = data->list.first();
1341 if ( !s->isSplitter )
1342 list.append( s->sizer );
1343 s = data->list.next();
1351 Sets the size parameters to the values given in \a list.
1352 If the splitterP is horizontal, the values set the sizes from
1353 left to right. If it is vertical, the sizes are applied from
1355 Extra values in \a list are ignored.
1357 If \a list contains too few values, the result is undefined
1358 but the program will still be well-behaved.
1361 void QSplitterP::setSizes( QValueList<int> list )
1363 processChildEvents();
1364 QValueList<int>::Iterator it = list.begin();
1365 QSplitterPLayoutStruct *s = data->list.first();
1366 while ( s && it != list.end() ) {
1367 if ( !s->isSplitter ) {
1371 s = data->list.next();
1378 Gets all posted child events, ensuring that the internal state of
1379 the splitter is consistent with the programmer's idea.
1382 void QSplitterP::processChildEvents()
1384 QApplication::sendPostedEvents( this, QEvent::ChildInserted );
1392 void QSplitterP::styleChange( QStyle& old )
1394 #if QT_VERSION < 300
1395 int sw = style().splitterWidth();
1397 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); //qt3.x
1399 QSplitterPLayoutStruct *s = data->list.first();
1401 if ( s->isSplitter )
1403 s = data->list.next();
1406 QFrame::styleChange( old );
1410 bool QSplitterP::isCompressEnabled() const
1412 return compress_flag;
1415 void QSplitterP::setCompressEnabled(bool on) {
1419 void QSplitterP::updateSplitterHandles() const {
1420 QSplitterPLayoutStruct *s = data->list.first();
1422 if ( s->isSplitter )
1423 ((QSplitterPHandle*)s->wid)->updateButtonState();
1424 s = data->list.next();