You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1018 lines
27 KiB
1018 lines
27 KiB
/**********************************************************************
|
|
** Copyright (C) 2000 Trolltech AS. All rights reserved.
|
|
**
|
|
** This file is part of TQt 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 TQt Enterprise Edition or TQt Professional Edition
|
|
** 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
|
|
** 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 TQt Commercial License Agreements.
|
|
**
|
|
** Contact info@trolltech.com if any conditions of this licensing are
|
|
** not clear to you.
|
|
**
|
|
**********************************************************************/
|
|
|
|
#include "formwindow.h"
|
|
#include "tqlayout.h"
|
|
#include <widgetdatabase.h>
|
|
#include "widgetfactory.h"
|
|
|
|
#include <tqlayout.h>
|
|
#include <tqevent.h>
|
|
#include <tqpainter.h>
|
|
#include <tqpen.h>
|
|
#include <tqbitmap.h>
|
|
#include <tqsplitter.h>
|
|
#include <tqvaluevector.h>
|
|
#include <tqmainwindow.h>
|
|
|
|
bool operator<( const TQGuardedPtr<TQWidget> &p1, const TQGuardedPtr<TQWidget> &p2 )
|
|
{
|
|
return p1.operator->() < p2.operator->();
|
|
}
|
|
|
|
/*!
|
|
\class Layout tqlayout.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 TQWidgetList &wl, TQWidget *p, FormWindow *fw, TQWidget *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 = TQPoint( 32767, 32767 );
|
|
TQValueList<TQWidgetList> lists;
|
|
TQWidget *lastParent = 0;
|
|
TQWidgetList *lastList = 0;
|
|
TQWidget *w = 0;
|
|
|
|
// Go through all widgets of the list we got. As we can only
|
|
// tqlayout 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();
|
|
TQValueList<TQWidgetList>::Iterator it = lists.begin();
|
|
for ( ; it != lists.end(); ++it ) {
|
|
if ( ( *it ).first()->parentWidget() == w->parentWidget() )
|
|
lastList = &( *it );
|
|
}
|
|
if ( !lastList ) {
|
|
TQWidgetList l;
|
|
l.setAutoDelete( FALSE );
|
|
lists.append( l );
|
|
lastList = &lists.last();
|
|
}
|
|
}
|
|
lastList->append( w );
|
|
}
|
|
|
|
// So, now find the list with the most entries
|
|
lastList = 0;
|
|
TQValueList<TQWidgetList>::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 tqlayout a container,
|
|
// we leave here.
|
|
if ( !lastList || ( lastList->count() < 2 &&
|
|
( !layoutBase ||
|
|
( !WidgetDatabase::isContainer( WidgetDatabase::idFromClassName( WidgetFactory::classNameOf( TQT_TQOBJECT(layoutBase) ) ) ) &&
|
|
layoutBase != formWindow->mainContainer() ) )
|
|
) ) {
|
|
widgets.clear();
|
|
startPoint = TQPoint( 0, 0 );
|
|
return;
|
|
}
|
|
|
|
// Now we have a new and clean widget list, which makes sense
|
|
// to tqlayout
|
|
widgets = *lastList;
|
|
// Also use the only correct parent later, so store it
|
|
parent = WidgetFactory::widgetOfContainer( widgets.first()->parentWidget() );
|
|
// Now calculate the position where the tqlayout-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, TQT_SIGNAL( destroyed() ),
|
|
this, TQT_SLOT( widgetDestroyed() ) );
|
|
startPoint = TQPoint( TQMIN( startPoint.x(), w->x() ),
|
|
TQMIN( startPoint.y(), w->y() ) );
|
|
geometries.insert( w, TQRect( 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 tqlayout. Else saving + loading will give different results
|
|
w->raise();
|
|
}
|
|
}
|
|
|
|
void Layout::widgetDestroyed()
|
|
{
|
|
if ( sender() && sender()->isWidgetType() )
|
|
widgets.removeRef( (TQWidget*)sender() );
|
|
}
|
|
|
|
bool Layout::prepareLayout( bool &needMove, bool &needReparent )
|
|
{
|
|
if ( !widgets.count() )
|
|
return FALSE;
|
|
for ( TQWidget *w = widgets.first(); w; w = widgets.next() )
|
|
w->raise();
|
|
needMove = !layoutBase;
|
|
needReparent = needMove || ::tqqt_cast<TQLayoutWidget*>(layoutBase) || ::tqqt_cast<TQSplitter*>(layoutBase);
|
|
if ( !layoutBase ) {
|
|
if ( !useSplitter )
|
|
layoutBase = WidgetFactory::create( WidgetDatabase::idFromClassName( TQLAYOUTWIDGET_OBJECT_NAME_STRING ),
|
|
WidgetFactory::containerOfWidget( parent ) );
|
|
else
|
|
layoutBase = WidgetFactory::create( WidgetDatabase::idFromClassName( TQSPLITTER_OBJECT_NAME_STRING ),
|
|
WidgetFactory::containerOfWidget( parent ) );
|
|
} else {
|
|
WidgetFactory::deleteLayout( layoutBase );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void Layout::finishLayout( bool needMove, TQLayout *tqlayout )
|
|
{
|
|
if ( needMove )
|
|
layoutBase->move( startPoint );
|
|
TQRect g( TQRect( layoutBase->pos(), layoutBase->size() ) );
|
|
if ( WidgetFactory::layoutType( layoutBase->parentWidget() ) == WidgetFactory::NoLayout && !isBreak )
|
|
layoutBase->adjustSize();
|
|
else if ( isBreak )
|
|
layoutBase->setGeometry( oldGeometry );
|
|
oldGeometry = g;
|
|
layoutBase->show();
|
|
tqlayout->activate();
|
|
formWindow->insertWidget( layoutBase );
|
|
formWindow->selectWidget( TQT_TQOBJECT(layoutBase) );
|
|
TQString n = layoutBase->name();
|
|
if ( n.find( "qt_dead_widget_" ) != -1 ) {
|
|
n.remove( 0, TQString( "qt_dead_widget_" ).length() );
|
|
layoutBase->setName( n );
|
|
}
|
|
}
|
|
|
|
void Layout::undoLayout()
|
|
{
|
|
if ( !widgets.count() )
|
|
return;
|
|
TQMap<TQGuardedPtr<TQWidget>, TQRect>::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( TQT_TQOBJECT(layoutBase), FALSE );
|
|
WidgetFactory::deleteLayout( layoutBase );
|
|
if ( parent != layoutBase && !::tqqt_cast<TQMainWindow*>(layoutBase) ) {
|
|
layoutBase->hide();
|
|
TQString n = layoutBase->name();
|
|
n.prepend( "qt_dead_widget_" );
|
|
layoutBase->setName( n );
|
|
} else {
|
|
layoutBase->setGeometry( oldGeometry );
|
|
}
|
|
if ( widgets.first() )
|
|
formWindow->selectWidget( TQT_TQOBJECT(widgets.first()) );
|
|
else
|
|
formWindow->selectWidget( TQT_TQOBJECT(formWindow) );
|
|
}
|
|
|
|
void Layout::breakLayout()
|
|
{
|
|
TQMap<TQWidget*, TQRect> rects;
|
|
if ( !widgets.isEmpty() ) {
|
|
TQWidget *w;
|
|
for ( w = widgets.first(); w; w = widgets.next() )
|
|
rects.insert( w, w->geometry() );
|
|
}
|
|
WidgetFactory::deleteLayout( layoutBase );
|
|
bool needReparent = qstrcmp( layoutBase->className(), TQLAYOUTWIDGET_OBJECT_NAME_STRING ) == 0 ||
|
|
qstrcmp( layoutBase->className(), TQSPLITTER_OBJECT_NAME_STRING ) == 0 ||
|
|
( !WidgetDatabase::isContainer( WidgetDatabase::idFromClassName( WidgetFactory::classNameOf( TQT_TQOBJECT(layoutBase) ) ) ) &&
|
|
layoutBase != formWindow->mainContainer() );
|
|
bool needResize = qstrcmp( layoutBase->className(), TQSPLITTER_OBJECT_NAME_STRING ) == 0;
|
|
bool add = geometries.isEmpty();
|
|
for ( TQWidget *w = widgets.first(); w; w = widgets.next() ) {
|
|
if ( needReparent )
|
|
w->reparent( layoutBase->parentWidget(), 0,
|
|
layoutBase->pos() + w->pos(), TRUE );
|
|
if ( needResize ) {
|
|
TQMap<TQWidget*, TQRect>::Iterator it = rects.find( w );
|
|
if ( it != rects.end() )
|
|
w->setGeometry( TQRect( layoutBase->pos() + (*it).topLeft(), (*it).size() ) );
|
|
}
|
|
if ( add )
|
|
geometries.insert( w, TQRect( w->pos(), w->size() ) );
|
|
}
|
|
if ( needReparent ) {
|
|
layoutBase->hide();
|
|
parent = layoutBase->parentWidget();
|
|
TQString n = layoutBase->name();
|
|
n.prepend( "qt_dead_widget_" );
|
|
layoutBase->setName( n );
|
|
} else {
|
|
parent = layoutBase;
|
|
}
|
|
if ( widgets.first() && widgets.first()->isVisibleTo( formWindow ) )
|
|
formWindow->selectWidget( TQT_TQOBJECT(widgets.first()) );
|
|
else
|
|
formWindow->selectWidget( TQT_TQOBJECT(formWindow) );
|
|
}
|
|
|
|
class HorizontalLayoutList : public TQWidgetList
|
|
{
|
|
public:
|
|
HorizontalLayoutList( const TQWidgetList &l )
|
|
: TQWidgetList( l ) {}
|
|
|
|
int compareItems( TQPtrCollection::Item item1, TQPtrCollection::Item item2 ) {
|
|
TQWidget *w1 = (TQWidget*)item1;
|
|
TQWidget *w2 = (TQWidget*)item2;
|
|
if ( w1->x() == w2->x() )
|
|
return 0;
|
|
if ( w1->x() > w2->x() )
|
|
return 1;
|
|
return -1;
|
|
}
|
|
|
|
};
|
|
|
|
HorizontalLayout::HorizontalLayout( const TQWidgetList &wl, TQWidget *p, FormWindow *fw, TQWidget *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;
|
|
|
|
TQHBoxLayout *tqlayout = (TQHBoxLayout*)WidgetFactory::createLayout( layoutBase, 0, WidgetFactory::HBox );
|
|
|
|
for ( TQWidget *w = widgets.first(); w; w = widgets.next() ) {
|
|
if ( needReparent && TQT_BASE_OBJECT(w->parent()) != TQT_BASE_OBJECT(layoutBase) )
|
|
w->reparent( layoutBase, 0, TQPoint( 0, 0 ), FALSE );
|
|
if ( !useSplitter ) {
|
|
if ( qstrcmp( w->className(), "Spacer" ) == 0 )
|
|
tqlayout->addWidget( w, 0, ( (Spacer*)w )->alignment() );
|
|
else
|
|
tqlayout->addWidget( w );
|
|
if ( ::tqqt_cast<TQLayoutWidget*>(w) )
|
|
( (TQLayoutWidget*)w )->updateSizePolicy();
|
|
}
|
|
w->show();
|
|
}
|
|
|
|
if ( ::tqqt_cast<TQSplitter*>(layoutBase) )
|
|
( (TQSplitter*)layoutBase )->setOrientation( Qt::Horizontal );
|
|
|
|
finishLayout( needMove, tqlayout );
|
|
}
|
|
|
|
|
|
|
|
|
|
class VerticalLayoutList : public TQWidgetList
|
|
{
|
|
public:
|
|
VerticalLayoutList( const TQWidgetList &l )
|
|
: TQWidgetList( l ) {}
|
|
|
|
int compareItems( TQPtrCollection::Item item1, TQPtrCollection::Item item2 ) {
|
|
TQWidget *w1 = (TQWidget*)item1;
|
|
TQWidget *w2 = (TQWidget*)item2;
|
|
if ( w1->y() == w2->y() )
|
|
return 0;
|
|
if ( w1->y() > w2->y() )
|
|
return 1;
|
|
return -1;
|
|
}
|
|
|
|
};
|
|
|
|
VerticalLayout::VerticalLayout( const TQWidgetList &wl, TQWidget *p, FormWindow *fw, TQWidget *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;
|
|
|
|
TQVBoxLayout *tqlayout = (TQVBoxLayout*)WidgetFactory::createLayout( layoutBase, 0, WidgetFactory::VBox );
|
|
|
|
for ( TQWidget *w = widgets.first(); w; w = widgets.next() ) {
|
|
if ( needReparent && TQT_BASE_OBJECT(w->parent()) != TQT_BASE_OBJECT(layoutBase) )
|
|
w->reparent( layoutBase, 0, TQPoint( 0, 0 ), FALSE );
|
|
if ( !useSplitter ) {
|
|
if ( qstrcmp( w->className(), "Spacer" ) == 0 )
|
|
tqlayout->addWidget( w, 0, ( (Spacer*)w )->alignment() );
|
|
else
|
|
tqlayout->addWidget( w );
|
|
if ( ::tqqt_cast<TQLayoutWidget*>(w) )
|
|
( (TQLayoutWidget*)w )->updateSizePolicy();
|
|
}
|
|
w->show();
|
|
}
|
|
|
|
if ( ::tqqt_cast<TQSplitter*>(layoutBase) )
|
|
( (TQSplitter*)layoutBase )->setOrientation( Qt::Vertical );
|
|
|
|
finishLayout( needMove, tqlayout );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class Grid
|
|
{
|
|
public:
|
|
Grid( int rows, int cols );
|
|
~Grid();
|
|
|
|
TQWidget* cell( int row, int col ) const { return cells[ row * ncols + col]; }
|
|
void setCell( int row, int col, TQWidget* w ) { cells[ row*ncols + col] = w; }
|
|
void setCells( TQRect c, TQWidget* 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( TQWidget* 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, TQWidget* w, int count );
|
|
void setCol( int r, int c, TQWidget* 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();
|
|
TQWidget** cells;
|
|
bool* cols;
|
|
bool* rows;
|
|
int nrows, ncols;
|
|
|
|
};
|
|
|
|
Grid::Grid( int r, int c )
|
|
: nrows( r ), ncols( c )
|
|
{
|
|
cells = new TQWidget*[ 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
|
|
{
|
|
TQWidget* 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
|
|
{
|
|
TQWidget* 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, TQWidget* w, int count )
|
|
{
|
|
for (int i = 0; i < count; i++ )
|
|
setCell( r + i, c, w );
|
|
}
|
|
|
|
void Grid::setRow( int r, int c, TQWidget* 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
|
|
{
|
|
TQWidget* 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++ ) {
|
|
TQWidget* 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++ ) {
|
|
TQWidget* 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++ ) {
|
|
TQWidget* 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++ ) {
|
|
TQWidget* 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( TQWidget* 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 TQWidgetList &wl, TQWidget *p, FormWindow *fw, TQWidget *lb, const TQSize &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 *tqlayout = (QDesignerGridLayout*)WidgetFactory::createLayout( layoutBase, 0, WidgetFactory::Grid );
|
|
|
|
if ( !grid )
|
|
buildGrid();
|
|
|
|
TQWidget* w;
|
|
int r, c, rs, cs;
|
|
for ( w = widgets.first(); w; w = widgets.next() ) {
|
|
if ( grid->locateWidget( w, r, c, rs, cs) ) {
|
|
if ( needReparent && TQT_BASE_OBJECT(w->parent()) != TQT_BASE_OBJECT(layoutBase) )
|
|
w->reparent( layoutBase, 0, TQPoint( 0, 0 ), FALSE );
|
|
if ( rs * cs == 1 ) {
|
|
tqlayout->addWidget( w, r, c, ::tqqt_cast<Spacer*>(w) ? ( (Spacer*)w )->alignment() : 0 );
|
|
} else {
|
|
tqlayout->addMultiCellWidget( w, r, r+rs-1, c, c+cs-1, ::tqqt_cast<Spacer*>(w) ? ( (Spacer*)w )->alignment() : 0 );
|
|
}
|
|
if ( ::tqqt_cast<TQLayoutWidget*>(w) )
|
|
( (TQLayoutWidget*)w )->updateSizePolicy();
|
|
w->show();
|
|
} else {
|
|
qWarning("ooops, widget '%s' does not fit in tqlayout", w->name() );
|
|
}
|
|
}
|
|
finishLayout( needMove, tqlayout );
|
|
}
|
|
|
|
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 tqlayout.
|
|
// -----------------------------------------------------------------
|
|
|
|
// We need a list of both start and stop values for x- & y-axis
|
|
TQValueVector<int> x( widgets.count()*2 );
|
|
TQValueVector<int> y( widgets.count()*2 );
|
|
|
|
// Using push_back would look nicer, but operator[] is much faster
|
|
int index = 0;
|
|
TQWidget* w = 0;
|
|
for ( w = widgets.first(); w; w = widgets.next() ) {
|
|
TQRect 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 (TQValueVector<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 (TQValueVector<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 tqlayout
|
|
// 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() ) {
|
|
TQRect 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( TQWidget *parent, const char *name )
|
|
: TQWidget( parent, name, WMouseNoMask ),
|
|
orient(Qt::Vertical ), interactive(TRUE), sh( TQSize(20,20) )
|
|
{
|
|
setSizeType( Expanding );
|
|
setAutoMask( TRUE );
|
|
}
|
|
|
|
void Spacer::paintEvent( TQPaintEvent * )
|
|
{
|
|
TQPainter p( this );
|
|
p.setPen( TQt::blue );
|
|
|
|
if ( orient ==Qt::Horizontal ) {
|
|
const int dist = 3;
|
|
const int amplitude = TQMIN( 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 = TQMIN( 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( TQResizeEvent* e)
|
|
{
|
|
TQWidget::resizeEvent( e );
|
|
if ( !parentWidget() || WidgetFactory::layoutType( parentWidget() ) == WidgetFactory::NoLayout )
|
|
sh = size();
|
|
}
|
|
|
|
void Spacer::updateMask()
|
|
{
|
|
TQRegion r( rect() );
|
|
if ( orient ==Qt::Horizontal ) {
|
|
const int amplitude = TQMIN( 3, height() / 3 );
|
|
const int base = height() / 2;
|
|
r = r.subtract( TQRect(1, 0, width() - 2, base - amplitude ) );
|
|
r = r.subtract( TQRect(1, base + amplitude, width() - 2, height() - base - amplitude ) );
|
|
} else {
|
|
const int amplitude = TQMIN( 3, width() / 3 );
|
|
const int base = width() / 2;
|
|
r = r.subtract( TQRect(0, 1, base - amplitude, height() - 2 ) );
|
|
r = r.subtract( TQRect( base + amplitude, 1, width() - base - amplitude, height() - 2 ) );
|
|
}
|
|
setMask( r );
|
|
}
|
|
|
|
void Spacer::setSizeType( SizeType t )
|
|
{
|
|
TQSizePolicy sizeP;
|
|
if ( orient ==Qt::Vertical )
|
|
sizeP = TQSizePolicy( TQSizePolicy::Minimum, (TQSizePolicy::SizeType)t );
|
|
else
|
|
sizeP = TQSizePolicy( (TQSizePolicy::SizeType)t, TQSizePolicy::Minimum );
|
|
setSizePolicy( sizeP );
|
|
}
|
|
|
|
|
|
Spacer::SizeType Spacer::sizeType() const
|
|
{
|
|
if ( orient ==Qt::Vertical )
|
|
return (SizeType)sizePolicy().verData();
|
|
return (SizeType)sizePolicy().horData();
|
|
}
|
|
|
|
int Spacer::alignment() const
|
|
{
|
|
if ( orient ==Qt::Vertical )
|
|
return AlignHCenter;
|
|
return AlignVCenter;
|
|
}
|
|
|
|
TQSize Spacer::minimumSize() const
|
|
{
|
|
TQSize s = TQSize( 20,20 );
|
|
if ( sizeType() == Expanding )
|
|
if ( orient ==Qt::Vertical )
|
|
s.rheight() = 0;
|
|
else
|
|
s.rwidth() = 0;
|
|
return s;
|
|
}
|
|
|
|
TQSize Spacer::sizeHint() const
|
|
{
|
|
return sh;
|
|
}
|
|
|
|
|
|
void Spacer::setSizeHint( const TQSize &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 = TQSize( sh.height(), sh.width() );
|
|
if (!parentWidget() || WidgetFactory::layoutType( parentWidget() ) == WidgetFactory::NoLayout )
|
|
resize( height(), width() );
|
|
}
|
|
updateMask();
|
|
update();
|
|
updateGeometry();
|
|
}
|
|
|
|
|
|
void QDesignerGridLayout::addWidget( TQWidget *w, int row, int col, int align_ )
|
|
{
|
|
items.insert( w, Item(row, col, 1, 1) );
|
|
TQGridLayout::addWidget( w, row, col, align_ );
|
|
}
|
|
|
|
void QDesignerGridLayout::addMultiCellWidget( TQWidget *w, int fromRow, int toRow,
|
|
int fromCol, int toCol, int align_ )
|
|
{
|
|
items.insert( w, Item(fromRow, fromCol, toRow - fromRow + 1, toCol - fromCol +1) );
|
|
TQGridLayout::addMultiCellWidget( w, fromRow, toRow, fromCol, toCol, align_ );
|
|
}
|