/****************************************************************************
** $Id: buttonflowtqlayout.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 tderadio
 */

#include <kdebug.h>

#include "buttonflowlayout.h"

/*********************************************/
/*              Iterator                     */
class ButtonFlowLayoutIterator :public TQGLayoutIterator
{
public:
    ButtonFlowLayoutIterator( TQPtrList<TQLayoutItem> *l ) :idx(0), list(l)  {}
    uint count() const;
    TQLayoutItem *current();
    TQLayoutItem *next();
    TQLayoutItem *takeCurrent();

private:
    int idx;
    TQPtrList<TQLayoutItem> *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( item );
}

bool ButtonFlowLayout::hasHeightForWidth() const
{
    return TRUE;
}

TQSize ButtonFlowLayout::sizeHint() const
{
    return minimumSize();
}

TQSizePolicy::ExpandData ButtonFlowLayout::expanding() const
{
    return TQSizePolicy::NoDirection;
}

TQLayoutIterator ButtonFlowLayout::iterator()
{
    return TQLayoutIterator( new ButtonFlowLayoutIterator( &list ) );
}

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<TQLayoutItem> 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<TQLayoutItem> it(list); it.current(); ++it) {
        TQLayoutItem *o = it.current();
        s = s.expandedTo( o->sizeHint()); //minimumSize() );
    }

    s.setHeight(heightForWidth(r.width()));

    return s;
}
