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