Salome HOME
PR: mergefrom_PAL_OCC_21Oct04
[modules/kernel.git] / src / PatchQt / qsplitterP.cxx
1 /////////////////////////////////////////////////////////////////////////////
2 // Module      : PatchQt
3 // File        : qsplitterP.cxx
4 // Description : the patch for Qt's QSplitter class (qsplitter.cpp)
5 /////////////////////////////////////////////////////////////////////////////
6
7 /****************************************************************************
8 ** $Id$
9 **
10 **  Splitter widget
11 **
12 **  Created:  980105
13 **
14 ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
15 **
16 ** This file is part of the widgets module of the Qt GUI Toolkit.
17 **
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.
21 **
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.
26 **
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.
30 **
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.
33 **
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.
38 **
39 ** Contact info@trolltech.com if any conditions of this licensing are
40 ** not clear to you.
41 **
42 **********************************************************************/
43
44 using namespace std;
45 #include "qsplitterP.h"
46 #ifndef QT_NO_COMPLEXWIDGETS
47
48 #include <qglobal.h>
49 #include <qpainter.h>
50 #include <qdrawutil.h>
51 #include <qbitmap.h>
52 #include <private/qlayoutengine_p.h>
53 #if QT_VERSION < 300
54   #include <qlist.h>
55   #include <qarray.h>
56 #else
57   #include <qptrlist.h>  //qt3.x
58   #include <qmemarray.h> //qt3.x
59   #include <qstyle.h> //qt3.x
60 #endif
61
62 #include <qobjectlist.h>
63 #include <qapplication.h> //sendPostedEvents
64
65 #define SPLITTER_ICON_WIDTH 10
66 #define SPLITTER_ICON_HEIGHT 12
67
68 static int mouseOffset;
69 static int opaqueOldPos = -1; //### there's only one mouse, but this is a bit risky
70
71 static const char* splitter_left_xpm[] = {
72   "5 5 2 1 0 0",
73   "     s none          m none  c none",
74   ".    s iconColor1    m black c black",
75   "   ..",
76   " ....",
77   ".....",
78   " ....",
79   "   .."
80 };
81
82 static const char* splitter_right_xpm[] = {
83   "5 5 2 1 0 0",
84   "     s iconColor1    m black c black",
85   ".    s none          m none  c none",
86   "  ...",
87   "    .",
88   "     ",
89   "    .",
90   "  ..."
91 };
92
93 static const char* splitter_up_xpm[] = {
94   "5 5 2 1 0 0",
95   "     s none          m none  c none",
96   ".    s iconColor1    m black c black",
97   "  .  ",
98   " ... ",
99   " ... ",
100   ".....",
101   "....."
102 };
103
104 static const char* splitter_down_xpm[] = {
105   "5 5 2 1 0 0",
106   "     s iconColor1    m black c black",
107   ".    s none          m none  c none",
108   "     ",
109   "     ",
110   ".   .",
111   ".   .",
112   ".. .."
113 };
114
115 QSplitterPHandle::QSplitterPHandle( Qt::Orientation o,
116                                   QSplitterP *parent, const char * name )
117     : QWidget( parent, name )
118 {
119   s = parent;
120   
121   left  = new QPushButton(this);
122   right = new QPushButton(this);
123   unleft  = new QPushButton(this);
124   unright = new QPushButton(this);
125   
126   setOrientation(o);
127   
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 );
133
134 // VSR 21/11/02 -> ================================
135   setMinimumSize( 1, 1 );
136 // VSR 21/11/02 <- ================================
137
138   connect(left,    SIGNAL(clicked()), this, SLOT(onBeforeCompress()));
139   connect(right,   SIGNAL(clicked()), this, SLOT(onAfterCompress()));
140   connect(unleft,  SIGNAL(clicked()), this, SLOT(onBeforeUnCompress()));
141   connect(unright, SIGNAL(clicked()), this, SLOT(onAfterUnCompress()));
142 }
143
144 void QSplitterPHandle::onBeforeCompress() {
145   oldpos = s->pick(pos());
146   int pos = s->pick(s->widgetBefore(id())->pos());
147   s->compress(s->widgetBefore(id()));
148   s->moveSplitter(pos, id());
149   s->updateSplitterHandles();
150 }
151
152 void QSplitterPHandle::onBeforeUnCompress() {
153   s->unCompress(s->widgetBefore(id()));
154   s->moveSplitter(oldpos, id());
155   s->updateSplitterHandles();
156 }
157
158 void QSplitterPHandle::onAfterCompress() {
159   oldpos = s->pick(pos());
160   int pos = s->pick(s->widgetAfter(id())->pos()) + s->pick(s->widgetAfter(id())->size()) - s->pick(size());
161   s->compress(s->widgetAfter(id()));
162   s->moveSplitter(pos, id());
163   s->updateSplitterHandles();
164 }
165
166 void QSplitterPHandle::onAfterUnCompress() {
167   s->unCompress(s->widgetAfter(id()));
168   s->moveSplitter(oldpos, id());
169   s->updateSplitterHandles();
170 }
171
172 // VSR 21/11/02 -> ================================
173 void QSplitterPHandle::compressAfter() 
174 {
175   onAfterCompress();
176 }
177
178 void QSplitterPHandle::unCompressAfter() 
179 {
180   onAfterUnCompress();
181 }
182
183 void QSplitterPHandle::compressBefore() 
184 {
185   onBeforeCompress();
186 }
187
188 void QSplitterPHandle::unCompressBefore() 
189 {
190   onBeforeUnCompress();
191 }
192 // VSR 21/11/02 <- ================================
193
194 QSizePolicy QSplitterPHandle::sizePolicy() const
195 {
196     //### removeme 3.0
197     return QWidget::sizePolicy();
198 }
199
200 QSize QSplitterPHandle::sizeHint() const
201 {
202 #if QT_VERSION < 300
203   int sw = style().splitterWidth();
204   return QSize(sw,sw).expandedTo( QApplication::globalStrut() );
205 #else
206   int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this);
207   return (style().sizeFromContents(QStyle::CT_Splitter, s, QSize(sw, sw)).
208           expandedTo(QApplication::globalStrut()));
209 #endif
210 }
211
212 void QSplitterPHandle::setOrientation( Qt::Orientation o )
213 {
214     orient = o;
215 #ifndef QT_NO_CURSOR
216     if ( o == QSplitterP::Horizontal )
217         setCursor( splitHCursor );
218     else
219         setCursor( splitVCursor );
220 #endif
221
222         QPixmap lp, rp;
223         if ( orient == QSplitterP::Horizontal )
224         {
225                 lp = QPixmap(splitter_left_xpm);
226                 rp = QPixmap(splitter_right_xpm);
227         }
228         else
229         {
230                 lp = QPixmap(splitter_up_xpm);
231                 rp = QPixmap(splitter_down_xpm);
232         }
233         left->setPixmap(lp);
234         right->setPixmap(rp);
235         unleft->setPixmap(rp);
236         unright->setPixmap(lp);
237 }
238
239 void QSplitterPHandle::mouseMoveEvent( QMouseEvent *e )
240 {
241     if ( !(e->state()&LeftButton) )
242         return;
243     QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()))
244                  - mouseOffset;
245     if ( opaque() ) {
246         s->moveSplitter( pos, id() );
247     } else {
248         int min = pos; int max = pos;
249         s->getRange( id(), &min, &max );
250         s->setRubberband( QMAX( min, QMIN(max, pos )));
251     }
252 }
253
254 void QSplitterPHandle::mousePressEvent( QMouseEvent *e )
255 {
256     if ( e->button() == LeftButton )
257         mouseOffset = s->pick(e->pos());
258 }
259
260 void QSplitterPHandle::mouseReleaseEvent( QMouseEvent *e )
261 {
262     if ( !opaque() && e->button() == LeftButton ) {
263         QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()));
264         s->setRubberband( -1 );
265         s->moveSplitter( pos, id() );
266     }
267 }
268
269 void QSplitterPHandle::paintEvent( QPaintEvent * )
270 {
271         updateButtonState();
272     QPainter p( this );
273     s->drawSplitter( &p, 0, 0, width(), height() );
274 }
275
276 void QSplitterPHandle::updateButtonState() {
277         if (!s->isCompressEnabled()) {
278                 left->hide();
279                 right->hide();
280                 unleft->hide();
281                 unright->hide();
282         }
283         else {
284                 if ( orient == QSplitterP::Horizontal )
285                 {
286                         left->setGeometry( QRect( QPoint( (width() - SPLITTER_ICON_WIDTH)/2, 0 ),
287                                                                           QSize ( SPLITTER_ICON_WIDTH, SPLITTER_ICON_HEIGHT ) ) );
288                         right->setGeometry( QRect( QPoint( (width() - SPLITTER_ICON_WIDTH)/2, SPLITTER_ICON_HEIGHT ),
289                                                            QSize ( SPLITTER_ICON_WIDTH, SPLITTER_ICON_HEIGHT ) ) );
290                         unleft->setGeometry( left->geometry() );
291                         unright->setGeometry( right->geometry() );
292                 }
293                 else
294                 {
295                         left->setGeometry( QRect( QPoint( 0, (height() - SPLITTER_ICON_WIDTH)/2 ),
296                                                                           QSize ( SPLITTER_ICON_HEIGHT, SPLITTER_ICON_WIDTH ) ) );
297                         right->setGeometry( QRect( QPoint( SPLITTER_ICON_HEIGHT, (height() - SPLITTER_ICON_WIDTH)/2),
298                                                                            QSize ( SPLITTER_ICON_HEIGHT, SPLITTER_ICON_WIDTH ) ) );
299                         unleft->setGeometry( left->geometry() );
300                         unright->setGeometry( right->geometry() );
301                 }
302                 if ( s->isCompressed( s->widgetBefore( id() ) ) ) {
303                         left->hide();
304                         unleft->show();
305                         right->setEnabled(false);
306                 }
307                 else {
308                         unleft->hide();
309                         left->show();
310                         right->setEnabled(true);
311                 }
312                 if ( s->isCompressed( s->widgetAfter( id() ) ) ) {
313                         right->hide();
314                         unright->show();
315                         left->setEnabled(false);
316                 }
317                 else {
318                         unright->hide();
319                         right->show();
320                         left->setEnabled(true);
321                 }
322         }
323 }
324
325 class QSplitterPLayoutStruct
326 {
327 public:
328     QSplitterP::ResizeMode mode;
329     QCOORD sizer;
330     bool isSplitter;
331     QWidget *wid;
332 };
333
334 class QSplitterPData
335 {
336 public:
337     QSplitterPData() : opaque( FALSE ), firstShow( TRUE ) {}
338
339     QList<QSplitterPLayoutStruct> list;
340     bool opaque;
341     bool firstShow;
342 };
343
344
345 // NOT REVISED
346 /*!
347   \class QSplitter qsplitter.h
348   \brief The QSplitter class implements a splitter widget.
349
350   \ingroup organizers
351
352   A splitter lets the user control the size of child widgets by
353   dragging the boundary between the children. Any number of widgets
354   may be controlled.
355
356   To show a QListBox, a QListView and a QMultiLineEdit side by side:
357
358   \code
359     QSplitter *split = new QSplitter( parent );
360     QListBox *lb = new QListBox( split );
361     QListView *lv = new QListView( split );
362     QMultiLineEdit *ed = new QMultiLineEdit( split );
363   \endcode
364
365   In QSplitter the boundary can be either horizontal or vertical.  The
366   default is horizontal (the children are side by side) and you
367   can use setOrientation( QSplitter::Vertical ) to set it to vertical.
368
369   By default, all widgets can be as large or as small as the user
370   wishes, down to \link QWidget::minimumSizeHint() minimumSizeHint()\endlink.
371   You can naturally use setMinimumSize() and/or
372   setMaximumSize() on the children. Use setResizeMode() to specify that
373   a widget should keep its size when the splitter is resized.
374
375   QSplitter normally resizes the children only at the end of a
376   resize operation, but if you call setOpaqueResize( TRUE ), the
377   widgets are resized as often as possible.
378
379   The initial distribution of size between the widgets is determined
380   by the initial size of each widget. You can also use setSizes() to
381   set the sizes of all the widgets. The function sizes() returns the
382   sizes set by the user.
383
384   If you hide() a child, its space will be distributed among the other
385   children. When you show() it again, it will be reinstated.
386
387   <img src=qsplitter-m.png> <img src=qsplitter-w.png>
388
389   \sa QTabBar
390 */
391
392
393
394 QSize QSplitterP::minSize( const QWidget *w ) const
395 {
396  if ( isCompressed(w) && (data->list.count() > 1 ) ) return QSize(0,0);
397  QSize min = w->minimumSize();
398  QSize s;
399  if ( min.height() <= 0 || min.width() <= 0 )
400     s = w->minimumSizeHint();
401  if ( min.height() > 0 )
402     s.setHeight( min.height() );
403  if ( min.width() > 0 )
404     s.setWidth( min.width() );
405  return s.expandedTo(QSize(0,0));
406 }
407
408 QSize QSplitterP::maxSize( const QWidget* w ) const
409 {
410   if ( isCompressed(w) && (data->list.count() > 1 ) ) return QSize(0,0);
411   else return w->maximumSize();
412 }
413
414 /*!
415   Constructs a horizontal splitter.
416 */
417
418 QSplitterP::QSplitterP( QWidget *parent, const char *name )
419      :QFrame(parent,name,WPaintUnclipped)
420 {
421   orient = Horizontal;
422   init();
423 }
424
425
426 /*!
427   Constructs splitter with orientation \a o.
428 */
429
430 QSplitterP::QSplitterP( Orientation o, QWidget *parent, const char *name )
431     :QFrame(parent,name,WPaintUnclipped)
432 {
433   orient = o;
434   init();
435 }
436
437
438 /*!
439   Destructs the splitter.
440 */
441
442 QSplitterP::~QSplitterP()
443 {
444     data->list.setAutoDelete( TRUE );
445     delete data;
446 }
447
448
449 void QSplitterP::init()
450 {
451     data = new QSplitterPData;
452     if ( orient == Horizontal )
453         setSizePolicy( QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Minimum) );
454     else
455         setSizePolicy( QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Fixed) );
456         compressed_widgets.clear();
457         compress_flag = false;
458 }
459
460
461 /*!
462   \fn void QSplitter::refresh()
463
464   Updates the splitter state. You should not need to call this
465   function during normal use of the splitter.
466 */
467
468
469 /*!  Sets the orientation to \a o.  By default the orientation is
470   horizontal (the widgets are side by side).
471
472   \sa orientation()
473 */
474
475 void QSplitterP::setOrientation( Orientation o )
476 {
477     if ( orient == o )
478         return;
479     orient = o;
480
481     if ( orient == Horizontal )
482         setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) );
483     else
484         setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
485
486     QSplitterPLayoutStruct *s = data->list.first();
487     while ( s ) {
488         if ( s->isSplitter )
489             ((QSplitterPHandle*)s->wid)->setOrientation( o );
490         s = data->list.next();  // ### next at end of loop, no iterator
491     }
492     recalc( isVisible() );
493 }
494
495
496 /*!
497    \fn Orientation QSplitter::orientation() const
498
499    Returns the orientation (\c Horizontal or \c Vertical) of the splitter.
500    \sa setOrientation()
501 */
502
503 /*!
504   \reimp
505 */
506 void QSplitterP::resizeEvent( QResizeEvent * )
507 {
508     doResize();
509 }
510
511
512 /*!
513   Inserts the widget \a w at the end, or at the beginning if \a first is TRUE
514
515   It is the responsibility of the caller of this function to make sure
516   that \a w is not already in the splitter, and to call recalcId if
517   needed.  (If \a first is TRUE, then recalcId is very probably
518   needed.)
519 */
520
521 QSplitterPLayoutStruct *QSplitterP::addWidget( QWidget *w, bool first )
522 {
523     QSplitterPLayoutStruct *s;
524     QSplitterPHandle *newHandle = 0;
525     if ( data->list.count() > 0 ) {
526         s = new QSplitterPLayoutStruct;
527         s->mode = KeepSize;
528         newHandle = new QSplitterPHandle( orientation(), this );
529         s->wid = newHandle;
530         newHandle->setId(data->list.count());
531         s->isSplitter = TRUE;
532         s->sizer = pick( newHandle->sizeHint() );
533         if ( first )
534             data->list.insert( 0, s );
535         else
536             data->list.append( s );
537     }
538     s = new QSplitterPLayoutStruct;
539     s->mode = Stretch;
540     s->wid = w;
541     if ( !testWState( WState_Resized ) && w->sizeHint().isValid() )
542         s->sizer = pick( w->sizeHint() );
543     else
544         s->sizer = pick( w->size() );
545     s->isSplitter = FALSE;
546     if ( first )
547         data->list.insert( 0, s );
548     else
549         data->list.append( s );
550     if ( newHandle && isVisible() )
551         newHandle->show(); //will trigger sending of post events
552     return s;
553 }
554
555
556 /*!
557   Tells the splitter that a child widget has been inserted/removed.
558 */
559
560 void QSplitterP::childEvent( QChildEvent *c )
561 {
562     if ( c->type() == QEvent::ChildInserted ) {
563         if ( !c->child()->isWidgetType() )
564             return;
565
566         if ( ((QWidget*)c->child())->testWFlags( WType_TopLevel ) )
567             return;
568
569         QSplitterPLayoutStruct *s = data->list.first();
570         while ( s ) {
571             if ( s->wid == c->child() )
572                 return;
573             s = data->list.next();
574         }
575         addWidget( (QWidget*)c->child() );
576         recalc( isVisible() );
577
578     } else if ( c->type() == QEvent::ChildRemoved ) {
579         QSplitterPLayoutStruct *p = 0;
580         if ( data->list.count() > 1 )
581             p = data->list.at(1); //remove handle _after_ first widget.
582         QSplitterPLayoutStruct *s = data->list.first();
583         while ( s ) {
584             if ( s->wid == c->child() ) {
585                 data->list.removeRef( s );
586                 delete s;
587                 if ( p && p->isSplitter ) {
588                     data->list.removeRef( p );
589                     delete p->wid; //will call childEvent
590                     delete p;
591                 }
592                 recalcId();
593                 doResize();
594                 return;
595             }
596             p = s;
597             s = data->list.next();
598         }
599     }
600 }
601
602
603 /*!
604   Shows a rubber band at position \a p. If \a p is negative, the
605   rubber band is removed.
606 */
607
608 void QSplitterP::setRubberband( int p )
609 {
610     QPainter paint( this );
611     paint.setPen( gray );
612     paint.setBrush( gray );
613     paint.setRasterOp( XorROP );
614     QRect r = contentsRect();
615     const int rBord = 3; //Themable????
616 #if QT_VERSION < 300
617     const int sw = style().splitterWidth();
618 #else
619     int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); //qt3.x
620 #endif
621     if ( orient == Horizontal ) {
622         if ( opaqueOldPos >= 0 )
623             paint.drawRect( opaqueOldPos + sw/2 - rBord , r.y(),
624                             2*rBord, r.height() );
625         if ( p >= 0 )
626             paint.drawRect( p  + sw/2 - rBord, r.y(), 2*rBord, r.height() );
627     } else {
628         if ( opaqueOldPos >= 0 )
629             paint.drawRect( r.x(), opaqueOldPos + sw/2 - rBord,
630                             r.width(), 2*rBord );
631         if ( p >= 0 )
632             paint.drawRect( r.x(), p + sw/2 - rBord, r.width(), 2*rBord );
633     }
634     opaqueOldPos = p;
635 }
636
637
638 /*! \reimp */
639
640 bool QSplitterP::event( QEvent *e )
641 {
642     if ( e->type() == QEvent::LayoutHint || ( e->type() == QEvent::Show && data->firstShow ) ) {
643         recalc( isVisible() );
644         if ( e->type() == QEvent::Show )
645             data->firstShow = FALSE;
646     }
647     return QWidget::event( e );
648 }
649
650
651 /*!
652   Draws the splitter handle in the rectangle described by \a x, \a y,
653   \a w, \a h using painter \a p.
654   \sa QStyle::drawSplitter
655 */
656
657 void QSplitterP::drawSplitter( QPainter *p,
658                               QCOORD x, QCOORD y, QCOORD w, QCOORD h )
659 {
660 #if QT_VERSION < 300
661     style().drawSplitter( p, x, y, w, h, colorGroup(), orient );
662 #else
663     style().drawPrimitive(QStyle::PE_Splitter, p, QRect(x, y, w, h), colorGroup(),
664                           (orientation() == Qt::Horizontal ?
665                            QStyle::Style_Horizontal : 0));
666 #endif
667 }
668
669
670 /*!
671   Returns the id of the splitter to the right of or below the widget \a w,
672   or 0 if there is no such splitter.
673   (ie. it is either not in this QSplitter, or it is at the end).
674 */
675
676 int QSplitterP::idAfter( QWidget* w ) const
677 {
678     QSplitterPLayoutStruct *s = data->list.first();
679     bool seen_w = FALSE;
680     while ( s ) {
681         if ( s->isSplitter && seen_w )
682             return data->list.at();
683         if ( !s->isSplitter && s->wid == w )
684             seen_w = TRUE;
685         s = data->list.next();
686     }
687     return 0;
688 }
689
690 // VSR 21/11/02 -> ================================
691 QSplitterPHandle* QSplitterP::getHandleAfter(QWidget* w)
692 {
693   QSplitterPLayoutStruct *s = data->list.first();
694   bool seen_w = FALSE;
695   while ( s ) {
696     if ( s->isSplitter && seen_w )
697       return (QSplitterPHandle*)s->wid;
698     if ( !s->isSplitter && s->wid == w )
699       seen_w = TRUE;
700     s = data->list.next();
701   }
702   return 0;
703 }
704
705 QSplitterPHandle* QSplitterP::getHandleBefore(QWidget* w)
706 {
707   QSplitterPLayoutStruct *s = data->list.first();
708   QSplitterPHandle* h = 0;
709   while ( s ) {
710     if ( s->isSplitter )
711       h = (QSplitterPHandle*)s;
712     if ( !s->isSplitter && s->wid == w )
713       return h;
714     s = data->list.next();
715   }
716   return 0;
717 }
718 // VSR 21/11/02 <- ================================
719
720 QWidget* QSplitterP::widgetBefore( int id ) const
721 {
722     QSplitterPLayoutStruct *s = data->list.first();
723         QWidget* w;
724     while ( s ) {
725                 if ( !s->isSplitter ) {
726                         w = s->wid;
727                         if (idAfter(w) == id) return w;
728                 }
729                 s = data->list.next();
730     }
731     return 0;
732 }
733
734 QWidget* QSplitterP::widgetAfter( int id ) const
735 {
736     QSplitterPLayoutStruct *s = data->list.first();
737         bool seen_s = FALSE;
738     while ( s ) {
739         if ( !s->isSplitter && seen_s )
740             return s->wid;
741         if ( s->isSplitter && data->list.at() == id )
742             seen_s = TRUE;
743         s = data->list.next();
744     }
745     return 0;
746 }
747
748 void QSplitterP::unCompress(QWidget* w) {
749    compressed_widgets.remove(w);
750 }
751
752 void QSplitterP::compress(QWidget* w)
753 {
754   if (!isCompressed(w)) compressed_widgets.append(w);
755 }
756
757 bool QSplitterP::isCompressed(const QWidget* w) const {
758   QWidget* t = (QWidget*)w;
759   if (compressed_widgets.containsRef(t)==0) return false;
760   else return true;
761 }
762
763 /*!
764   Moves the left/top edge of the splitter handle with id \a id as
765   close as possible to \a p which is the distance from the left (or
766   top) edge of the widget.
767
768   \sa idAfter()
769 */
770 void QSplitterP::moveSplitter( QCOORD p, int id )
771 {
772     p = adjustPos( p, id );
773
774     QSplitterPLayoutStruct *s = data->list.at(id);
775     int oldP = orient == Horizontal? s->wid->x() : s->wid->y();
776     bool upLeft = p < oldP;
777
778     moveAfter( p, id, upLeft );
779     moveBefore( p-1, id-1, upLeft );
780
781     storeSizes();
782 }
783
784
785 void QSplitterP::setG( QWidget *w, int p, int s )
786 {
787     if ( orient == Horizontal )
788         w->setGeometry( p, contentsRect().y(), s, contentsRect().height() );
789     else
790         w->setGeometry( contentsRect().x(), p, contentsRect().width(), s );
791 }
792
793
794 /*!
795   Places the right/bottom edge of the widget at \a id at position \a pos.
796
797   \sa idAfter()
798 */
799
800 void QSplitterP::moveBefore( int pos, int id, bool upLeft )
801 {
802     QSplitterPLayoutStruct *s = data->list.at(id);
803     if ( !s )
804         return;
805     QWidget *w = s->wid;
806     if ( w->isHidden() ) {
807         moveBefore( pos, id-1, upLeft );
808     } else if ( s->isSplitter ) {
809         int dd = s->sizer;
810         if ( upLeft ) {
811             setG( w, pos-dd+1, dd );
812             moveBefore( pos-dd, id-1, upLeft );
813         } else {
814             moveBefore( pos-dd, id-1, upLeft );
815             setG( w, pos-dd+1, dd );
816         }
817     } else {
818         int left = pick( w->pos() );
819         int dd = pos - left + 1;
820         dd = QMAX( pick(minSize(w)), QMIN(dd, pick(maxSize(w))));
821         int newLeft = pos-dd+1;
822         setG( w, newLeft, dd );
823         if ( left != newLeft )
824             moveBefore( newLeft-1, id-1, upLeft );
825     }
826 }
827
828
829 /*!
830   Places the left/top edge of the widget at \a id at position \a pos.
831
832   \sa idAfter()
833 */
834
835 void QSplitterP::moveAfter( int pos, int id, bool upLeft )
836 {
837     QSplitterPLayoutStruct *s = id < int(data->list.count()) ?
838                                data->list.at(id) : 0;
839     if ( !s )
840         return;
841     QWidget *w = s->wid;
842     if ( w->isHidden() ) {
843         moveAfter( pos, id+1, upLeft );
844     } else if ( pick( w->pos() ) == pos ) {
845         //No need to do anything if it's already there.
846         return;
847     } else if ( s->isSplitter ) {
848         int dd = s->sizer;
849         if ( upLeft ) {
850             setG( w, pos, dd );
851             moveAfter( pos+dd, id+1, upLeft );
852         } else {
853             moveAfter( pos+dd, id+1, upLeft );
854             setG( w, pos, dd );
855         }
856     } else {
857         int right = pick( w->geometry().bottomRight() );
858
859         int dd = right - pos + 1;
860         dd = QMAX( pick(minSize(w)), QMIN(dd, pick(maxSize(w))));
861         int newRight = pos+dd-1;
862         setG( w, pos, dd );
863         moveAfter( newRight+1, id+1, upLeft );
864     }
865 }
866
867
868 /*!
869   Returns the valid range of the splitter with id \a id in \a min and \a max.
870
871   \sa idAfter()
872 */
873
874 void QSplitterP::getRange( int id, int *min, int *max )
875 {
876     int minB = 0;       //before
877     int maxB = 0;
878     int minA = 0;
879     int maxA = 0;       //after
880     int n = data->list.count();
881     if ( id < 0 || id >= n )
882         return;
883     int i;
884     for ( i = 0; i < id; i++ ) {
885         QSplitterPLayoutStruct *s = data->list.at(i);
886         if ( s->isSplitter ) {
887             minB += s->sizer;
888             maxB += s->sizer;
889         } else {
890             minB += pick( minSize(s->wid) );
891             maxB += pick( maxSize(s->wid) );
892         }
893     }
894     for ( i = id; i < n; i++ ) {
895         QSplitterPLayoutStruct *s = data->list.at(i);
896         if ( s->isSplitter ) {
897             minA += s->sizer;
898             maxA += s->sizer;
899         } else {
900             minA += pick( minSize(s->wid) );
901             maxA += pick( maxSize(s->wid) );
902         }
903     }
904     QRect r = contentsRect();
905     if ( min )
906         *min = pick(r.topLeft()) + QMAX( minB, pick(r.size())-maxA );
907     if ( max )
908         *max = pick(r.topLeft()) + QMIN( maxB, pick(r.size())-minA );
909
910 }
911
912
913 /*!
914   Returns the legal position closest to \a p of the splitter with id \a id.
915
916   \sa idAfter()
917 */
918
919 int QSplitterP::adjustPos( int p, int id )
920 {
921     int min = 0;
922     int max = 0;
923     getRange( id, &min, &max );
924     p = QMAX( min, QMIN( p, max ) );
925
926     return p;
927 }
928
929
930 void QSplitterP::doResize()
931 {
932     QRect r = contentsRect();
933     int i;
934     int n = data->list.count();
935     QArray<QLayoutStruct> a( n );
936     for ( i = 0; i< n; i++ ) {
937         a[i].init();
938         QSplitterPLayoutStruct *s = data->list.at(i);
939         if ( s->wid->isHidden() ) {
940             a[i].stretch = 0;
941             a[i].sizeHint = a[i].minimumSize = 0;
942             a[i].maximumSize = 0;
943         } else if ( s->isSplitter ) {
944             a[i].stretch = 0;
945             a[i].sizeHint = a[i].minimumSize = a[i].maximumSize = s->sizer;
946             a[i].empty = FALSE;
947         } else if ( s->mode == KeepSize ) {
948             a[i].stretch = 0;
949             a[i].minimumSize = pick( minSize(s->wid) );
950             a[i].sizeHint = s->sizer;
951             a[i].maximumSize = pick( maxSize(s->wid) );
952             a[i].empty = FALSE;
953         } else if ( s->mode == FollowSizeHint ) {
954             a[i].stretch = 0;
955             a[i].minimumSize = a[i].sizeHint = pick( s->wid->sizeHint() );
956             a[i].maximumSize = pick( maxSize(s->wid) );
957             a[i].empty = FALSE;
958         } else { //proportional
959             a[i].stretch = s->sizer;
960             a[i].maximumSize = pick( maxSize(s->wid) );
961             a[i].sizeHint = a[i].minimumSize = pick( minSize(s->wid) );
962             a[i].empty = FALSE;
963         }
964     }
965
966     qGeomCalc( a, 0, n, pick( r.topLeft() ), pick( r.size() ), 0 );
967     for ( i = 0; i< n; i++ ) {
968         QSplitterPLayoutStruct *s = data->list.at(i);
969         if ( orient == Horizontal )
970             s->wid->setGeometry( a[i].pos, r.top(), a[i].size, r.height() );
971         else
972             s->wid->setGeometry( r.left(), a[i].pos, r.width(), a[i].size );
973     }
974
975 }
976
977
978 void QSplitterP::recalc( bool update )
979 {
980     int fi = 2*frameWidth();
981     int maxl = fi;
982     int minl = fi;
983     int maxt = QWIDGETSIZE_MAX;
984     int mint = fi;
985     int n = data->list.count();
986     bool first = TRUE;
987     /*
988       The splitter before a hidden widget is always hidden.
989       The splitter before the first visible widget is hidden.
990       The splitter before any other visible widget is visible.
991     */
992     for ( int i = 0; i< n; i++ ) {
993         QSplitterPLayoutStruct *s = data->list.at(i);
994         if ( !s->isSplitter ) {
995             QSplitterPLayoutStruct *p = (i > 0) ? p = data->list.at( i-1 ) : 0;
996             if ( p && p->isSplitter )
997                 if ( first || s->wid->isHidden() )
998                     p->wid->hide(); //may trigger new recalc
999                 else
1000                     p->wid->show(); //may trigger new recalc
1001             if ( !s->wid->isHidden() )
1002                 first = FALSE;
1003         }
1004     }
1005
1006     bool empty=TRUE;
1007     for ( int j = 0; j< n; j++ ) {
1008         QSplitterPLayoutStruct *s = data->list.at(j);
1009         if ( !s->wid->isHidden() ) {
1010             empty = FALSE;
1011             if ( s->isSplitter ) {
1012                 minl += s->sizer;
1013                 maxl += s->sizer;
1014             } else {
1015                 QSize minS = minSize(s->wid);
1016                 minl += pick( minS );
1017                 maxl += pick( maxSize(s->wid) );
1018                 mint = QMAX( mint, trans( minS ));
1019                 int tm = trans( maxSize(s->wid) );
1020                 if ( tm > 0 )
1021                     maxt = QMIN( maxt, tm );
1022             }
1023         }
1024     }
1025     if ( empty )
1026         maxl = maxt = 0;
1027     else
1028         maxl = QMIN( maxl, QWIDGETSIZE_MAX );
1029     if ( maxt < mint )
1030         maxt = mint;
1031
1032     if ( orient == Horizontal ) {
1033         setMaximumSize( maxl, maxt );
1034         setMinimumSize( minl, mint );
1035     } else {
1036         setMaximumSize( maxt, maxl );
1037         setMinimumSize( mint, minl );
1038     }
1039     if ( update )
1040         doResize();
1041 }
1042
1043 /*! \enum QSplitter::ResizeMode
1044
1045   This enum type describes how QSplitter will resize each of its child widgets.  The currently defined values are: <ul>
1046
1047   <li> \c Stretch - the widget will be resized when the splitter
1048   itself is resized.
1049
1050   <li> \c KeepSize - QSplitter will try to keep this widget's size
1051   unchanged.
1052
1053   <li> \c FollowSizeHint - QSplitter will resize the widget when its
1054   size hint changes.
1055
1056   </ul>
1057
1058 */
1059
1060 /*!
1061   Sets resize mode of \a w to \a mode.
1062
1063   \sa ResizeMode
1064 */
1065
1066 void QSplitterP::setResizeMode( QWidget *w, ResizeMode mode )
1067 {
1068     processChildEvents();
1069     QSplitterPLayoutStruct *s = data->list.first();
1070     while ( s ) {
1071         if ( s->wid == w  ) {
1072             s->mode = mode;
1073             return;
1074         }
1075         s = data->list.next();
1076     }
1077     s = addWidget( w, TRUE );
1078     s->mode = mode;
1079 }
1080
1081
1082 /*!
1083   Returns TRUE if opaque resize is on, FALSE otherwise.
1084
1085   \sa setOpaqueResize()
1086 */
1087
1088 bool QSplitterP::opaqueResize() const
1089 {
1090     return data->opaque;
1091 }
1092
1093
1094 /*!
1095   Sets opaque resize to \a on. Opaque resize is initially turned off.
1096
1097   \sa opaqueResize()
1098 */
1099
1100 void QSplitterP::setOpaqueResize( bool on )
1101 {
1102     data->opaque = on;
1103 }
1104
1105
1106 /*!
1107   Moves \a w to the leftmost/top position.
1108 */
1109
1110 void QSplitterP::moveToFirst( QWidget *w )
1111 {
1112     processChildEvents();
1113     bool found = FALSE;
1114     QSplitterPLayoutStruct *s = data->list.first();
1115     while ( s ) {
1116         if ( s->wid == w  ) {
1117             found = TRUE;
1118             QSplitterPLayoutStruct *p = data->list.prev();
1119             if ( p ) { // not already at first place
1120                 data->list.take(); //take p
1121                 data->list.take(); // take s
1122                 data->list.insert( 0, p );
1123                 data->list.insert( 0, s );
1124             }
1125             break;
1126         }
1127         s = data->list.next();
1128     }
1129      if ( !found )
1130         addWidget( w, TRUE );
1131      recalcId();
1132 }
1133
1134
1135 /*!
1136   Moves \a w to the rightmost/bottom position.
1137 */
1138
1139 void QSplitterP::moveToLast( QWidget *w )
1140 {
1141     processChildEvents();
1142     bool found = FALSE;
1143     QSplitterPLayoutStruct *s = data->list.first();
1144     while ( s ) {
1145         if ( s->wid == w  ) {
1146             found = TRUE;
1147             data->list.take(); // take s
1148             QSplitterPLayoutStruct *p = data->list.current();
1149             if ( p ) { // the splitter handle after s
1150                 data->list.take(); //take p
1151                 data->list.append( p );
1152             }
1153             data->list.append( s );
1154             break;
1155         }
1156         s = data->list.next();
1157     }
1158      if ( !found )
1159         addWidget( w);
1160      recalcId();
1161 }
1162
1163
1164 void QSplitterP::recalcId()
1165 {
1166     int n = data->list.count();
1167     for ( int i = 0; i < n; i++ ) {
1168         QSplitterPLayoutStruct *s = data->list.at(i);
1169         if ( s->isSplitter )
1170             ((QSplitterPHandle*)s->wid)->setId(i);
1171     }
1172 }
1173
1174
1175 /*!\reimp
1176 */
1177 QSize QSplitterP::sizeHint() const
1178 {
1179     constPolish();
1180     int l = 0;
1181     int t = 0;
1182     if ( children() ) {
1183         const QObjectList * c = children();
1184         QObjectListIt it( *c );
1185         QObject * o;
1186
1187         while( (o=it.current()) != 0 ) {
1188             ++it;
1189             if ( o->isWidgetType() &&
1190                  !((QWidget*)o)->isHidden() ) {
1191                 QSize s = ((QWidget*)o)->sizeHint();
1192                 if ( s.isValid() ) {
1193                     l += pick( s );
1194                     t = QMAX( t, trans( s ) );
1195                 }
1196             }
1197         }
1198     }
1199     return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
1200 }
1201
1202
1203 /*!
1204 \reimp
1205 */
1206
1207 QSize QSplitterP::minimumSizeHint() const
1208 {
1209     constPolish();
1210     int l = 0;
1211     int t = 0;
1212     if ( children() ) {
1213         const QObjectList * c = children();
1214         QObjectListIt it( *c );
1215         QObject * o;
1216
1217         while( (o=it.current()) != 0 ) {
1218             ++it;
1219             if ( o->isWidgetType() &&
1220                  !((QWidget*)o)->isHidden() ) {
1221                 QSize s = minSize((QWidget*)o);
1222                 if ( s.isValid() ) {
1223                     l += pick( s );
1224                     t = QMAX( t, trans( s ) );
1225                 }
1226             }
1227         }
1228     }
1229     return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
1230 }
1231
1232
1233
1234 /*!\reimp
1235 */
1236 QSizePolicy QSplitterP::sizePolicy() const
1237 {
1238     return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
1239 }
1240
1241
1242 /*!
1243   Calculates stretch parameters from current sizes
1244 */
1245
1246 void QSplitterP::storeSizes()
1247 {
1248     QSplitterPLayoutStruct *s = data->list.first();
1249     while ( s ) {
1250         if ( !s->isSplitter )
1251             s->sizer = pick( s->wid->size() );
1252         s = data->list.next();
1253     }
1254 }
1255
1256
1257 #if 0 // ### remove this code ASAP
1258
1259 /*!
1260   Hides \a w if \a hide is TRUE, and updates the splitter.
1261
1262   \warning Due to a limitation in the current implementation,
1263   calling QWidget::hide() will not work.
1264 */
1265
1266 void QSplitterP::setHidden( QWidget *w, bool hide )
1267 {
1268     if ( w == w1 ) {
1269         w1show = !hide;
1270     } else if ( w == w2 ) {
1271         w2show = !hide;
1272     } else {
1273 #ifdef CHECK_RANGE
1274         qWarning( "QSplitterP::setHidden(), unknown widget" );
1275 #endif
1276         return;
1277     }
1278     if ( hide )
1279         w->hide();
1280     else
1281         w->show();
1282     recalc( TRUE );
1283 }
1284
1285
1286 /*!
1287   Returns the hidden status of \a w
1288 */
1289
1290 bool QSplitterP::isHidden( QWidget *w ) const
1291 {
1292     if ( w == w1 )
1293         return !w1show;
1294      else if ( w == w2 )
1295         return !w2show;
1296 #ifdef CHECK_RANGE
1297     else
1298         qWarning( "QSplitterP::isHidden(), unknown widget" );
1299 #endif
1300     return FALSE;
1301 }
1302 #endif
1303
1304
1305 /*!
1306   Returns a list of the size parameters of all the widgets in this
1307   splitter.
1308
1309   Giving the values to setSizes() will give a splitter with the same
1310   layout as this one.
1311 */
1312
1313 QValueList<int> QSplitterP::sizes() const
1314 {
1315     if ( !testWState(WState_Polished) ) {
1316         QWidget* that = (QWidget*) this;
1317         that->polish();
1318     }
1319     QValueList<int> list;
1320     QSplitterPLayoutStruct *s = data->list.first();
1321     while ( s ) {
1322         if ( !s->isSplitter )
1323             list.append( s->sizer );
1324         s = data->list.next();
1325     }
1326     return list;
1327 }
1328
1329
1330
1331 /*!
1332   Sets the size parameters to the values given in \a list.
1333   If the splitterP is horizontal, the values set the sizes from
1334   left to right. If it is vertical, the sizes are applied from
1335   top to bottom.
1336   Extra values in \a list are ignored.
1337
1338   If \a list contains too few values, the result is undefined
1339   but the program will still be well-behaved.
1340 */
1341
1342 void QSplitterP::setSizes( QValueList<int> list )
1343 {
1344     processChildEvents();
1345     QValueList<int>::Iterator it = list.begin();
1346     QSplitterPLayoutStruct *s = data->list.first();
1347     while ( s && it != list.end() ) {
1348         if ( !s->isSplitter ) {
1349             s->sizer = *it;
1350             ++it;
1351         }
1352         s = data->list.next();
1353     }
1354     doResize();
1355 }
1356
1357
1358 /*!
1359   Gets all posted child events, ensuring that the internal state of
1360   the splitter is consistent with the programmer's idea.
1361 */
1362
1363 void QSplitterP::processChildEvents()
1364 {
1365     QApplication::sendPostedEvents( this, QEvent::ChildInserted );
1366 }
1367
1368
1369 /*!
1370   \reimp
1371 */
1372
1373 void QSplitterP::styleChange( QStyle& old )
1374 {
1375 #if QT_VERSION < 300
1376     int sw = style().splitterWidth();
1377 #else
1378     int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); //qt3.x
1379 #endif
1380     QSplitterPLayoutStruct *s = data->list.first();
1381     while ( s ) {
1382         if ( s->isSplitter )
1383             s->sizer = sw;
1384         s = data->list.next();
1385     }
1386     doResize();
1387     QFrame::styleChange( old );
1388 }
1389 #endif
1390
1391 bool QSplitterP::isCompressEnabled() const
1392
1393         return compress_flag; 
1394 }
1395
1396 void QSplitterP::setCompressEnabled(bool on) {
1397         compress_flag = on;
1398 }
1399
1400 void QSplitterP::updateSplitterHandles() const {
1401     QSplitterPLayoutStruct *s = data->list.first();
1402     while ( s ) {
1403         if ( s->isSplitter )
1404             ((QSplitterPHandle*)s->wid)->updateButtonState();
1405         s = data->list.next();
1406     }
1407 }