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.
kima/src/flowlayout.cpp

349 lines
11 KiB

/***************************************************************************
* Copyright (C) 2005 by Ken Werner *
* ken.werner@web.de *
* *
* 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., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "flowlayout.h"
#include "sources/source.h"
//#include "kdebug.h"
//#include <tqlabel.h> // debugging
class FlowLayoutIterator :public TQGLayoutIterator{
public:
FlowLayoutIterator( TQPtrList<TQLayoutItem>* layoutItems ):
index(0),
mLayoutItems(layoutItems){
}
uint count() const;
TQLayoutItem* current();
TQLayoutItem* next();
TQLayoutItem* takeCurrent();
private:
int index;
TQPtrList<TQLayoutItem>* mLayoutItems;
};
TQLayoutItem* FlowLayoutIterator::current(){
return index < int(mLayoutItems->count()) ? mLayoutItems->at(index) : 0;
/*if(index < int(mLayoutItems->count())){
TQLayoutItem* item = mLayoutItems->at(index);
kdDebug() << "FlowLayoutIterator::current(index " << index << ") returns: " << item << endl;
return item;
}else{
kdDebug() << "FlowLayoutIterator::current(index " << index << ") returns: NULL" << endl;
return 0;
}*/
}
TQLayoutItem* FlowLayoutIterator::next(){
index++;
//kdDebug() << "FlowLayoutIterator::next, index: " << index << endl;
return current();
}
TQLayoutItem* FlowLayoutIterator::takeCurrent(){
return index < int(mLayoutItems->count()) ? mLayoutItems->take(index) : 0;
/*if(index < int(mLayoutItems->count())){
TQLayoutItem* item = mLayoutItems->take(index);
kdDebug() << "FlowLayoutIterator::takeCurrent(index " << index << ") returns: " << item << endl;
return item;
}else{
kdDebug() << "FlowLayoutIterator::takeCurrent(index " << index << ") returns: NULL" << endl;
return 0;
}*/
}
FlowLayout::FlowLayout( TQWidget* parent, Qt::Orientation orientation, int border, int space, const char* name )
: TQLayout( parent, border, space, name ),
mOrientation(orientation), mLastItem(NULL){
}
FlowLayout::FlowLayout( TQLayout* parent, Qt::Orientation orientation, int space, const char* name )
: TQLayout( parent, space, name ),
mOrientation(orientation), mLastItem(NULL){
}
FlowLayout::FlowLayout( Qt::Orientation orientation, int space, const char* name )
: TQLayout( space, name ),
mOrientation(orientation), mLastItem(NULL){
}
FlowLayout::~FlowLayout(){
deleteAllItems();
}
int FlowLayout::heightForWidth( int w ) const{
FlowLayout* mthis = (FlowLayout*)this;
int h = mthis->doLayout( TQRect(0,0,w,0), TRUE );
return h;
}
int FlowLayout::widthForHeight( int h ) const{
FlowLayout* mthis = (FlowLayout*)this;
int w = mthis->doLayout( TQRect(0,0,0,h), TRUE );
return w;
}
void FlowLayout::addItem(TQLayoutItem* item){
//kdDebug() << "FlowLayout::addItem: " << (static_cast<TQLabel*>(item->widget()))->text() << ", width: " << item->widget()->width() << ", height: " << item->widget()->height()<< endl;
// we are indirectly called from addSource. this
// is a hint for addSource, to let it know which item
// was added.
mLastItem = TQT_TQLAYOUTITEM(item);
}
void FlowLayout::addSource(Source* src){
add(src->getWidget());
mSources[mLastItem] = src;
src->getWidget()->show();
// step back until we find an item which has a
// smaller position stored in its config. then, we found
// the right position for the new item.
TQLayoutItem * qli = mLayoutItems.last();
while(qli && mSources[qli]->getPosition() > src->getPosition())
qli = mLayoutItems.prev();
mLayoutItems.insert(mLayoutItems.at()+1, mLastItem);
}
void FlowLayout::remove(TQWidget* widget){
//kdDebug() << "FlowLayout::remove: " << (static_cast<TQLabel*>(widget))->text() << endl;
widget->hide();
TQPtrListIterator<TQLayoutItem> it(mLayoutItems);
while(it.current() != NULL) {
if(it.current()->widget() == widget) {
mSources.erase(it.current());
mLayoutItems.remove(it.current());
// removes and deletes only the TQLayoutItem
// (TQWidgetItem)
TQLayout::remove(widget);
break;
}
++it;
}
}
uint FlowLayout::count(){
return mLayoutItems.count();
}
bool FlowLayout::moveItem(const TQLayoutItem* which, const TQLayoutItem* relate, DIRECTION direction){
int newPos = mLayoutItems.findRef(relate);
int oldPos = mLayoutItems.findRef(which);
// check whether the widget is already at a correct position
if(oldPos+1 == newPos && direction == ABOVE || oldPos-1 == newPos && direction == BELOW)
return false;
// remove the item
mLayoutItems.remove(which);
if(oldPos < newPos)
newPos--;
newPos += direction;
// actually reinsert the item
mLayoutItems.insert(newPos, which);
activate(); // relayout
// kdDebug() << "oldPos: " << oldPos << ", newPos: " << newPos << endl;
return true;
}
void FlowLayout::updatePositions(TDEConfig * inTDEConfig){
//kdDebug() << "updating all positions..." << endl;
int pos = 0;
TQPtrListIterator<TQLayoutItem> it(mLayoutItems);
while(it.current() != NULL) {
mSources[it.current()]->setPosition(pos, inTDEConfig);
++it;
++pos;
}
//kdDebug() << "positions updated!" << endl;
}
bool FlowLayout::hasHeightForWidth() const{
return mOrientation != Qt::Horizontal;
}
bool FlowLayout::hasWidthForHeight() const{
return mOrientation == Qt::Horizontal;
}
TQSize FlowLayout::sizeHint() const{
//return minimumSize();
TQSize size(0,0);
TQPtrListIterator<TQLayoutItem> it(mLayoutItems);
TQLayoutItem *o;
while((o=it.current()) != 0){
++it;
size = size.expandedTo( o->sizeHint() );
}
return size;
}
TQSize FlowLayout::minimumSize() const{
TQSize size(0,0);
TQPtrListIterator<TQLayoutItem> it(mLayoutItems);
TQLayoutItem *o;
while((o=it.current()) != 0){
++it;
size = size.expandedTo(o->minimumSize());
}
return size;
}
TQSizePolicy::ExpandData FlowLayout::expanding() const{
return TQ_SPNoDirection;
}
TQLayoutIterator FlowLayout::iterator(){
// [FIXME]
#ifdef USE_QT4
#warning [FIXME] ContainerAreaLayout iterators may not function correctly under Qt4
return TQLayoutIterator( this ); // [FIXME]
#else // USE_QT4
return TQLayoutIterator(new FlowLayoutIterator(&mLayoutItems));
#endif // USE_QT4
}
Qt::Orientation FlowLayout::getOrientation() const{
return mOrientation;
}
void FlowLayout::setOrientation(Qt::Orientation orientation){
mOrientation = orientation;
}
void FlowLayout::setGeometry( const TQRect& rect ){
TQLayout::setGeometry( rect );
doLayout( rect );
}
int FlowLayout::doLayout( const TQRect& rect, bool testonly ){
if(mOrientation == Qt::Horizontal)
return doLayoutHorizontal(rect, testonly);
else
return doLayoutVertical(rect, testonly);
}
int FlowLayout::doLayoutHorizontal( const TQRect& rect, bool testOnly ){
//kdDebug() << "spacing: " << spacing() << endl;
int x = rect.x();
int y = rect.y();
int width = 0; // width of this column so far
int height = 0; // height of this column so far
TQPtrListIterator<TQLayoutItem> it(mLayoutItems);
TQLayoutItem* layoutItem;
TQPtrList<TQLayoutItem> column; // stores the items of one column
while((layoutItem = it.current()) != 0){
++it;
//int nextY = y + layoutItem->sizeHint().height() + spacing(); // next y
int nextY = y + layoutItem->sizeHint().height(); // next y
//if( nextY - spacing() > rect.bottom() && width > 0 ) {
if( nextY > rect.bottom() && width > 0 ) {
// next column
y = rect.y(); // reset y
x = x + width + spacing(); // new x
//nextY = y + layoutItem->sizeHint().height() + spacing(); // next y with changed y
nextY = y + layoutItem->sizeHint().height(); // next y with changed y
width = 0; // reset width for the next column
}
if(!testOnly){
layoutItem->setGeometry( TQRect( TQPoint( x, y ), layoutItem->sizeHint() ) );
column.append(layoutItem);
height += layoutItem->sizeHint().height(); // add the height of the current item to the column height
if( it.current() == 0 || nextY + it.current()->sizeHint().height() > rect.bottom() ){ // test it it's the last item (of this column)
// calculate real needed width
int rWidth = 0;
for(TQLayoutItem* item = column.first(); item; item = column.next()){
rWidth = TQMAX( rWidth, item->widget()->sizeHint().width() );
}
// relayout the items of the former column
int space = (rect.height() - height) / (column.count() + 1);
int i = 0; // counts the items of this column
for(TQLayoutItem* item = column.first(); item; item = column.next()){
TQRect r = item->geometry();
item->setGeometry( TQRect(r.left(), r.top() + ((++i) * space), rWidth, r.height()) );
}
column.clear(); // remove the items of the former column
height = 0; // reset height for the next column
}
}
y = nextY;
width = TQMAX( width, layoutItem->sizeHint().width() );
}
return x + width - rect.x(); // width
}
int FlowLayout::doLayoutVertical( const TQRect& rect, bool testOnly ){
int x = rect.x();
int y = rect.y();
int height = 0; // height of this line so far
TQPtrListIterator<TQLayoutItem> it(mLayoutItems);
TQLayoutItem* layoutItem;
while((layoutItem = it.current() ) != 0){
++it;
//int nextX = x + layoutItem->sizeHint().width() + spacing();
int nextX = x + layoutItem->sizeHint().width();
if(nextX - spacing() > rect.right() && height > 0) {
// next line
x = rect.x(); // reset x
//y = y + height + spacing(); // new y
y = y + height; // new y
//nextX = x + layoutItem->sizeHint().width() + spacing(); // next x
nextX = x + layoutItem->sizeHint().width(); // next x
height = 0; // reset height for the next line
}
const int itemHeight = layoutItem->sizeHint().height();
if(!testOnly)
layoutItem->setGeometry(TQRect(x, y, rect.right(), itemHeight));
x = nextX;
height = TQMAX(height, itemHeight);
}
return y + height - rect.y(); // height
}
#ifdef USE_QT4
/*!
\reimp
*/
int FlowLayout::count() const {
return mLayoutItems.count();
}
/*!
\reimp
*/
TQLayoutItem* FlowLayout::itemAt(int index) const {
return index >= 0 && index < mLayoutItems.count() ? (const_cast<TQPtrList<TQLayoutItem>&>(mLayoutItems).at(index)) : 0;
}
/*!
\reimp
*/
TQLayoutItem* FlowLayout::takeAt(int index) {
if (index < 0 || index >= mLayoutItems.count())
return 0;
TQLayoutItem *item = mLayoutItems.at(index);
mLayoutItems.remove(mLayoutItems.at(index));
delete item;
invalidate();
return item;
}
#endif // USE_QT4
#include "flowlayout.moc"