summaryrefslogtreecommitdiffstats
path: root/src/widgets/qsplitter.cpp
diff options
context:
space:
mode:
authorTimothy Pearson <[email protected]>2011-11-08 12:31:36 -0600
committerTimothy Pearson <[email protected]>2011-11-08 12:31:36 -0600
commitd796c9dd933ab96ec83b9a634feedd5d32e1ba3f (patch)
tree6e3dcca4f77e20ec8966c666aac7c35bd4704053 /src/widgets/qsplitter.cpp
downloadtqt3-d796c9dd933ab96ec83b9a634feedd5d32e1ba3f.tar.gz
tqt3-d796c9dd933ab96ec83b9a634feedd5d32e1ba3f.zip
Test conversion to TQt3 from Qt3 8c6fc1f8e35fd264dd01c582ca5e7549b32ab731
Diffstat (limited to 'src/widgets/qsplitter.cpp')
-rw-r--r--src/widgets/qsplitter.cpp1368
1 files changed, 1368 insertions, 0 deletions
diff --git a/src/widgets/qsplitter.cpp b/src/widgets/qsplitter.cpp
new file mode 100644
index 000000000..90c21b009
--- /dev/null
+++ b/src/widgets/qsplitter.cpp
@@ -0,0 +1,1368 @@
+/****************************************************************************
+**
+** Implementation of TQSplitter class
+**
+** Created : 980105
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the TQt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at [email protected].
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qsplitter.h"
+#ifndef QT_NO_SPLITTER
+
+#include "qlayout.h"
+#include "../kernel/qlayoutengine_p.h"
+#include "qapplication.h"
+#include "qbitmap.h"
+#include "qdrawutil.h"
+#include "qmemarray.h"
+#include "qobjectlist.h"
+#include "qpainter.h"
+#include "qptrlist.h"
+#include "qstyle.h"
+
+const uint Default = QT_QSPLITTER_DEFAULT;
+
+static int mouseOffset;
+static int opaqueOldPos = -1; // this assumes that there's only one mouse
+
+static TQPoint toggle( TQWidget *w, TQPoint pos )
+{
+ TQSize minS = qSmartMinSize( w );
+ return -pos - TQPoint( minS.width(), minS.height() );
+}
+
+static bool isCollapsed( TQWidget *w )
+{
+ return w->x() < 0 || w->y() < 0;
+}
+
+static TQPoint topLeft( TQWidget *w )
+{
+ if ( isCollapsed(w) ) {
+ return toggle( w, w->pos() );
+ } else {
+ return w->pos();
+ }
+}
+
+static TQPoint bottomRight( TQWidget *w )
+{
+ if ( isCollapsed(w) ) {
+ return toggle( w, w->pos() ) - TQPoint( 1, 1 );
+ } else {
+ return w->geometry().bottomRight();
+ }
+}
+
+TQSplitterHandle::TQSplitterHandle( Orientation o, TQSplitter *parent,
+ const char * name )
+ : TQWidget( parent, name )
+{
+ s = parent;
+ setOrientation( o );
+}
+
+TQSize TQSplitterHandle::sizeHint() const
+{
+ int hw = s->handleWidth();
+ return parentWidget()->style().sizeFromContents( TQStyle::CT_Splitter, s,
+ TQSize(hw, hw) )
+ .expandedTo( TQApplication::globalStrut() );
+}
+
+void TQSplitterHandle::setOrientation( Orientation o )
+{
+ orient = o;
+#ifndef QT_NO_CURSOR
+ setCursor( o == TQSplitter::Horizontal ? splitHCursor : splitVCursor );
+#endif
+}
+
+void TQSplitterHandle::mouseMoveEvent( TQMouseEvent *e )
+{
+ if ( !(e->state()&LeftButton) )
+ return;
+ TQCOORD pos = s->pick( parentWidget()->mapFromGlobal(e->globalPos()) )
+ - mouseOffset;
+ if ( opaque() ) {
+ s->moveSplitter( pos, id() );
+ } else {
+ s->setRubberband( s->adjustPos(pos, id()) );
+ }
+}
+
+void TQSplitterHandle::mousePressEvent( TQMouseEvent *e )
+{
+ if ( e->button() == LeftButton )
+ mouseOffset = s->pick( e->pos() );
+}
+
+void TQSplitterHandle::mouseReleaseEvent( TQMouseEvent *e )
+{
+ if ( !opaque() && e->button() == LeftButton ) {
+ TQCOORD pos = s->pick( parentWidget()->mapFromGlobal(e->globalPos()) )
+ - mouseOffset;
+ s->setRubberband( -1 );
+ s->moveSplitter( pos, id() );
+ }
+}
+
+void TQSplitterHandle::paintEvent( TQPaintEvent * )
+{
+ TQPainter p( this );
+ parentWidget()->style().drawPrimitive( TQStyle::PE_Splitter, &p, rect(),
+ colorGroup(),
+ (orientation() == Horizontal ?
+ TQStyle::Style_Horizontal : 0) );
+}
+
+TQCOORD TQSplitterLayoutStruct::getSizer( Orientation orient )
+{
+ if ( sizer == -1 ) {
+ TQSize s = wid->sizeHint();
+ if ( !s.isValid() || wid->testWState(WState_Resized) )
+ s = wid->size();
+ sizer = ( orient == Horizontal ) ? s.width() : s.height();
+ }
+ return sizer;
+}
+
+/*!
+ \class TQSplitter
+ \brief The TQSplitter class implements a splitter widget.
+
+ \ingroup organizers
+ \mainclass
+
+ A splitter lets the user control the size of child widgets by
+ dragging the boundary between the children. Any number of widgets
+ may be controlled by a single splitter.
+
+ To show a TQListBox, a TQListView and a TQTextEdit side by side:
+ \code
+ TQSplitter *split = new TQSplitter( parent );
+ TQListBox *lb = new TQListBox( split );
+ TQListView *lv = new TQListView( split );
+ TQTextEdit *ed = new TQTextEdit( split );
+ \endcode
+
+ TQSplitter lays out its children horizontally (side by side); you
+ can use setOrientation(TQSplitter::Vertical) to lay out the
+ children vertically.
+
+ By default, all widgets can be as large or as small as the user
+ wishes, between the \l minimumSizeHint() (or \l minimumSize())
+ and \l maximumSize() of the widgets. Use setResizeMode() to
+ specify that a widget should keep its size when the splitter is
+ resized, or set the stretch component of the \l sizePolicy.
+
+ Although TQSplitter normally resizes the children only at the end
+ of a resize operation, if you call setOpaqueResize(TRUE) the
+ widgets are resized as often as possible.
+
+ The initial distribution of size between the widgets is determined
+ by the initial size of each widget. You can also use setSizes() to
+ set the sizes of all the widgets. The function sizes() returns the
+ sizes set by the user.
+
+ If you hide() a child its space will be distributed among the
+ other children. It will be reinstated when you show() it again. It
+ is also possible to reorder the widgets within the splitter using
+ moveToFirst() and moveToLast().
+
+ <img src=qsplitter-m.png> <img src=qsplitter-w.png>
+
+ \sa TQTabBar
+*/
+
+
+/*!
+ Constructs a horizontal splitter with the \a parent and \a name
+ arguments being passed on to the TQFrame constructor.
+*/
+
+TQSplitter::TQSplitter( TQWidget *parent, const char *name )
+ : TQFrame( parent, name, WPaintUnclipped )
+{
+ orient = Horizontal;
+ init();
+}
+
+
+/*!
+ Constructs a splitter with orientation \a o with the \a parent and
+ \a name arguments being passed on to the TQFrame constructor.
+*/
+
+TQSplitter::TQSplitter( Orientation o, TQWidget *parent, const char *name )
+ : TQFrame( parent, name, WPaintUnclipped )
+{
+ orient = o;
+ init();
+}
+
+
+/*!
+ Destroys the splitter and any children.
+*/
+
+TQSplitter::~TQSplitter()
+{
+ delete d;
+}
+
+
+void TQSplitter::init()
+{
+ d = new TQSplitterPrivate;
+ d->list.setAutoDelete( TRUE );
+ TQSizePolicy sp( TQSizePolicy::Expanding, TQSizePolicy::Preferred );
+ if ( orient == Vertical )
+ sp.transpose();
+ setSizePolicy( sp );
+ clearWState( WState_OwnSizePolicy );
+}
+
+/*!
+ \fn void TQSplitter::refresh()
+
+ Updates the splitter's state. You should not need to call this
+ function.
+*/
+
+
+/*!
+ \property TQSplitter::orientation
+ \brief the orientation of the splitter
+
+ By default the orientation is horizontal (the widgets are side by
+ side). The possible orientations are \c Horizontal and
+ \c Vertical.
+*/
+
+void TQSplitter::setOrientation( Orientation o )
+{
+ if ( orient == o )
+ return;
+
+ if ( !testWState( WState_OwnSizePolicy ) ) {
+ TQSizePolicy sp = sizePolicy();
+ sp.transpose();
+ setSizePolicy( sp );
+ clearWState( WState_OwnSizePolicy );
+ }
+
+ orient = o;
+
+ TQSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( s->isHandle )
+ ((TQSplitterHandle*)s->wid)->setOrientation( o );
+ s = d->list.next();
+ }
+ recalc( isVisible() );
+}
+
+/*!
+ \property TQSplitter::childrenCollapsible
+ \brief whether child widgets can be resized down to size 0 by the user
+
+ By default, children are collapsible. It is possible to enable
+ and disable the collapsing of individual children; see
+ setCollapsible().
+*/
+
+void TQSplitter::setChildrenCollapsible( bool collapse )
+{
+ d->childrenCollapsible = collapse;
+}
+
+bool TQSplitter::childrenCollapsible() const
+{
+ return d->childrenCollapsible;
+}
+
+/*!
+ Sets whether the child widget \a w is collapsible to \a collapse.
+
+ By default, children are collapsible, meaning that the user can
+ resize them down to size 0, even if they have a non-zero
+ minimumSize() or minimumSizeHint(). This behavior can be changed
+ on a per-widget basis by calling this function, or globally for
+ all the widgets in the splitter by setting the \l
+ childrenCollapsible property.
+
+ \sa childrenCollapsible
+*/
+
+void TQSplitter::setCollapsible( TQWidget *w, bool collapse )
+{
+ findWidget( w )->collapsible = collapse ? 1 : 0;
+}
+
+/*!
+ \reimp
+*/
+void TQSplitter::resizeEvent( TQResizeEvent * )
+{
+ doResize();
+}
+
+TQSplitterLayoutStruct *TQSplitter::findWidget( TQWidget *w )
+{
+ processChildEvents();
+ TQSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( s->wid == w )
+ return s;
+ s = d->list.next();
+ }
+ return addWidget( w );
+}
+
+/*
+ Inserts the widget \a w at the end (or at the beginning if \a
+ prepend is TRUE) of the splitter's list of widgets.
+
+ It is the responsibility of the caller to make sure that \a w is
+ not already in the splitter and to call recalcId() if needed. (If
+ \a prepend is TRUE, then recalcId() is very probably needed.)
+*/
+
+TQSplitterLayoutStruct *TQSplitter::addWidget( TQWidget *w, bool prepend )
+{
+ TQSplitterLayoutStruct *s;
+ TQSplitterHandle *newHandle = 0;
+ if ( d->list.count() > 0 ) {
+ s = new TQSplitterLayoutStruct;
+ s->resizeMode = KeepSize;
+ TQString tmp = "qt_splithandle_";
+ tmp += w->name();
+ newHandle = new TQSplitterHandle( orientation(), this, tmp );
+ s->wid = newHandle;
+ newHandle->setId( d->list.count() );
+ s->isHandle = TRUE;
+ s->sizer = pick( newHandle->sizeHint() );
+ if ( prepend )
+ d->list.prepend( s );
+ else
+ d->list.append( s );
+ }
+ s = new TQSplitterLayoutStruct;
+ s->resizeMode = DefaultResizeMode;
+ s->wid = w;
+ s->isHandle = FALSE;
+ if ( prepend )
+ d->list.prepend( s );
+ else
+ d->list.append( s );
+ if ( newHandle && isVisible() )
+ newHandle->show(); // will trigger sending of post events
+ return s;
+}
+
+
+/*!
+ Tells the splitter that the child widget described by \a c has
+ been inserted or removed.
+*/
+
+void TQSplitter::childEvent( TQChildEvent *c )
+{
+ if ( c->type() == TQEvent::ChildInserted ) {
+ if ( !c->child()->isWidgetType() )
+ return;
+
+ if ( ((TQWidget*)c->child())->testWFlags( WType_TopLevel ) )
+ return;
+
+ TQSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( s->wid == c->child() )
+ return;
+ s = d->list.next();
+ }
+ addWidget( (TQWidget*)c->child() );
+ recalc( isVisible() );
+ } else if ( c->type() == TQEvent::ChildRemoved ) {
+ TQSplitterLayoutStruct *prev = 0;
+ if ( d->list.count() > 1 )
+ prev = d->list.at( 1 ); // yes, this is correct
+ TQSplitterLayoutStruct *curr = d->list.first();
+ while ( curr ) {
+ if ( curr->wid == c->child() ) {
+ d->list.removeRef( curr );
+ if ( prev && prev->isHandle ) {
+ TQWidget *w = prev->wid;
+ d->list.removeRef( prev );
+ delete w; // will call childEvent()
+ }
+ recalcId();
+ doResize();
+ return;
+ }
+ prev = curr;
+ curr = d->list.next();
+ }
+ }
+}
+
+
+/*!
+ Displays a rubber band at position \a p. If \a p is negative, the
+ rubber band is removed.
+*/
+
+void TQSplitter::setRubberband( int p )
+{
+ TQPainter paint( this );
+ paint.setPen( gray );
+ paint.setBrush( gray );
+ paint.setRasterOp( XorROP );
+ TQRect r = contentsRect();
+ const int rBord = 3; // customizable?
+ int hw = handleWidth();
+ if ( orient == Horizontal ) {
+ if ( opaqueOldPos >= 0 )
+ paint.drawRect( opaqueOldPos + hw / 2 - rBord, r.y(),
+ 2 * rBord, r.height() );
+ if ( p >= 0 )
+ paint.drawRect( p + hw / 2 - rBord, r.y(), 2 * rBord, r.height() );
+ } else {
+ if ( opaqueOldPos >= 0 )
+ paint.drawRect( r.x(), opaqueOldPos + hw / 2 - rBord,
+ r.width(), 2 * rBord );
+ if ( p >= 0 )
+ paint.drawRect( r.x(), p + hw / 2 - rBord, r.width(), 2 * rBord );
+ }
+ opaqueOldPos = p;
+}
+
+
+/*!
+ \reimp
+*/
+
+bool TQSplitter::event( TQEvent *e )
+{
+ switch ( e->type() ) {
+ case TQEvent::Show:
+ if ( !d->firstShow )
+ break;
+ d->firstShow = FALSE;
+ // fall through
+ case TQEvent::LayoutHint:
+ recalc( isVisible() );
+ break;
+ default:
+ ;
+ }
+ return TQWidget::event( e );
+}
+
+
+/*!
+ \obsolete
+
+ Draws the splitter handle in the rectangle described by \a x, \a y,
+ \a w, \a h using painter \a p.
+ \sa TQStyle::drawPrimitive()
+*/
+
+// ### Remove this in 4.0
+
+void TQSplitter::drawSplitter( TQPainter *p,
+ TQCOORD x, TQCOORD y, TQCOORD w, TQCOORD h )
+{
+ style().drawPrimitive(TQStyle::PE_Splitter, p, TQRect(x, y, w, h), colorGroup(),
+ (orientation() == Horizontal ?
+ TQStyle::Style_Horizontal : 0));
+}
+
+
+/*!
+ Returns the ID of the widget to the right of or below the widget
+ \a w, or 0 if there is no such widget (i.e. it is either not in
+ this TQSplitter or \a w is at the end).
+*/
+
+int TQSplitter::idAfter( TQWidget* w ) const
+{
+ TQSplitterLayoutStruct *s = d->list.first();
+ bool seen_w = FALSE;
+ while ( s ) {
+ if ( s->isHandle && seen_w )
+ return d->list.at();
+ if ( !s->isHandle && s->wid == w )
+ seen_w = TRUE;
+ s = d->list.next();
+ }
+ return 0;
+}
+
+
+/*!
+ Moves the left/top edge of the splitter handle with ID \a id as
+ close as possible to position \a p, which is the distance from the
+ left (or top) edge of the widget.
+
+ For Arabic, Hebrew and other right-to-left languages the layout is
+ reversed. \a p is then the distance from the right (or top) edge
+ of the widget.
+
+ \sa idAfter()
+*/
+void TQSplitter::moveSplitter( TQCOORD p, int id )
+{
+ TQSplitterLayoutStruct *s = d->list.at( id );
+ int farMin;
+ int min;
+ int max;
+ int farMax;
+
+ p = adjustPos( p, id, &farMin, &min, &max, &farMax );
+ int oldP = pick( s->wid->pos() );
+
+ if ( TQApplication::reverseLayout() && orient == Horizontal ) {
+ int q = p + s->wid->width();
+ doMove( FALSE, q, id - 1, -1, (q > oldP), (p > max) );
+ doMove( TRUE, q, id, -1, (q > oldP), (p < min) );
+ } else {
+ doMove( FALSE, p, id, +1, (p < oldP), (p > max) );
+ doMove( TRUE, p, id - 1, +1, (p < oldP), (p < min) );
+ }
+ storeSizes();
+}
+
+
+void TQSplitter::setGeo( TQWidget *w, int p, int s, bool splitterMoved )
+{
+ TQRect r;
+ if ( orient == Horizontal ) {
+ if ( TQApplication::reverseLayout() && orient == Horizontal
+ && !splitterMoved )
+ p = contentsRect().width() - p - s;
+ r.setRect( p, contentsRect().y(), s, contentsRect().height() );
+ } else {
+ r.setRect( contentsRect().x(), p, contentsRect().width(), s );
+ }
+
+ /*
+ Hide the child widget, but without calling hide() so that the
+ splitter handle is still shown.
+ */
+ if ( !w->isHidden() && s <= 0 && pick(qSmartMinSize(w)) > 0 )
+ r.moveTopLeft( toggle(w, r.topLeft()) );
+ w->setGeometry( r );
+}
+
+
+void TQSplitter::doMove( bool backwards, int pos, int id, int delta, bool upLeft,
+ bool mayCollapse )
+{
+ if ( id < 0 || id >= (int) d->list.count() )
+ return;
+
+ TQSplitterLayoutStruct *s = d->list.at( id );
+ TQWidget *w = s->wid;
+
+ int nextId = backwards ? id - delta : id + delta;
+
+ if ( w->isHidden() ) {
+ doMove( backwards, pos, nextId, delta, upLeft, TRUE );
+ } else {
+ if ( s->isHandle ) {
+ int dd = s->getSizer( orient );
+ int nextPos = backwards ? pos - dd : pos + dd;
+ int left = backwards ? pos - dd : pos;
+ setGeo( w, left, dd, TRUE );
+ doMove( backwards, nextPos, nextId, delta, upLeft, mayCollapse );
+ } else {
+ int dd = backwards ? pos - pick( topLeft(w) )
+ : pick( bottomRight(w) ) - pos + 1;
+ if ( dd > 0 || (!isCollapsed(w) && !mayCollapse) ) {
+ dd = TQMAX( pick(qSmartMinSize(w)),
+ TQMIN(dd, pick(w->maximumSize())) );
+ } else {
+ dd = 0;
+ }
+ setGeo( w, backwards ? pos - dd : pos, dd, TRUE );
+ doMove( backwards, backwards ? pos - dd : pos + dd, nextId, delta,
+ upLeft, TRUE );
+ }
+ }
+}
+
+int TQSplitter::findWidgetJustBeforeOrJustAfter( int id, int delta, int &collapsibleSize )
+{
+ id += delta;
+ do {
+ TQWidget *w = d->list.at( id )->wid;
+ if ( !w->isHidden() ) {
+ if ( collapsible(d->list.at(id)) )
+ collapsibleSize = pick( qSmartMinSize(w) );
+ return id;
+ }
+ id += 2 * delta; // go to previous (or next) widget, skip the handle
+ } while ( id >= 0 && id < (int)d->list.count() );
+
+ return -1;
+}
+
+void TQSplitter::getRange( int id, int *farMin, int *min, int *max, int *farMax )
+{
+ int n = d->list.count();
+ if ( id <= 0 || id >= n - 1 )
+ return;
+
+ int collapsibleSizeBefore = 0;
+ int idJustBefore = findWidgetJustBeforeOrJustAfter( id, -1, collapsibleSizeBefore );
+
+ int collapsibleSizeAfter = 0;
+ int idJustAfter = findWidgetJustBeforeOrJustAfter( id, +1, collapsibleSizeAfter );
+
+ int minBefore = 0;
+ int minAfter = 0;
+ int maxBefore = 0;
+ int maxAfter = 0;
+ int i;
+
+ for ( i = 0; i < id; i++ )
+ addContribution( i, &minBefore, &maxBefore, i == idJustBefore );
+ for ( i = id; i < n; i++ )
+ addContribution( i, &minAfter, &maxAfter, i == idJustAfter );
+
+ TQRect r = contentsRect();
+ int farMinVal;
+ int minVal;
+ int maxVal;
+ int farMaxVal;
+
+ int smartMinBefore = TQMAX( minBefore, pick(r.size()) - maxAfter );
+ int smartMaxBefore = TQMIN( maxBefore, pick(r.size()) - minAfter );
+
+ if ( orient == Vertical || !TQApplication::reverseLayout() ) {
+ minVal = pick( r.topLeft() ) + smartMinBefore;
+ maxVal = pick( r.topLeft() ) + smartMaxBefore;
+
+ farMinVal = minVal;
+ if ( minBefore - collapsibleSizeBefore >= pick(r.size()) - maxAfter )
+ farMinVal -= collapsibleSizeBefore;
+ farMaxVal = maxVal;
+ if ( pick(r.size()) - (minAfter - collapsibleSizeAfter) <= maxBefore )
+ farMaxVal += collapsibleSizeAfter;
+ } else {
+ int hw = handleWidth();
+ minVal = r.width() - smartMaxBefore - hw;
+ maxVal = r.width() - smartMinBefore - hw;
+
+ farMinVal = minVal;
+ if ( pick(r.size()) - (minAfter - collapsibleSizeAfter) <= maxBefore )
+ farMinVal -= collapsibleSizeAfter;
+ farMaxVal = maxVal;
+ if ( minBefore - collapsibleSizeBefore >= pick(r.size()) - maxAfter )
+ farMaxVal += collapsibleSizeBefore;
+ }
+
+ if ( farMin )
+ *farMin = farMinVal;
+ if ( min )
+ *min = minVal;
+ if ( max )
+ *max = maxVal;
+ if ( farMax )
+ *farMax = farMaxVal;
+}
+
+/*!
+ Returns the valid range of the splitter with ID \a id in \a *min
+ and \a *max if \a min and \a max are not 0.
+
+ \sa idAfter()
+*/
+
+void TQSplitter::getRange( int id, int *min, int *max )
+{
+ getRange( id, min, 0, 0, max );
+}
+
+
+/*!
+ Returns the closest legal position to \a pos of the widget with ID
+ \a id.
+
+ \sa idAfter()
+*/
+
+int TQSplitter::adjustPos( int pos, int id )
+{
+ int x, i, n, u;
+ return adjustPos( pos, id, &u, &n, &i, &x );
+}
+
+int TQSplitter::adjustPos( int pos, int id, int *farMin, int *min, int *max,
+ int *farMax )
+{
+ const int Threshold = 40;
+
+ getRange( id, farMin, min, max, farMax );
+
+ if ( pos >= *min ) {
+ if ( pos <= *max ) {
+ return pos;
+ } else {
+ int delta = pos - *max;
+ int width = *farMax - *max;
+
+ if ( delta > width / 2 && delta >= TQMIN(Threshold, width) ) {
+ return *farMax;
+ } else {
+ return *max;
+ }
+ }
+ } else {
+ int delta = *min - pos;
+ int width = *min - *farMin;
+
+ if ( delta > width / 2 && delta >= TQMIN(Threshold, width) ) {
+ return *farMin;
+ } else {
+ return *min;
+ }
+ }
+}
+
+bool TQSplitter::collapsible( TQSplitterLayoutStruct *s )
+{
+ if (pick(qSmartMinSize(s->wid)) == 1)
+ return FALSE;
+ if ( s->collapsible != Default ) {
+ return (bool) s->collapsible;
+ } else {
+ return d->childrenCollapsible;
+ }
+}
+
+void TQSplitter::doResize()
+{
+ TQRect r = contentsRect();
+ int n = d->list.count();
+ TQMemArray<TQLayoutStruct> a( n );
+
+ for ( int pass = 0; pass < 2; pass++ ) {
+ int numAutoWithStretch = 0;
+ int numAutoWithoutStretch = 0;
+
+ for ( int i = 0; i < n; i++ ) {
+ a[i].init();
+ TQSplitterLayoutStruct *s = d->list.at( i );
+ if ( s->wid->isHidden() || isCollapsed(s->wid) ) {
+ a[i].maximumSize = 0;
+ } else if ( s->isHandle ) {
+ a[i].sizeHint = a[i].minimumSize = a[i].maximumSize = s->sizer;
+ a[i].empty = FALSE;
+ } else {
+ int mode = s->resizeMode;
+ int stretch = 1;
+
+ if ( mode == DefaultResizeMode ) {
+ TQSizePolicy p = s->wid->sizePolicy();
+ int sizePolicyStretch =
+ pick( TQSize(p.horStretch(), p.verStretch()) );
+ if ( sizePolicyStretch > 0 ) {
+ mode = Stretch;
+ stretch = sizePolicyStretch;
+ numAutoWithStretch++;
+ } else {
+ /*
+ Do things differently on the second pass,
+ if there's one. A second pass is necessary
+ if it was found out during the first pass
+ that all DefaultResizeMode items are
+ KeepSize items. In that case, we make them
+ all Stretch items instead, for a more TQt
+ 3.0-compatible behavior.
+ */
+ mode = ( pass == 0 ) ? KeepSize : Stretch;
+ numAutoWithoutStretch++;
+ }
+ }
+
+ a[i].minimumSize = pick( qSmartMinSize(s->wid) );
+ a[i].maximumSize = pick( s->wid->maximumSize() );
+ a[i].empty = FALSE;
+
+ if ( mode == Stretch ) {
+ if ( s->getSizer(orient) > 1 )
+ stretch *= s->getSizer( orient );
+ // TQMIN(): ad hoc work-around for layout engine limitation
+ a[i].stretch = TQMIN( stretch, 8192 );
+ a[i].sizeHint = a[i].minimumSize;
+ } else if ( mode == KeepSize ) {
+ a[i].sizeHint = s->getSizer( orient );
+ } else { // mode == FollowSizeHint
+ a[i].sizeHint = pick( s->wid->sizeHint() );
+ }
+ }
+ }
+
+ // a second pass would yield the same results
+ if ( numAutoWithStretch > 0 || numAutoWithoutStretch == 0 )
+ break;
+ }
+
+ qGeomCalc( a, 0, n, pick( r.topLeft() ), pick( r.size() ), 0 );
+
+ for ( int i = 0; i < n; i++ ) {
+ TQSplitterLayoutStruct *s = d->list.at(i);
+ setGeo( s->wid, a[i].pos, a[i].size, FALSE );
+ }
+}
+
+void TQSplitter::recalc( bool update )
+{
+ int fi = 2 * frameWidth();
+ int maxl = fi;
+ int minl = fi;
+ int maxt = TQWIDGETSIZE_MAX;
+ int mint = fi;
+ int n = d->list.count();
+ bool first = TRUE;
+
+ /*
+ Splitter handles before the first visible widget or right
+ before a hidden widget must be hidden.
+ */
+ for ( int i = 0; i < n; i++ ) {
+ TQSplitterLayoutStruct *s = d->list.at( i );
+ if ( !s->isHandle ) {
+ TQSplitterLayoutStruct *p = 0;
+ if ( i > 0 )
+ p = d->list.at( i - 1 );
+
+ // may trigger new recalc
+ if ( p && p->isHandle )
+ p->wid->setHidden( first || s->wid->isHidden() );
+
+ if ( !s->wid->isHidden() )
+ first = FALSE;
+ }
+ }
+
+ bool empty = TRUE;
+ for ( int j = 0; j < n; j++ ) {
+ TQSplitterLayoutStruct *s = d->list.at( j );
+ if ( !s->wid->isHidden() ) {
+ empty = FALSE;
+ if ( s->isHandle ) {
+ minl += s->getSizer( orient );
+ maxl += s->getSizer( orient );
+ } else {
+ TQSize minS = qSmartMinSize( s->wid );
+ minl += pick( minS );
+ maxl += pick( s->wid->maximumSize() );
+ mint = TQMAX( mint, trans(minS) );
+ int tm = trans( s->wid->maximumSize() );
+ if ( tm > 0 )
+ maxt = TQMIN( maxt, tm );
+ }
+ }
+ }
+ if ( empty ) {
+ if ( ::qt_cast<TQSplitter*>(parentWidget()) ) {
+ // nested splitters; be nice
+ maxl = maxt = 0;
+ } else {
+ // TQSplitter with no children yet
+ maxl = TQWIDGETSIZE_MAX;
+ }
+ } else {
+ maxl = TQMIN( maxl, TQWIDGETSIZE_MAX );
+ }
+ if ( maxt < mint )
+ maxt = mint;
+
+ if ( orient == Horizontal ) {
+ setMaximumSize( maxl, maxt );
+ setMinimumSize( minl, mint );
+ } else {
+ setMaximumSize( maxt, maxl );
+ setMinimumSize( mint, minl );
+ }
+ if ( update )
+ doResize();
+ else
+ d->firstShow = TRUE;
+}
+
+/*!
+ \enum TQSplitter::ResizeMode
+
+ This enum type describes how TQSplitter will resize each of its
+ child widgets.
+
+ \value Auto The widget will be resized according to the stretch
+ factors set in its sizePolicy().
+
+ \value Stretch The widget will be resized when the splitter
+ itself is resized.
+
+ \value KeepSize TQSplitter will try to keep the widget's size
+ unchanged.
+
+ \value FollowSizeHint TQSplitter will resize the widget when the
+ widget's size hint changes.
+*/
+
+/*!
+ Sets resize mode of widget \a w to \a mode. (The default is \c
+ Auto.)
+*/
+
+void TQSplitter::setResizeMode( TQWidget *w, ResizeMode mode )
+{
+ findWidget( w )->resizeMode = mode;
+}
+
+
+/*!
+ \property TQSplitter::opaqueResize
+ \brief whether resizing is opaque
+
+ Opaque resizing is off by default.
+*/
+
+bool TQSplitter::opaqueResize() const
+{
+ return d->opaque;
+}
+
+
+void TQSplitter::setOpaqueResize( bool on )
+{
+ d->opaque = on;
+}
+
+
+/*!
+ Moves widget \a w to the leftmost/top position.
+*/
+
+void TQSplitter::moveToFirst( TQWidget *w )
+{
+ processChildEvents();
+ bool found = FALSE;
+ TQSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( s->wid == w ) {
+ found = TRUE;
+ TQSplitterLayoutStruct *p = d->list.prev();
+ if ( p ) { // not already at first place
+ d->list.take(); // take p
+ d->list.take(); // take s
+ d->list.prepend( p );
+ d->list.prepend( s );
+ }
+ break;
+ }
+ s = d->list.next();
+ }
+ if ( !found )
+ addWidget( w, TRUE );
+ recalcId();
+}
+
+
+/*!
+ Moves widget \a w to the rightmost/bottom position.
+*/
+
+void TQSplitter::moveToLast( TQWidget *w )
+{
+ processChildEvents();
+ bool found = FALSE;
+ TQSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( s->wid == w ) {
+ found = TRUE;
+ d->list.take(); // take s
+ TQSplitterLayoutStruct *p = d->list.current();
+ if ( p ) { // the splitter handle after s
+ d->list.take(); // take p
+ d->list.append( p );
+ }
+ d->list.append( s );
+ break;
+ }
+ s = d->list.next();
+ }
+ if ( !found )
+ addWidget( w );
+ recalcId();
+}
+
+
+void TQSplitter::recalcId()
+{
+ int n = d->list.count();
+ for ( int i = 0; i < n; i++ ) {
+ TQSplitterLayoutStruct *s = d->list.at( i );
+ if ( s->isHandle )
+ ((TQSplitterHandle*)s->wid)->setId( i );
+ }
+}
+
+
+/*!
+ \reimp
+*/
+TQSize TQSplitter::sizeHint() const
+{
+ constPolish();
+ int l = 0;
+ int t = 0;
+ if ( children() ) {
+ const TQObjectList * c = children();
+ TQObjectListIt it( *c );
+ TQObject * o;
+
+ while( (o = it.current()) != 0 ) {
+ ++it;
+ if ( o->isWidgetType() && !((TQWidget*)o)->isHidden() ) {
+ TQSize s = ((TQWidget*)o)->sizeHint();
+ if ( s.isValid() ) {
+ l += pick( s );
+ t = TQMAX( t, trans( s ) );
+ }
+ }
+ }
+ }
+ return orientation() == Horizontal ? TQSize( l, t ) : TQSize( t, l );
+}
+
+
+/*!
+ \reimp
+*/
+
+TQSize TQSplitter::minimumSizeHint() const
+{
+ constPolish();
+ int l = 0;
+ int t = 0;
+ if ( children() ) {
+ const TQObjectList * c = children();
+ TQObjectListIt it( *c );
+ TQObject * o;
+
+ while ( (o = it.current()) != 0 ) {
+ ++it;
+ if ( o->isWidgetType() && !((TQWidget*)o)->isHidden() ) {
+ TQSize s = qSmartMinSize( (TQWidget*)o );
+ if ( s.isValid() ) {
+ l += pick( s );
+ t = TQMAX( t, trans( s ) );
+ }
+ }
+ }
+ }
+ return orientation() == Horizontal ? TQSize( l, t ) : TQSize( t, l );
+}
+
+
+void TQSplitter::storeSizes()
+{
+ TQSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( !s->isHandle )
+ s->sizer = pick( s->wid->size() );
+ s = d->list.next();
+ }
+}
+
+
+void TQSplitter::addContribution( int id, int *min, int *max,
+ bool mayCollapse )
+{
+ TQSplitterLayoutStruct *s = d->list.at( id );
+ if ( !s->wid->isHidden() ) {
+ if ( s->isHandle ) {
+ *min += s->getSizer( orient );
+ *max += s->getSizer( orient );
+ } else {
+ if ( mayCollapse || !isCollapsed(s->wid) )
+ *min += pick( qSmartMinSize(s->wid) );
+ *max += pick( s->wid->maximumSize() );
+ }
+ }
+}
+
+
+/*!
+ Returns a list of the size parameters of all the widgets in this
+ splitter.
+
+ If the splitter's orientation is horizontal, the list is a list of
+ widget widths; if the orientation is vertical, the list is a list
+ of widget heights.
+
+ Giving the values to another splitter's setSizes() function will
+ produce a splitter with the same layout as this one.
+
+ Note that if you want to iterate over the list, you should iterate
+ over a copy, e.g.
+ \code
+ TQValueList<int> list = mySplitter.sizes();
+ TQValueList<int>::Iterator it = list.begin();
+ while( it != list.end() ) {
+ myProcessing( *it );
+ ++it;
+ }
+ \endcode
+
+ \sa setSizes()
+*/
+
+TQValueList<int> TQSplitter::sizes() const
+{
+ if ( !testWState(WState_Polished) )
+ constPolish();
+
+ TQValueList<int> list;
+ TQSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( !s->isHandle )
+ list.append( isCollapsed(s->wid) ? 0 : pick(s->wid->size()));
+ s = d->list.next();
+ }
+ return list;
+}
+
+/*!
+ Sets the size parameters to the values given in the \a list. If
+ the splitter is horizontal, the values set the widths of each
+ widget going from left to right. If the splitter is vertical, the
+ values set the heights of each widget going from top to bottom.
+ Extra values in the \a list are ignored.
+
+ If \a list contains too few values, the result is undefined but
+ the program will still be well-behaved.
+
+ Note that the values in \a list should be the height/width that
+ the widgets should be resized to.
+
+ \sa sizes()
+*/
+
+void TQSplitter::setSizes( TQValueList<int> list )
+{
+ processChildEvents();
+ TQValueList<int>::Iterator it = list.begin();
+ TQSplitterLayoutStruct *s = d->list.first();
+ while ( s && it != list.end() ) {
+ if ( !s->isHandle ) {
+ s->sizer = TQMAX( *it, 0 );
+ int smartMinSize = pick( qSmartMinSize(s->wid) );
+ // Make sure that we reset the collapsed state.
+ if ( s->sizer == 0 ) {
+ if ( collapsible(s) && smartMinSize > 0 ) {
+ s->wid->move( -1, -1 );
+ } else {
+ s->sizer = smartMinSize;
+ s->wid->move( 0, 0 );
+ }
+ } else {
+ if ( s->sizer < smartMinSize )
+ s->sizer = smartMinSize;
+ s->wid->move( 0, 0 );
+ }
+ ++it;
+ }
+ s = d->list.next();
+ }
+ doResize();
+}
+
+/*!
+ \property TQSplitter::handleWidth
+ \brief the width of the splitter handle
+*/
+
+int TQSplitter::handleWidth() const
+{
+ if ( d->handleWidth > 0 ) {
+ return d->handleWidth;
+ } else {
+ return style().pixelMetric( TQStyle::PM_SplitterWidth, this );
+ }
+}
+
+void TQSplitter::setHandleWidth( int width )
+{
+ d->handleWidth = width;
+ updateHandles();
+}
+
+/*!
+ Processes all posted child events, ensuring that the internal state of
+ the splitter is kept consistent.
+*/
+
+void TQSplitter::processChildEvents()
+{
+ TQApplication::sendPostedEvents( this, TQEvent::ChildInserted );
+}
+
+/*!
+ \reimp
+*/
+
+void TQSplitter::styleChange( TQStyle& old )
+{
+ updateHandles();
+ TQFrame::styleChange( old );
+}
+
+void TQSplitter::updateHandles()
+{
+ int hw = handleWidth();
+ TQSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( s->isHandle )
+ s->sizer = hw;
+ s = d->list.next();
+ }
+ recalc( isVisible() );
+}
+
+#ifndef QT_NO_TEXTSTREAM
+/*!
+ \relates TQSplitter
+
+ Writes the sizes and the hidden state of the widgets in the
+ splitter \a splitter to the text stream \a ts.
+
+ \sa operator>>(), sizes(), TQWidget::isHidden()
+*/
+
+TQTextStream& operator<<( TQTextStream& ts, const TQSplitter& splitter )
+{
+ TQSplitterLayoutStruct *s = splitter.d->list.first();
+ bool first = TRUE;
+ ts << "[";
+
+ while ( s != 0 ) {
+ if ( !s->isHandle ) {
+ if ( !first )
+ ts << ",";
+
+ if ( s->wid->isHidden() ) {
+ ts << "H";
+ } else if ( isCollapsed(s->wid) ) {
+ ts << 0;
+ } else {
+ ts << s->getSizer( splitter.orientation() );
+ }
+ first = FALSE;
+ }
+ s = splitter.d->list.next();
+ }
+ ts << "]" << endl;
+ return ts;
+}
+
+/*!
+ \relates TQSplitter
+
+ Reads the sizes and the hidden state of the widgets in the
+ splitter \a splitter from the text stream \a ts. The sizes must
+ have been previously written by the operator<<() function.
+
+ \sa operator<<(), setSizes(), TQWidget::hide()
+*/
+
+TQTextStream& operator>>( TQTextStream& ts, TQSplitter& splitter )
+{
+#undef SKIP_SPACES
+#define SKIP_SPACES() \
+ while ( line[i].isSpace() ) \
+ i++
+
+ splitter.processChildEvents();
+ TQSplitterLayoutStruct *s = splitter.d->list.first();
+ TQString line = ts.readLine();
+ int i = 0;
+
+ SKIP_SPACES();
+ if ( line[i] == '[' ) {
+ i++;
+ SKIP_SPACES();
+ while ( line[i] != ']' ) {
+ while ( s != 0 && s->isHandle )
+ s = splitter.d->list.next();
+ if ( s == 0 )
+ break;
+
+ if ( line[i].upper() == 'H' ) {
+ s->wid->hide();
+ i++;
+ } else {
+ s->wid->show();
+ int dim = 0;
+ while ( line[i].digitValue() >= 0 ) {
+ dim *= 10;
+ dim += line[i].digitValue();
+ i++;
+ }
+ s->sizer = dim;
+ if ( dim == 0 )
+ splitter.setGeo( s->wid, 0, 0, FALSE );
+ }
+ SKIP_SPACES();
+ if ( line[i] == ',' ) {
+ i++;
+ } else {
+ break;
+ }
+ SKIP_SPACES();
+ s = splitter.d->list.next();
+ }
+ }
+ splitter.doResize();
+ return ts;
+}
+#endif
+
+#endif