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