summaryrefslogtreecommitdiffstats
path: root/kdevdesigner/designer/layout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kdevdesigner/designer/layout.cpp')
-rw-r--r--kdevdesigner/designer/layout.cpp1017
1 files changed, 1017 insertions, 0 deletions
diff --git a/kdevdesigner/designer/layout.cpp b/kdevdesigner/designer/layout.cpp
new file mode 100644
index 00000000..2926b4f6
--- /dev/null
+++ b/kdevdesigner/designer/layout.cpp
@@ -0,0 +1,1017 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include "formwindow.h"
+#include "layout.h"
+#include <widgetdatabase.h>
+#include "widgetfactory.h"
+
+#include <qlayout.h>
+#include <qevent.h>
+#include <qpainter.h>
+#include <qpen.h>
+#include <qbitmap.h>
+#include <qsplitter.h>
+#include <qvaluevector.h>
+#include <qmainwindow.h>
+
+bool operator<( const QGuardedPtr<QWidget> &p1, const QGuardedPtr<QWidget> &p2 )
+{
+ return p1.operator->() < p2.operator->();
+}
+
+/*!
+ \class Layout layout.h
+ \brief Baseclass for layouting widgets in the Designer
+
+ Classes derived from this abstract base class are used for layouting
+ operations in the Designer.
+
+*/
+
+/*! \a p specifies the parent of the layoutBase \a lb. The parent
+ might be changed in setup(). If the layoutBase is a
+ container, the parent and the layoutBase are the same. Also they
+ always have to be a widget known to the designer (e.g. in the case
+ of the tabwidget parent and layoutBase are the tabwidget and not the
+ page which actually gets laid out. For actual usage the correct
+ widget is found later by Layout.)
+ */
+
+Layout::Layout( const QWidgetList &wl, QWidget *p, FormWindow *fw, QWidget *lb, bool doSetup, bool splitter )
+ : widgets( wl ), parent( p ), formWindow( fw ), isBreak( !doSetup ), useSplitter( splitter )
+{
+ widgets.setAutoDelete( FALSE );
+ layoutBase = lb;
+ if ( !doSetup && layoutBase )
+ oldGeometry = layoutBase->geometry();
+}
+
+/*! The widget list we got in the constructor might contain too much
+ widgets (like widgets with different parents, already laid out
+ widgets, etc.). Here we set up the list and so the only the "best"
+ widgets get laid out.
+*/
+
+void Layout::setup()
+{
+ startPoint = QPoint( 32767, 32767 );
+ QValueList<QWidgetList> lists;
+ QWidget *lastParent = 0;
+ QWidgetList *lastList = 0;
+ QWidget *w = 0;
+
+ // Go through all widgets of the list we got. As we can only
+ // layout widgets which have the same parent, we first do some
+ // sorting which means create a list for each parent containing
+ // its child here. After that we keep working on the list of
+ // childs which has the most entries.
+ // Widgets which are already laid out are thrown away here too
+ for ( w = widgets.first(); w; w = widgets.next() ) {
+ if ( w->parentWidget() && WidgetFactory::layoutType( w->parentWidget() ) != WidgetFactory::NoLayout )
+ continue;
+ if ( lastParent != w->parentWidget() ) {
+ lastList = 0;
+ lastParent = w->parentWidget();
+ QValueList<QWidgetList>::Iterator it = lists.begin();
+ for ( ; it != lists.end(); ++it ) {
+ if ( ( *it ).first()->parentWidget() == w->parentWidget() )
+ lastList = &( *it );
+ }
+ if ( !lastList ) {
+ QWidgetList l;
+ l.setAutoDelete( FALSE );
+ lists.append( l );
+ lastList = &lists.last();
+ }
+ }
+ lastList->append( w );
+ }
+
+ // So, now find the list with the most entries
+ lastList = 0;
+ QValueList<QWidgetList>::Iterator it = lists.begin();
+ for ( ; it != lists.end(); ++it ) {
+ if ( !lastList || ( *it ).count() > lastList->count() )
+ lastList = &( *it );
+ }
+
+ // If we found no list (because no widget did fit at all) or the
+ // best list has only one entry and we do not layout a container,
+ // we leave here.
+ if ( !lastList || ( lastList->count() < 2 &&
+ ( !layoutBase ||
+ ( !WidgetDatabase::isContainer( WidgetDatabase::idFromClassName( WidgetFactory::classNameOf( layoutBase ) ) ) &&
+ layoutBase != formWindow->mainContainer() ) )
+ ) ) {
+ widgets.clear();
+ startPoint = QPoint( 0, 0 );
+ return;
+ }
+
+ // Now we have a new and clean widget list, which makes sense
+ // to layout
+ widgets = *lastList;
+ // Also use the only correct parent later, so store it
+ parent = WidgetFactory::widgetOfContainer( widgets.first()->parentWidget() );
+ // Now calculate the position where the layout-meta-widget should
+ // be placed and connect to widgetDestroyed() signals of the
+ // widgets to get informed if one gets deleted to be able to
+ // handle that and do not crash in this case
+ for ( w = widgets.first(); w; w = widgets.next() ) {
+ connect( w, SIGNAL( destroyed() ),
+ this, SLOT( widgetDestroyed() ) );
+ startPoint = QPoint( QMIN( startPoint.x(), w->x() ),
+ QMIN( startPoint.y(), w->y() ) );
+ geometries.insert( w, QRect( w->pos(), w->size() ) );
+ // Change the Z-order, as saving/loading uses the Z-order for
+ // writing/creating widgets and this has to be the same as in
+ // the layout. Else saving + loading will give different results
+ w->raise();
+ }
+}
+
+void Layout::widgetDestroyed()
+{
+ if ( sender() && sender()->isWidgetType() )
+ widgets.removeRef( (QWidget*)sender() );
+}
+
+bool Layout::prepareLayout( bool &needMove, bool &needReparent )
+{
+ if ( !widgets.count() )
+ return FALSE;
+ for ( QWidget *w = widgets.first(); w; w = widgets.next() )
+ w->raise();
+ needMove = !layoutBase;
+ needReparent = needMove || ::qt_cast<QLayoutWidget*>(layoutBase) || ::qt_cast<QSplitter*>(layoutBase);
+ if ( !layoutBase ) {
+ if ( !useSplitter )
+ layoutBase = WidgetFactory::create( WidgetDatabase::idFromClassName( "QLayoutWidget" ),
+ WidgetFactory::containerOfWidget( parent ) );
+ else
+ layoutBase = WidgetFactory::create( WidgetDatabase::idFromClassName( "QSplitter" ),
+ WidgetFactory::containerOfWidget( parent ) );
+ } else {
+ WidgetFactory::deleteLayout( layoutBase );
+ }
+
+ return TRUE;
+}
+
+void Layout::finishLayout( bool needMove, QLayout *layout )
+{
+ if ( needMove )
+ layoutBase->move( startPoint );
+ QRect g( QRect( layoutBase->pos(), layoutBase->size() ) );
+ if ( WidgetFactory::layoutType( layoutBase->parentWidget() ) == WidgetFactory::NoLayout && !isBreak )
+ layoutBase->adjustSize();
+ else if ( isBreak )
+ layoutBase->setGeometry( oldGeometry );
+ oldGeometry = g;
+ layoutBase->show();
+ layout->activate();
+ formWindow->insertWidget( layoutBase );
+ formWindow->selectWidget( layoutBase );
+ QString n = layoutBase->name();
+ if ( n.find( "qt_dead_widget_" ) != -1 ) {
+ n.remove( 0, QString( "qt_dead_widget_" ).length() );
+ layoutBase->setName( n );
+ }
+}
+
+void Layout::undoLayout()
+{
+ if ( !widgets.count() )
+ return;
+ QMap<QGuardedPtr<QWidget>, QRect>::Iterator it = geometries.begin();
+ for ( ; it != geometries.end(); ++it ) {
+ if ( !it.key() )
+ continue;
+ it.key()->reparent( WidgetFactory::containerOfWidget( parent ), 0, ( *it ).topLeft(), it.key()->isVisibleTo( formWindow ) );
+ it.key()->resize( ( *it ).size() );
+ }
+ formWindow->selectWidget( layoutBase, FALSE );
+ WidgetFactory::deleteLayout( layoutBase );
+ if ( parent != layoutBase && !::qt_cast<QMainWindow*>(layoutBase) ) {
+ layoutBase->hide();
+ QString n = layoutBase->name();
+ n.prepend( "qt_dead_widget_" );
+ layoutBase->setName( n );
+ } else {
+ layoutBase->setGeometry( oldGeometry );
+ }
+ if ( widgets.first() )
+ formWindow->selectWidget( widgets.first() );
+ else
+ formWindow->selectWidget( formWindow );
+}
+
+void Layout::breakLayout()
+{
+ QMap<QWidget*, QRect> rects;
+ if ( !widgets.isEmpty() ) {
+ QWidget *w;
+ for ( w = widgets.first(); w; w = widgets.next() )
+ rects.insert( w, w->geometry() );
+ }
+ WidgetFactory::deleteLayout( layoutBase );
+ bool needReparent = qstrcmp( layoutBase->className(), "QLayoutWidget" ) == 0 ||
+ qstrcmp( layoutBase->className(), "QSplitter" ) == 0 ||
+ ( !WidgetDatabase::isContainer( WidgetDatabase::idFromClassName( WidgetFactory::classNameOf( layoutBase ) ) ) &&
+ layoutBase != formWindow->mainContainer() );
+ bool needResize = qstrcmp( layoutBase->className(), "QSplitter" ) == 0;
+ bool add = geometries.isEmpty();
+ for ( QWidget *w = widgets.first(); w; w = widgets.next() ) {
+ if ( needReparent )
+ w->reparent( layoutBase->parentWidget(), 0,
+ layoutBase->pos() + w->pos(), TRUE );
+ if ( needResize ) {
+ QMap<QWidget*, QRect>::Iterator it = rects.find( w );
+ if ( it != rects.end() )
+ w->setGeometry( QRect( layoutBase->pos() + (*it).topLeft(), (*it).size() ) );
+ }
+ if ( add )
+ geometries.insert( w, QRect( w->pos(), w->size() ) );
+ }
+ if ( needReparent ) {
+ layoutBase->hide();
+ parent = layoutBase->parentWidget();
+ QString n = layoutBase->name();
+ n.prepend( "qt_dead_widget_" );
+ layoutBase->setName( n );
+ } else {
+ parent = layoutBase;
+ }
+ if ( widgets.first() && widgets.first()->isVisibleTo( formWindow ) )
+ formWindow->selectWidget( widgets.first() );
+ else
+ formWindow->selectWidget( formWindow );
+}
+
+class HorizontalLayoutList : public QWidgetList
+{
+public:
+ HorizontalLayoutList( const QWidgetList &l )
+ : QWidgetList( l ) {}
+
+ int compareItems( QPtrCollection::Item item1, QPtrCollection::Item item2 ) {
+ QWidget *w1 = (QWidget*)item1;
+ QWidget *w2 = (QWidget*)item2;
+ if ( w1->x() == w2->x() )
+ return 0;
+ if ( w1->x() > w2->x() )
+ return 1;
+ return -1;
+ }
+
+};
+
+HorizontalLayout::HorizontalLayout( const QWidgetList &wl, QWidget *p, FormWindow *fw, QWidget *lb, bool doSetup, bool splitter )
+ : Layout( wl, p, fw, lb, doSetup, splitter )
+{
+ if ( doSetup )
+ setup();
+}
+
+void HorizontalLayout::setup()
+{
+ HorizontalLayoutList l( widgets );
+ l.sort();
+ widgets = l;
+ Layout::setup();
+}
+
+void HorizontalLayout::doLayout()
+{
+ bool needMove, needReparent;
+ if ( !prepareLayout( needMove, needReparent ) )
+ return;
+
+ QHBoxLayout *layout = (QHBoxLayout*)WidgetFactory::createLayout( layoutBase, 0, WidgetFactory::HBox );
+
+ for ( QWidget *w = widgets.first(); w; w = widgets.next() ) {
+ if ( needReparent && w->parent() != layoutBase )
+ w->reparent( layoutBase, 0, QPoint( 0, 0 ), FALSE );
+ if ( !useSplitter ) {
+ if ( qstrcmp( w->className(), "Spacer" ) == 0 )
+ layout->addWidget( w, 0, ( (Spacer*)w )->alignment() );
+ else
+ layout->addWidget( w );
+ if ( ::qt_cast<QLayoutWidget*>(w) )
+ ( (QLayoutWidget*)w )->updateSizePolicy();
+ }
+ w->show();
+ }
+
+ if ( ::qt_cast<QSplitter*>(layoutBase) )
+ ( (QSplitter*)layoutBase )->setOrientation( Qt::Horizontal );
+
+ finishLayout( needMove, layout );
+}
+
+
+
+
+class VerticalLayoutList : public QWidgetList
+{
+public:
+ VerticalLayoutList( const QWidgetList &l )
+ : QWidgetList( l ) {}
+
+ int compareItems( QPtrCollection::Item item1, QPtrCollection::Item item2 ) {
+ QWidget *w1 = (QWidget*)item1;
+ QWidget *w2 = (QWidget*)item2;
+ if ( w1->y() == w2->y() )
+ return 0;
+ if ( w1->y() > w2->y() )
+ return 1;
+ return -1;
+ }
+
+};
+
+VerticalLayout::VerticalLayout( const QWidgetList &wl, QWidget *p, FormWindow *fw, QWidget *lb, bool doSetup, bool splitter )
+ : Layout( wl, p, fw, lb, doSetup, splitter )
+{
+ if ( doSetup )
+ setup();
+}
+
+void VerticalLayout::setup()
+{
+ VerticalLayoutList l( widgets );
+ l.sort();
+ widgets = l;
+ Layout::setup();
+}
+
+void VerticalLayout::doLayout()
+{
+ bool needMove, needReparent;
+ if ( !prepareLayout( needMove, needReparent ) )
+ return;
+
+ QVBoxLayout *layout = (QVBoxLayout*)WidgetFactory::createLayout( layoutBase, 0, WidgetFactory::VBox );
+
+ for ( QWidget *w = widgets.first(); w; w = widgets.next() ) {
+ if ( needReparent && w->parent() != layoutBase )
+ w->reparent( layoutBase, 0, QPoint( 0, 0 ), FALSE );
+ if ( !useSplitter ) {
+ if ( qstrcmp( w->className(), "Spacer" ) == 0 )
+ layout->addWidget( w, 0, ( (Spacer*)w )->alignment() );
+ else
+ layout->addWidget( w );
+ if ( ::qt_cast<QLayoutWidget*>(w) )
+ ( (QLayoutWidget*)w )->updateSizePolicy();
+ }
+ w->show();
+ }
+
+ if ( ::qt_cast<QSplitter*>(layoutBase) )
+ ( (QSplitter*)layoutBase )->setOrientation( Qt::Vertical );
+
+ finishLayout( needMove, layout );
+}
+
+
+
+
+
+class Grid
+{
+public:
+ Grid( int rows, int cols );
+ ~Grid();
+
+ QWidget* cell( int row, int col ) const { return cells[ row * ncols + col]; }
+ void setCell( int row, int col, QWidget* w ) { cells[ row*ncols + col] = w; }
+ void setCells( QRect c, QWidget* w ) {
+ for ( int rows = c.bottom()-c.top(); rows >= 0; rows--)
+ for ( int cols = c.right()-c.left(); cols >= 0; cols--) {
+ setCell(c.top()+rows, c.left()+cols, w);
+ }
+ }
+ int numRows() const { return nrows; }
+ int numCols() const { return ncols; }
+
+ void simplify();
+ bool locateWidget( QWidget* w, int& row, int& col, int& rowspan, int& colspan );
+
+private:
+ void merge();
+ int countRow( int r, int c ) const;
+ int countCol( int r, int c ) const;
+ void setRow( int r, int c, QWidget* w, int count );
+ void setCol( int r, int c, QWidget* w, int count );
+ bool isWidgetStartCol( int c ) const;
+ bool isWidgetEndCol( int c ) const;
+ bool isWidgetStartRow( int r ) const;
+ bool isWidgetEndRow( int r ) const;
+ bool isWidgetTopLeft( int r, int c ) const;
+ void extendLeft();
+ void extendRight();
+ void extendUp();
+ void extendDown();
+ QWidget** cells;
+ bool* cols;
+ bool* rows;
+ int nrows, ncols;
+
+};
+
+Grid::Grid( int r, int c )
+ : nrows( r ), ncols( c )
+{
+ cells = new QWidget*[ r * c ];
+ memset( cells, 0, sizeof( cells ) * r * c );
+ rows = new bool[ r ];
+ cols = new bool[ c ];
+
+}
+
+Grid::~Grid()
+{
+ delete [] cells;
+ delete [] cols;
+ delete [] rows;
+}
+
+int Grid::countRow( int r, int c ) const
+{
+ QWidget* w = cell( r, c );
+ int i = c + 1;
+ while ( i < ncols && cell( r, i ) == w )
+ i++;
+ return i - c;
+}
+
+int Grid::countCol( int r, int c ) const
+{
+ QWidget* w = cell( r, c );
+ int i = r + 1;
+ while ( i < nrows && cell( i, c ) == w )
+ i++;
+ return i - r;
+}
+
+void Grid::setCol( int r, int c, QWidget* w, int count )
+{
+ for (int i = 0; i < count; i++ )
+ setCell( r + i, c, w );
+}
+
+void Grid::setRow( int r, int c, QWidget* w, int count )
+{
+ for (int i = 0; i < count; i++ )
+ setCell( r, c + i, w );
+}
+
+bool Grid::isWidgetStartCol( int c ) const
+{
+ int r;
+ for ( r = 0; r < nrows; r++ ) {
+ if ( cell( r, c ) && ( (c==0) || (cell( r, c) != cell( r, c-1) )) ) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+bool Grid::isWidgetEndCol( int c ) const
+{
+ int r;
+ for ( r = 0; r < nrows; r++ ) {
+ if ( cell( r, c ) && ((c == ncols-1) || (cell( r, c) != cell( r, c+1) )) )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+bool Grid::isWidgetStartRow( int r ) const
+{
+ int c;
+ for ( c = 0; c < ncols; c++ ) {
+ if ( cell( r, c ) && ( (r==0) || (cell( r, c) != cell( r-1, c) )) )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+bool Grid::isWidgetEndRow( int r ) const
+{
+ int c;
+ for ( c = 0; c < ncols; c++ ) {
+ if ( cell( r, c ) && ((r == nrows-1) || (cell( r, c) != cell( r+1, c) )) )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+bool Grid::isWidgetTopLeft( int r, int c ) const
+{
+ QWidget* w = cell( r, c );
+ if ( !w )
+ return FALSE;
+ return ( !r || cell( r-1, c) != w ) && (!c || cell( r, c-1) != w);
+}
+
+void Grid::extendLeft()
+{
+ int r,c,i;
+ for ( c = 1; c < ncols; c++ ) {
+ for ( r = 0; r < nrows; r++ ) {
+ QWidget* w = cell( r, c );
+ if ( !w )
+ continue;
+ int cc = countCol( r, c);
+ int stretch = 0;
+ for ( i = c-1; i >= 0; i-- ) {
+ if ( cell( r, i ) )
+ break;
+ if ( countCol( r, i ) < cc )
+ break;
+ if ( isWidgetEndCol( i ) )
+ break;
+ if ( isWidgetStartCol( i ) ) {
+ stretch = c - i;
+ break;
+ }
+ }
+ if ( stretch ) {
+ for ( i = 0; i < stretch; i++ )
+ setCol( r, c-i-1, w, cc );
+ }
+ }
+ }
+}
+
+
+void Grid::extendRight()
+{
+ int r,c,i;
+ for ( c = ncols - 2; c >= 0; c-- ) {
+ for ( r = 0; r < nrows; r++ ) {
+ QWidget* w = cell( r, c );
+ if ( !w )
+ continue;
+ int cc = countCol( r, c);
+ int stretch = 0;
+ for ( i = c+1; i < ncols; i++ ) {
+ if ( cell( r, i ) )
+ break;
+ if ( countCol( r, i ) < cc )
+ break;
+ if ( isWidgetStartCol( i ) )
+ break;
+ if ( isWidgetEndCol( i ) ) {
+ stretch = i - c;
+ break;
+ }
+ }
+ if ( stretch ) {
+ for ( i = 0; i < stretch; i++ )
+ setCol( r, c+i+1, w, cc );
+ }
+ }
+ }
+
+}
+
+void Grid::extendUp()
+{
+ int r,c,i;
+ for ( r = 1; r < nrows; r++ ) {
+ for ( c = 0; c < ncols; c++ ) {
+ QWidget* w = cell( r, c );
+ if ( !w )
+ continue;
+ int cr = countRow( r, c);
+ int stretch = 0;
+ for ( i = r-1; i >= 0; i-- ) {
+ if ( cell( i, c ) )
+ break;
+ if ( countRow( i, c ) < cr )
+ break;
+ if ( isWidgetEndRow( i ) )
+ break;
+ if ( isWidgetStartRow( i ) ) {
+ stretch = r - i;
+ break;
+ }
+ }
+ if ( stretch ) {
+ for ( i = 0; i < stretch; i++ )
+ setRow( r-i-1, c, w, cr );
+ }
+ }
+ }
+}
+
+void Grid::extendDown()
+{
+ int r,c,i;
+ for ( r = nrows - 2; r >= 0; r-- ) {
+ for ( c = 0; c < ncols; c++ ) {
+ QWidget* w = cell( r, c );
+ if ( !w )
+ continue;
+ int cr = countRow( r, c);
+ int stretch = 0;
+ for ( i = r+1; i < nrows; i++ ) {
+ if ( cell( i, c ) )
+ break;
+ if ( countRow( i, c ) < cr )
+ break;
+ if ( isWidgetStartRow( i ) )
+ break;
+ if ( isWidgetEndRow( i ) ) {
+ stretch = i - r;
+ break;
+ }
+ }
+ if ( stretch ) {
+ for ( i = 0; i < stretch; i++ )
+ setRow( r+i+1, c, w, cr );
+ }
+ }
+ }
+
+}
+
+void Grid::simplify()
+{
+ extendLeft();
+ extendRight();
+ extendUp();
+ extendDown();
+ merge();
+}
+
+
+void Grid::merge()
+{
+ int r,c;
+ for ( c = 0; c < ncols; c++ )
+ cols[c] = FALSE;
+
+ for ( r = 0; r < nrows; r++ )
+ rows[r] = FALSE;
+
+ for ( c = 0; c < ncols; c++ ) {
+ for ( r = 0; r < nrows; r++ ) {
+ if ( isWidgetTopLeft( r, c ) ) {
+ rows[r] = TRUE;
+ cols[c] = TRUE;
+ }
+ }
+ }
+}
+
+bool Grid::locateWidget( QWidget* w, int& row, int& col, int& rowspan, int & colspan )
+{
+ int r,c, r2, c2;
+ for ( c = 0; c < ncols; c++ ) {
+ for ( r = 0; r < nrows; r++ ) {
+ if ( cell( r, c ) == w ) {
+ row = 0;
+ for ( r2 = 1; r2 <= r; r2++ ) {
+ if ( rows[ r2-1 ] )
+ row++;
+ }
+ col = 0;
+ for ( c2 = 1; c2 <= c; c2++ ) {
+ if ( cols[ c2-1 ] )
+ col++;
+ }
+ rowspan = 0;
+ for ( r2 = r ; r2 < nrows && cell( r2, c) == w; r2++ ) {
+ if ( rows[ r2 ] )
+ rowspan++;
+ }
+ colspan = 0;
+ for ( c2 = c; c2 < ncols && cell( r, c2) == w; c2++ ) {
+ if ( cols[ c2] )
+ colspan++;
+ }
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+
+
+GridLayout::GridLayout( const QWidgetList &wl, QWidget *p, FormWindow *fw, QWidget *lb, const QSize &res, bool doSetup )
+ : Layout( wl, p, fw, lb, doSetup ), resolution( res )
+{
+ grid = 0;
+ if ( doSetup )
+ setup();
+}
+
+GridLayout::~GridLayout()
+{
+ delete grid;
+}
+
+void GridLayout::doLayout()
+{
+ bool needMove, needReparent;
+ if ( !prepareLayout( needMove, needReparent ) )
+ return;
+
+ QDesignerGridLayout *layout = (QDesignerGridLayout*)WidgetFactory::createLayout( layoutBase, 0, WidgetFactory::Grid );
+
+ if ( !grid )
+ buildGrid();
+
+ QWidget* w;
+ int r, c, rs, cs;
+ for ( w = widgets.first(); w; w = widgets.next() ) {
+ if ( grid->locateWidget( w, r, c, rs, cs) ) {
+ if ( needReparent && w->parent() != layoutBase )
+ w->reparent( layoutBase, 0, QPoint( 0, 0 ), FALSE );
+ if ( rs * cs == 1 ) {
+ layout->addWidget( w, r, c, ::qt_cast<Spacer*>(w) ? ( (Spacer*)w )->alignment() : 0 );
+ } else {
+ layout->addMultiCellWidget( w, r, r+rs-1, c, c+cs-1, ::qt_cast<Spacer*>(w) ? ( (Spacer*)w )->alignment() : 0 );
+ }
+ if ( ::qt_cast<QLayoutWidget*>(w) )
+ ( (QLayoutWidget*)w )->updateSizePolicy();
+ w->show();
+ } else {
+ qWarning("ooops, widget '%s' does not fit in layout", w->name() );
+ }
+ }
+ finishLayout( needMove, layout );
+}
+
+void GridLayout::setup()
+{
+ Layout::setup();
+ buildGrid();
+}
+
+void GridLayout::buildGrid()
+{
+ if ( !widgets.count() )
+ return;
+
+ // Pixel to cell conversion:
+ // By keeping a list of start'n'stop values (x & y) for each widget,
+ // it is possible to create a very small grid of cells to represent
+ // the widget layout.
+ // -----------------------------------------------------------------
+
+ // We need a list of both start and stop values for x- & y-axis
+ QValueVector<int> x( widgets.count()*2 );
+ QValueVector<int> y( widgets.count()*2 );
+
+ // Using push_back would look nicer, but operator[] is much faster
+ int index = 0;
+ QWidget* w = 0;
+ for ( w = widgets.first(); w; w = widgets.next() ) {
+ QRect widgetPos = w->geometry();
+ x[index] = widgetPos.left();
+ x[index+1] = widgetPos.right();
+ y[index] = widgetPos.top();
+ y[index+1] = widgetPos.bottom();
+ index += 2;
+ }
+
+ qHeapSort(x);
+ qHeapSort(y);
+
+ // Remove duplicate x enteries (Remove next, if equal to current)
+ if ( !x.empty() ) {
+ for (QValueVector<int>::iterator current = x.begin() ;
+ (current != x.end()) && ((current+1) != x.end()) ; )
+ if ( (*current == *(current+1)) )
+ x.erase(current+1);
+ else
+ current++;
+ }
+
+ // Remove duplicate y enteries (Remove next, if equal to current)
+ if ( !y.empty() ) {
+ for (QValueVector<int>::iterator current = y.begin() ;
+ (current != y.end()) && ((current+1) != y.end()) ; )
+ if ( (*current == *(current+1)) )
+ y.erase(current+1);
+ else
+ current++;
+ }
+
+ // Create the smallest grid possible to represent the current layout
+ // Since no widget will be placed in the last row and column, we'll
+ // skip them to increase speed even further
+ delete grid;
+ grid = new Grid( y.size()-1, x.size()-1 );
+
+ // Mark the cells in the grid that contains a widget
+ for ( w = widgets.first(); w; w = widgets.next() ) {
+ QRect c(0,0,0,0), widgetPos = w->geometry();
+ // From left til right (not including)
+ for (uint cw=0; cw<x.size(); cw++) {
+ if ( x[cw] == widgetPos.left() )
+ c.setLeft(cw);
+ if ( x[cw] < widgetPos.right())
+ c.setRight(cw);
+ }
+ // From top til bottom (not including)
+ for (uint ch=0; ch<y.size(); ch++) {
+ if ( y[ch] == widgetPos.top() )
+ c.setTop(ch);
+ if ( y[ch] < widgetPos.bottom() )
+ c.setBottom(ch);
+ }
+ grid->setCells(c, w); // Mark cellblock
+ }
+ grid->simplify();
+}
+
+
+
+
+
+
+
+Spacer::Spacer( QWidget *parent, const char *name )
+ : QWidget( parent, name, WMouseNoMask ),
+ orient( Vertical ), interactive(TRUE), sh( QSize(20,20) )
+{
+ setSizeType( Expanding );
+ setAutoMask( TRUE );
+}
+
+void Spacer::paintEvent( QPaintEvent * )
+{
+ QPainter p( this );
+ p.setPen( Qt::blue );
+
+ if ( orient == Horizontal ) {
+ const int dist = 3;
+ const int amplitude = QMIN( 3, height() / 3 );
+ const int base = height() / 2;
+ int i = 0;
+ p.setPen( white );
+ for ( i = 0; i < width() / 3 +2; ++i )
+ p.drawLine( i * dist, base - amplitude, i * dist + dist / 2, base + amplitude );
+ p.setPen( blue );
+ for ( i = 0; i < width() / 3 +2; ++i )
+ p.drawLine( i * dist + dist / 2, base + amplitude, i * dist + dist, base - amplitude );
+ p.drawLine( 0, 0, 0, height() );
+ p.drawLine( width() - 1, 0, width() - 1, height());
+ } else {
+ const int dist = 3;
+ const int amplitude = QMIN( 3, width() / 3 );
+ const int base = width() / 2;
+ int i = 0;
+ p.setPen( white );
+ for ( i = 0; i < height() / 3 +2; ++i )
+ p.drawLine( base - amplitude, i * dist, base + amplitude,i * dist + dist / 2 );
+ p.setPen( blue );
+ for ( i = 0; i < height() / 3 +2; ++i )
+ p.drawLine( base + amplitude, i * dist + dist / 2, base - amplitude, i * dist + dist );
+ p.drawLine( 0, 0, width(), 0 );
+ p.drawLine( 0, height() - 1, width(), height() - 1 );
+ }
+}
+
+void Spacer::resizeEvent( QResizeEvent* e)
+{
+ QWidget::resizeEvent( e );
+ if ( !parentWidget() || WidgetFactory::layoutType( parentWidget() ) == WidgetFactory::NoLayout )
+ sh = size();
+}
+
+void Spacer::updateMask()
+{
+ QRegion r( rect() );
+ if ( orient == Horizontal ) {
+ const int amplitude = QMIN( 3, height() / 3 );
+ const int base = height() / 2;
+ r = r.subtract( QRect(1, 0, width() - 2, base - amplitude ) );
+ r = r.subtract( QRect(1, base + amplitude, width() - 2, height() - base - amplitude ) );
+ } else {
+ const int amplitude = QMIN( 3, width() / 3 );
+ const int base = width() / 2;
+ r = r.subtract( QRect(0, 1, base - amplitude, height() - 2 ) );
+ r = r.subtract( QRect( base + amplitude, 1, width() - base - amplitude, height() - 2 ) );
+ }
+ setMask( r );
+}
+
+void Spacer::setSizeType( SizeType t )
+{
+ QSizePolicy sizeP;
+ if ( orient == Vertical )
+ sizeP = QSizePolicy( QSizePolicy::Minimum, (QSizePolicy::SizeType)t );
+ else
+ sizeP = QSizePolicy( (QSizePolicy::SizeType)t, QSizePolicy::Minimum );
+ setSizePolicy( sizeP );
+}
+
+
+Spacer::SizeType Spacer::sizeType() const
+{
+ if ( orient == Vertical )
+ return (SizeType)sizePolicy().verData();
+ return (SizeType)sizePolicy().horData();
+}
+
+int Spacer::alignment() const
+{
+ if ( orient == Vertical )
+ return AlignHCenter;
+ return AlignVCenter;
+}
+
+QSize Spacer::minimumSize() const
+{
+ QSize s = QSize( 20,20 );
+ if ( sizeType() == Expanding )
+ if ( orient == Vertical )
+ s.rheight() = 0;
+ else
+ s.rwidth() = 0;
+ return s;
+}
+
+QSize Spacer::sizeHint() const
+{
+ return sh;
+}
+
+
+void Spacer::setSizeHint( const QSize &s )
+{
+ sh = s;
+ if ( !parentWidget() || WidgetFactory::layoutType( parentWidget() ) == WidgetFactory::NoLayout )
+ resize( sizeHint() );
+ updateGeometry();
+}
+
+Qt::Orientation Spacer::orientation() const
+{
+ return orient;
+}
+
+void Spacer::setOrientation( Qt::Orientation o )
+{
+ if ( orient == o )
+ return;
+
+ SizeType st = sizeType();
+ orient = o;
+ setSizeType( st );
+ if ( interactive ) {
+ sh = QSize( sh.height(), sh.width() );
+ if (!parentWidget() || WidgetFactory::layoutType( parentWidget() ) == WidgetFactory::NoLayout )
+ resize( height(), width() );
+ }
+ updateMask();
+ update();
+ updateGeometry();
+}
+
+
+void QDesignerGridLayout::addWidget( QWidget *w, int row, int col, int align_ )
+{
+ items.insert( w, Item(row, col, 1, 1) );
+ QGridLayout::addWidget( w, row, col, align_ );
+}
+
+void QDesignerGridLayout::addMultiCellWidget( QWidget *w, int fromRow, int toRow,
+ int fromCol, int toCol, int align_ )
+{
+ items.insert( w, Item(fromRow, fromCol, toRow - fromRow + 1, toCol - fromCol +1) );
+ QGridLayout::addMultiCellWidget( w, fromRow, toRow, fromCol, toCol, align_ );
+}