/**************************************************************************** ** $Id: buttonflowlayout.cpp 272 2005-05-18 08:12:51Z emw $ ** ** Implementing your own layout: flow example ** ** Copyright (C) 1996 by Trolltech AS. All rights reserved. ** ** This file is part of an example program for TQt. This example ** program may be used, distributed and modified without limitation. ** *****************************************************************************/ /** Modified 2002 by Klas Kalass (klas.kalass@gmx.de) for kradio */ #include #include "buttonflowlayout.h" /*********************************************/ /* Iterator */ class ButtonFlowLayoutIterator :public TQGLayoutIterator { public: ButtonFlowLayoutIterator( TQPtrList *l ) :idx(0), list(l) {} uint count() const; TQLayoutItem *current(); TQLayoutItem *next(); TQLayoutItem *takeCurrent(); private: int idx; TQPtrList *list; }; uint ButtonFlowLayoutIterator::count() const { return list->count(); } TQLayoutItem *ButtonFlowLayoutIterator::current() { return idx < int(count()) ? list->at(idx) : 0; } TQLayoutItem *ButtonFlowLayoutIterator::next() { idx++; return current(); } TQLayoutItem *ButtonFlowLayoutIterator::takeCurrent() { return idx < int(count()) ? list->take( idx ) : 0; } /**************************************************************/ ButtonFlowLayout::ButtonFlowLayout( TQWidget *parent, int margin, int spacing, const char *name ) : TQLayout( parent, margin, spacing, name ), cached_width(0) { } ButtonFlowLayout::ButtonFlowLayout( TQLayout* parentLayout, int spacing, const char *name ) : TQLayout( parentLayout, spacing, name ), cached_width(0) { } ButtonFlowLayout::ButtonFlowLayout( int spacing, const char *name ) : TQLayout( spacing, name ), cached_width(0) { } ButtonFlowLayout::~ButtonFlowLayout() { deleteAllItems(); } int ButtonFlowLayout::heightForWidth( int w ) const { if ( cached_width != w ) { //Not all C++ compilers support "mutable" yet: ButtonFlowLayout * mthis = (ButtonFlowLayout*)this; int h = mthis->doLayout( TQRect(0,0,w,0), TRUE ); mthis->cached_hfw = h; mthis->cached_width = w; return h; } return cached_hfw; } void ButtonFlowLayout::addItem( TQLayoutItem *item) { list.append( TQT_TQLAYOUTITEM(item) ); } bool ButtonFlowLayout::hasHeightForWidth() const { return TRUE; } TQSize ButtonFlowLayout::sizeHint() const { return minimumSize(); } TQSizePolicy::ExpandData ButtonFlowLayout::expanding() const { return TQ_SPNoDirection; } TQLayoutIterator ButtonFlowLayout::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 ButtonFlowLayoutIterator( &list ) ); #endif // USE_QT4 } void ButtonFlowLayout::setGeometry( const TQRect &r ) { TQLayout::setGeometry( r ); doLayout( r ); } int ButtonFlowLayout::doLayout( const TQRect &r, bool testonly ) { /* kdDebug() << "buttonflowlayout::doLayout (" << r.x() << "," << r.y() << "," << r.width() << "," << r.height() << ", " << testonly << ")\n"; */ float x = r.x(); float y = r.y(); int h = 0; //height of this line so far. float buttonWidth = 0; int buttonHeight = 0; int linecount = 0; int totalWidth = r.width(); int totalHeight = r.height(); TQPtrListIterator it(list); TQLayoutItem *o; // get the width of the biggest Button it.toFirst(); while ( (o=it.current()) != 0 ) { ++it; buttonWidth = TQMAX( buttonWidth, o->sizeHint().width() ); buttonHeight = TQMAX( buttonHeight, o->sizeHint().height() ); } // calculate the optimal width unsigned int columns = (totalWidth + spacing()) / ((int)buttonWidth + spacing()); if (columns > it.count() ) columns = it.count(); if (columns == 0) columns = 1; // avoid division by zero int rows = (it.count() - 1) / columns + 1; float deltaH = (float)(totalHeight - rows * buttonHeight - (rows - 1) * spacing()) / (float)(rows + 1) ; if (deltaH < 0) deltaH = 0; y += deltaH; buttonWidth = (float)(totalWidth - spacing()*(columns-1)) / (float)columns; /* fprintf (stderr, "cols = %i col-width = %f\n" "rows = %i row-height = %i\n" "w = %i h = %i\n", columns, buttonWidth, rows, buttonHeight, totalWidth, totalHeight ); */ // calculate the positions and sizes it.toFirst(); while ( (o = it.current()) != 0 ) { // fprintf (stderr, "x = %i y = %i\n", x, (int)y); ++it; int btnRight = (int)rint(x + buttonWidth) - 1, btnLeft = (int)rint(x); if ( btnRight > r.right() && h > 0 ) { x = r.x(); btnRight = (int)rint(x + buttonWidth) - 1; btnLeft = (int)rint(x); y += h + spacing() + deltaH; h = 0; linecount++; } if (!testonly) o->setGeometry( TQRect( TQPoint( btnLeft, (int)rint(y) ), TQSize( btnRight - btnLeft + 1, buttonHeight) ) ); x += buttonWidth + spacing(); h = TQMAX( h, buttonHeight ); } int ret = (int)rint(y + h + deltaH) - r.y(); // kdDebug() << "ButtonFlowLayout::doLayout() = " << ret << endl; return ret; } TQSize ButtonFlowLayout::minimumSize() const { return minimumSize(geometry().size()); } TQSize ButtonFlowLayout::minimumSize(const TQSize &r) const { TQSize s(0, 0); for (TQPtrListIterator it(list); it.current(); ++it) { TQLayoutItem *o = it.current(); s = s.expandedTo( o->sizeHint()); //minimumSize() ); } s.setHeight(heightForWidth(r.width())); return s; } #ifdef USE_QT4 /*! \reimp */ int ButtonFlowLayout::count() const { return list.count(); } /*! \reimp */ TQLayoutItem* ButtonFlowLayout::itemAt(int index) const { return index >= 0 && index < list.count() ? (const_cast&>(list).at(index)) : 0; } /*! \reimp */ TQLayoutItem* ButtonFlowLayout::takeAt(int index) { if (index < 0 || index >= list.count()) return 0; TQLayoutItem *item = list.at(index); list.remove(list.at(index)); delete item; invalidate(); return item; } #endif // USE_QT4