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.
431 lines
13 KiB
431 lines
13 KiB
/***************************************************************************
|
|
* Copyright (C) 2004 by Hans Oischinger *
|
|
* hans.oischinger@kde-mail.net *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
***************************************************************************/
|
|
#include "komposelayout.h"
|
|
|
|
#include "komposewidget.h"
|
|
#include "komposeviewmanager.h"
|
|
#include "komposetaskmanager.h"
|
|
#include "komposefullscreenwidget.h"
|
|
|
|
#include <math.h>
|
|
|
|
#include <twin.h>
|
|
#include <kdebug.h>
|
|
|
|
|
|
KomposeLayout::KomposeLayout( KomposeWidget *parent, int type, int dist, const char *name )
|
|
: TQObject(parent, name),
|
|
spacing(dist),
|
|
widgetsChanged(false),
|
|
currentRows(0),
|
|
currentColumns(0),
|
|
parentWidget(parent)
|
|
{
|
|
setType( type );
|
|
currentSize = TQSize( 1, 1 );
|
|
}
|
|
|
|
KomposeLayout::~KomposeLayout()
|
|
{}
|
|
|
|
void KomposeLayout::setType( int t )
|
|
{
|
|
/*
|
|
if ( t == TLAYOUT_TASKCONTAINERS &&
|
|
!KomposeSettings::instance()->getDynamicVirtDeskLayout() )
|
|
t = TLAYOUT_GENERIC;
|
|
|
|
layoutType = t;
|
|
*/
|
|
layoutType = TLAYOUT_GENERIC;
|
|
}
|
|
|
|
|
|
void KomposeLayout::add( KomposeWidget *w )
|
|
{
|
|
//kdDebug() << "KomposeLayout::add()@%s - Added widget to layout", parent()->className());
|
|
//kdDebug() << "KomposeLayout::add() - Added widget to layout");
|
|
list.append( w );
|
|
widgetsChanged = true;
|
|
}
|
|
|
|
void KomposeLayout::remove( KomposeWidget *w )
|
|
{
|
|
list.remove( w );
|
|
widgetsChanged = true;
|
|
}
|
|
|
|
|
|
void KomposeLayout::arrangeLayout()
|
|
{
|
|
//kdDebug() << "KomposeLayout::arrangeLayout()");
|
|
rearrangeContents();
|
|
}
|
|
|
|
void KomposeLayout::rearrangeContents()
|
|
{
|
|
// Check or empty list
|
|
if (list.count() == 0)
|
|
{
|
|
kdDebug() << "KomposeLayout::rearrangeContents() - empty list... skipping!" << endl;
|
|
return;
|
|
}
|
|
|
|
|
|
// Check for layout Type and do the work
|
|
if (layoutType==TLAYOUT_TASKCONTAINERS)
|
|
{
|
|
filledContainers.clear();
|
|
emptyContainers.clear();
|
|
|
|
// Check for empty containers
|
|
TQPtrListIterator<KomposeWidget> it( list );
|
|
KomposeWidget *task;
|
|
while ( (task = it.current()) != 0 )
|
|
{
|
|
++it;
|
|
KomposeTaskContainerWidget *containerTask = dynamic_cast<KomposeTaskContainerWidget*>(task);
|
|
|
|
if ( containerTask->getNumofChilds() > 0 )
|
|
{
|
|
filledContainers.append( containerTask );
|
|
}
|
|
else
|
|
{
|
|
emptyContainers.append( containerTask );
|
|
}
|
|
}
|
|
|
|
// Arrange filled containers
|
|
TQRect filledRect( 0,
|
|
0,
|
|
parentWidget->width(),
|
|
parentWidget->height() - ( 40 + 2*spacing ) );
|
|
// arrange the filled desktops taking 90% of the screen
|
|
rearrangeContents( filledRect, filledContainers );
|
|
|
|
// Arrange empty containers
|
|
TQRect emptyRect( 0,
|
|
parentWidget->height() - ( 40 + 2*spacing ),
|
|
parentWidget->width(),
|
|
( 40 + 2*spacing ) );
|
|
// arrange the empty widget in one row
|
|
rearrangeContents( emptyRect, emptyContainers, 1, -1, false );
|
|
|
|
|
|
}
|
|
else // default type (generic)
|
|
{
|
|
TQRect availRect( 0,
|
|
0,
|
|
parentWidget->width(),
|
|
parentWidget->height());
|
|
rearrangeContents( availRect, list );
|
|
}
|
|
|
|
|
|
currentSize = parentWidget->size();
|
|
widgetsChanged = false;
|
|
}
|
|
|
|
|
|
/**
|
|
* availRect specifies the size&pos of the contents
|
|
* Specify either rows or cols to set a fixed number of those (setting both won't work correctly)
|
|
*/
|
|
void KomposeLayout::rearrangeContents( const TQRect& availRect, const TQPtrList<KomposeWidget> widgets, int rows, int columns, bool setMemberRowsCols )
|
|
{
|
|
// Check or empty list
|
|
if (widgets.count() == 0)
|
|
{
|
|
kdDebug() << "KomposeLayout::rearrangeContents() - empty list... skipping!" << endl;
|
|
return;
|
|
}
|
|
|
|
TQPtrListIterator<KomposeWidget> it( widgets );
|
|
|
|
// Calculate grid's rows & cols
|
|
if ( rows != -1 ) // rows have been specified
|
|
{
|
|
columns = (int)ceil(widgets.count() / rows);
|
|
}
|
|
else if ( columns != -1 ) // columns have been specified
|
|
{
|
|
rows = (int)ceil(widgets.count() / columns);
|
|
}
|
|
else // neither rows nor cols have been specified
|
|
{
|
|
double parentRatio = (double)availRect.width() / (double)availRect.height();
|
|
// Use more columns than rows when parent's width > parent's height
|
|
if ( parentRatio > 1 )
|
|
{
|
|
columns = (int)ceil( sqrt(widgets.count()) );
|
|
rows = (int)ceil( (double)widgets.count() / (double)columns );
|
|
}
|
|
else
|
|
{
|
|
rows = (int)ceil( sqrt(widgets.count()) );
|
|
columns = (int)ceil( (double)widgets.count() / (double)rows );
|
|
}
|
|
}
|
|
|
|
kdDebug() << "KomposeLayout::rearrangeContents() - Relayouting " << widgets.count() << " child widgets with " << rows << " rows & " << columns << " columns" << endl;
|
|
|
|
// Calculate width & height
|
|
int w = (availRect.width() - (columns+1) * spacing ) / columns;
|
|
int h = (availRect.height() - (rows+1) * spacing ) / rows;
|
|
|
|
TQValueList<TQRect> geometryRects;
|
|
TQValueList<int> maxRowHeights;
|
|
// Process rows
|
|
for ( int i=0; i<rows; ++i )
|
|
{
|
|
int xOffsetFromLastCol = 0;
|
|
int maxHeightInRow = 0;
|
|
// Process columns
|
|
for ( int j=0; j<columns; ++j )
|
|
{
|
|
KomposeWidget *task;
|
|
|
|
// Check for end of List
|
|
if ( (task = it.current()) == 0)
|
|
break;
|
|
|
|
// Calculate width and height of widget
|
|
double ratio = task->getAspectRatio();
|
|
|
|
int widgetw = 100;
|
|
int widgeth = 100;
|
|
int usableW = w;
|
|
int usableH = h;
|
|
|
|
// use width of two boxes if there is no right neighbour
|
|
if (it.atLast() && j!=columns-1)
|
|
{
|
|
usableW = 2*w;
|
|
}
|
|
++it; // We need access to the neighbour in the following
|
|
// expand if right neighbour has ratio < 1
|
|
if (j!=columns-1 && it.current() && it.current()->getAspectRatio() < 1)
|
|
{
|
|
int addW = w - it.current()->getWidthForHeight(h);
|
|
if ( addW > 0 )
|
|
{
|
|
usableW = w + addW;
|
|
}
|
|
}
|
|
|
|
if ( ratio == -1 )
|
|
{
|
|
widgetw = w;
|
|
widgeth = h;
|
|
}
|
|
else
|
|
{
|
|
double widthForHeight = task->getWidthForHeight(usableH);
|
|
double heightForWidth = task->getHeightForWidth(usableW);
|
|
if ( (ratio >= 1.0 && heightForWidth <= usableH) ||
|
|
(ratio < 1.0 && widthForHeight > usableW) )
|
|
{
|
|
widgetw = usableW;
|
|
widgeth = (int)heightForWidth;
|
|
}
|
|
else if ( (ratio < 1.0 && widthForHeight <= usableW) ||
|
|
(ratio >= 1.0 && heightForWidth > usableH) )
|
|
{
|
|
widgeth = usableH;
|
|
widgetw = (int)widthForHeight;
|
|
}
|
|
}
|
|
|
|
// Set the Widget's size
|
|
|
|
int alignmentXoffset = 0;
|
|
int alignmentYoffset = 0;
|
|
if ( i==0 && h > widgeth )
|
|
alignmentYoffset = h - widgeth;
|
|
if ( j==0 && w > widgetw )
|
|
alignmentXoffset = w - widgetw;
|
|
TQRect geom( availRect.x() + j * (w + spacing) + spacing + alignmentXoffset + xOffsetFromLastCol,
|
|
availRect.y() + i * (h + spacing) + spacing + alignmentYoffset,
|
|
widgetw, widgeth );
|
|
geometryRects.append(geom);
|
|
|
|
// Set the x offset for the next column
|
|
if (alignmentXoffset==0)
|
|
xOffsetFromLastCol += widgetw-w;
|
|
if (maxHeightInRow < widgeth)
|
|
maxHeightInRow = widgeth;
|
|
}
|
|
maxRowHeights.append(maxHeightInRow);
|
|
}
|
|
|
|
it.toFirst();
|
|
TQValueList<TQRect>::iterator geomIt = geometryRects.begin();
|
|
TQValueList<int>::iterator maxRowHeightIt = maxRowHeights.begin();
|
|
int topOffset = 0;
|
|
for ( int i=0; i<rows; ++i )
|
|
{
|
|
// Process columns again
|
|
for ( int j=0; j<columns; ++j )
|
|
{
|
|
KomposeWidget *task;
|
|
if ( (task = it.current()) == 0)
|
|
break;
|
|
|
|
TQRect geom = *geomIt;
|
|
geom.setY( geom.y() + topOffset );
|
|
// geom.setHeight( geom.height() - topOffset );
|
|
task->setGeometry( geom );
|
|
kdDebug() << "KomposeLayout::rearrangeContents() - Put item " << task->className() << " at x: " << geom.x() << " y: " << geom.y() << " with size: " << geom.width() << "x" << geom.height() << endl;
|
|
++geomIt;
|
|
++it;
|
|
}
|
|
if ( *maxRowHeightIt-h > 0 )
|
|
topOffset += *maxRowHeightIt-h;
|
|
++maxRowHeightIt;
|
|
}
|
|
|
|
// Sync cols/rows member vars to current cols/rows
|
|
if ( setMemberRowsCols )
|
|
{
|
|
currentRows = rows;
|
|
currentColumns = columns;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Search for neighbour (called from outside)
|
|
*/
|
|
KomposeWidget* KomposeLayout::getNeighbour( const KomposeWidget* widget, int direction, int wrap )
|
|
{
|
|
kdDebug() << "KomposeLayout::getNeighbour() - Called with list.count: " << list.count() << endl;
|
|
|
|
if (layoutType==TLAYOUT_TASKCONTAINERS)
|
|
{
|
|
KomposeWidget* neighbour = 0;
|
|
if ( filledContainers.containsRef(widget) )
|
|
{
|
|
if ( ( neighbour = getNeighbour( filledContainers, widget, direction, WLAYOUT_HORIZONTAL ) ) == 0 )
|
|
return emptyContainers.first();
|
|
}
|
|
else if ( emptyContainers.containsRef(widget) )
|
|
{
|
|
if ( ( neighbour = getNeighbour( emptyContainers, widget, direction, WLAYOUT_HORIZONTAL ) ) == 0 )
|
|
if ( direction == DLAYOUT_TOP )
|
|
return filledContainers.last();
|
|
else
|
|
return filledContainers.first();
|
|
}
|
|
return neighbour;
|
|
}
|
|
else if (layoutType==TLAYOUT_GENERIC)
|
|
return getNeighbour( list, widget, direction, wrap );
|
|
|
|
kdDebug() << "KomposeLayout::getNeighbour() - this should never happen!" << endl;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* Search for neighbour in the given list (called from inside)
|
|
*/
|
|
KomposeWidget* KomposeLayout::getNeighbour(
|
|
TQPtrList<KomposeWidget> listToSearch,
|
|
const KomposeWidget* widget,
|
|
int direction,
|
|
int wrap )
|
|
{
|
|
TQPtrListIterator<KomposeWidget> it( listToSearch );
|
|
|
|
KomposeWidget *task;
|
|
KomposeWidget *neighbour;
|
|
int index = 0;
|
|
|
|
if (widget == 0)
|
|
{
|
|
kdDebug() << "KomposeLayout::getNeighbour() - NULL startWidget given. using first()" << endl;
|
|
return listToSearch.first();
|
|
}
|
|
|
|
while ( (task = it.current()) != 0 )
|
|
{
|
|
if ( task == widget )
|
|
{
|
|
switch ( direction )
|
|
{
|
|
case DLAYOUT_RIGHT:
|
|
++it;
|
|
if ( (index)%currentColumns == currentColumns-1 || ( neighbour = it.current() ) == 0 )
|
|
{
|
|
if (wrap == WLAYOUT_HORIZONTAL || wrap == WLAYOUT_BOTH )
|
|
return listToSearch.at(index+1-currentColumns);
|
|
kdDebug() << "KomposeLayout::getNeighbour() - No valid neighbour available" << endl;
|
|
return NULL;
|
|
}
|
|
return neighbour;
|
|
case DLAYOUT_LEFT:
|
|
--it;
|
|
if ( index%currentColumns == 0 || ( neighbour = it.current() ) == 0 )
|
|
{
|
|
if (wrap == WLAYOUT_HORIZONTAL || wrap == WLAYOUT_BOTH )
|
|
if ( (uint)(index+currentColumns-1) < listToSearch.count() )
|
|
return listToSearch.at(index+currentColumns-1);
|
|
else
|
|
return listToSearch.last();
|
|
kdDebug() << "KomposeLayout::getNeighbour() - No valid neighbour available" << endl;
|
|
return NULL;
|
|
}
|
|
return neighbour;
|
|
case DLAYOUT_TOP:
|
|
if ( index < currentColumns || (neighbour = listToSearch.at( index - currentColumns )) == 0)
|
|
{
|
|
if (wrap == WLAYOUT_VERTICAL || wrap == WLAYOUT_BOTH )
|
|
if ( listToSearch.count()%currentColumns == 0 || listToSearch.count()%currentColumns > (uint)(index) )
|
|
return listToSearch.at( (currentRows-1)*currentColumns + index );
|
|
else
|
|
return listToSearch.at( (currentRows-2)*currentColumns + index );
|
|
kdDebug() << "KomposeLayout::getNeighbour() - No valid neighbour available" << endl;
|
|
return NULL;
|
|
}
|
|
return neighbour;
|
|
case DLAYOUT_BOTTOM:
|
|
if ( listToSearch.count() <= (uint)(index + currentColumns) || (neighbour = listToSearch.at( index + currentColumns )) == 0)
|
|
{
|
|
if (wrap == WLAYOUT_VERTICAL || wrap == WLAYOUT_BOTH )
|
|
return listToSearch.at( index%currentColumns );
|
|
kdDebug() << "KomposeLayout::getNeighbour() - No valid neighbour available" << endl;
|
|
return NULL;
|
|
}
|
|
return neighbour;
|
|
}
|
|
}
|
|
++index;
|
|
++it;
|
|
}
|
|
|
|
kdDebug() << "KomposeLayout::getNeighbour() - this should never happen!" << endl;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
#include "komposelayout.moc"
|