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.
tdelibs/kdeui/kbuttonbox.cpp

378 lines
8.9 KiB

/* This file is part of the KDE libraries
Copyright (C) 1997 Mario Weilguni (mweilguni@sime.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
/*
* KButtonBox class
*
* A container widget for buttons. Uses Qt layout control to place the
* buttons, can handle both vertical and horizontal button placement.
*
* HISTORY
*
* 05/11/2004 Andrew Coles <andrew_coles@yahoo.co.uk>
* Now uses QPtrListIterators instead of indexing through data->buttons
* Item.button and data are now const pointers, set in the relevant constructors
*
* 03/08/2000 Mario Weilguni <mweilguni@kde.org>
* Removed all those long outdated Motif stuff
* Improved and clarified some if conditions (easier to understand)
*
* 11/13/98 Reginald Stadlbauer <reggie@kde.org>
* Now in Qt 1.4x motif default buttons have no extra width/height anymore.
* So the KButtonBox doesn't add this width/height to default buttons anymore
* which makes the buttons look better.
*
* 01/17/98 Mario Weilguni <mweilguni@sime.com>
* Fixed a bug in sizeHint()
* Improved the handling of Motif default buttons
*
* 01/09/98 Mario Weilguni <mweilguni@sime.com>
* The last button was to far right away from the right/bottom border.
* Fixed this. Removed old code. Buttons get now a minimum width.
* Programmer may now override minimum width and height of a button.
*
*/
#include "kbuttonbox.moc"
#include <kglobalsettings.h>
#include <kguiitem.h>
#include <kpushbutton.h>
#include <qptrlist.h>
#include <assert.h>
#define minButtonWidth 50
class KButtonBox::Item {
public:
KPushButton* const button;
bool noexpand;
unsigned short stretch;
unsigned short actual_size;
Item(KPushButton* const _button) : button(_button) {}
};
template class QPtrList<KButtonBox::Item>;
class KButtonBoxPrivate {
public:
unsigned short border;
unsigned short autoborder;
unsigned short orientation;
bool activated;
QPtrList<KButtonBox::Item> buttons;
};
KButtonBox::KButtonBox(QWidget *parent, Orientation _orientation,
int border, int autoborder)
: QWidget(parent), data(new KButtonBoxPrivate)
{
assert(data);
data->orientation = _orientation;
data->border = border;
data->autoborder = autoborder < 0 ? border : autoborder;
data->buttons.setAutoDelete(true);
}
KButtonBox::~KButtonBox() {
delete data;
}
QPushButton *KButtonBox::addButton(const QString& text, bool noexpand) {
Item* const item = new Item(new KPushButton(text, this));
item->noexpand = noexpand;
data->buttons.append(item);
item->button->adjustSize();
this->updateGeometry();
return item->button;
}
QPushButton *KButtonBox::addButton(const KGuiItem& guiitem, bool noexpand) {
Item* const item = new Item(new KPushButton(guiitem, this));
item->noexpand = noexpand;
data->buttons.append(item);
item->button->adjustSize();
this->updateGeometry();
return item->button;
}
QPushButton *
KButtonBox::addButton(
const QString & text,
QObject * receiver,
const char * slot,
bool noexpand
)
{
QPushButton * pb = addButton(text, noexpand);
if ((0 != receiver) && (0 != slot))
QObject::connect(pb, SIGNAL(clicked()), receiver, slot);
return pb;
}
QPushButton *
KButtonBox::addButton(
const KGuiItem& guiitem,
QObject * receiver,
const char * slot,
bool noexpand
)
{
QPushButton * pb = addButton(guiitem, noexpand);
if ((0 != receiver) && (0 != slot))
QObject::connect(pb, SIGNAL(clicked()), receiver, slot);
return pb;
}
void KButtonBox::addStretch(int scale) {
if(scale > 0) {
Item* const item = new Item(0);
item->noexpand = false;
item->stretch = scale;
data->buttons.append(item);
}
}
void KButtonBox::layout() {
// resize all buttons
const QSize bs = bestButtonSize();
QPtrListIterator<KButtonBox::Item> itr(data->buttons);
Item* item;
while ( (item = itr.current()) != 0 ) {
QPushButton* const b = item->button;
if(b) {
if(item->noexpand)
b->setFixedSize(buttonSizeHint(b));
else
b->setFixedSize(bs);
}
++itr;
}
setMinimumSize(sizeHint());
}
void KButtonBox::placeButtons() {
if(data->orientation == Horizontal) {
// calculate free size and stretches
int fs = width() - 2 * data->border;
int stretch = 0;
{
QPtrListIterator<KButtonBox::Item> itr(data->buttons);
Item *item;
while ( (item = itr.current()) != 0 ) {
QPushButton* const b = item->button;
if(b) {
fs -= b->width();
// Last button?
if(!itr.atLast())
fs -= data->autoborder;
} else {
stretch +=item->stretch;
}
++itr;
}
}
// distribute buttons
int x_pos = data->border;
{
QPtrListIterator<KButtonBox::Item> itr(data->buttons);
Item *item;
while ( (item = itr.current()) != 0 ) {
QPushButton* const b = item->button;
if(b) {
b->move(x_pos, (height() - b->height()) / 2);
x_pos += b->width() + data->autoborder;
} else {
x_pos += (int)((((double)fs) * item->stretch) / stretch);
}
++itr;
}
}
} else { // VERTICAL
// calcualte free size and stretches
int fs = height() - 2 * data->border;
int stretch = 0;
{
QPtrListIterator<KButtonBox::Item> itr(data->buttons);
Item *item;
while ( (item = itr.current()) != 0 ) {
QPushButton* const b = item->button;
if(b)
fs -= b->height() + data->autoborder;
else
stretch +=item->stretch;
++itr;
}
}
// distribute buttons
int y_pos = data->border;
{
QPtrListIterator<KButtonBox::Item> itr(data->buttons);
Item *item;
while ( (item = itr.current()) != 0 ) {
QPushButton* const b = item->button;
if(b) {
b->move((width() - b->width()) / 2, y_pos);
y_pos += b->height() + data->autoborder;
} else {
y_pos += (int)((((double)fs) * item->stretch) / stretch);
}
++itr;
}
}
}
}
void KButtonBox::resizeEvent(QResizeEvent *) {
placeButtons();
}
QSize KButtonBox::bestButtonSize() const {
QSize s(0, 0);
// calculate optimal size
QPtrListIterator<KButtonBox::Item> itr(data->buttons);
Item *item;
while ( (item = itr.current()) != 0 ) {
QPushButton* const b = item->button;
if(b && !item->noexpand) {
const QSize bs = buttonSizeHint(b);
const int bsWidth = bs.width();
const int bsHeight = bs.height();
if(bsWidth > s.width())
s.setWidth(bsWidth);
if(bsHeight > s.height())
s.setHeight(bsHeight);
}
++itr;
}
return s;
}
QSize KButtonBox::sizeHint() const {
unsigned int dw;
if(data->buttons.isEmpty())
return QSize(0, 0);
else {
dw = 2 * data->border;
const QSize bs = bestButtonSize();
QPtrListIterator<KButtonBox::Item> itr(data->buttons);
Item *item;
while ( (item = itr.current()) != 0 ) {
QPushButton* const b = item->button;
if(b) {
QSize s;
if(item->noexpand)
s = buttonSizeHint(b);
else
s = bs;
if(data->orientation == Horizontal)
dw += s.width();
else
dw += s.height();
if( !itr.atLast() )
dw += data->autoborder;
}
++itr;
}
if(data->orientation == Horizontal)
return QSize(dw, bs.height() + 2 * data->border);
else
return QSize(bs.width() + 2 * data->border, dw);
}
}
QSizePolicy KButtonBox::sizePolicy() const
{
return data->orientation == Horizontal?
QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) :
QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum );
}
/*
* Returns the best size for a button. If a button is less than
* minButtonWidth pixels wide, return minButtonWidth pixels
* as minimum width
*/
QSize KButtonBox::buttonSizeHint(QPushButton *b) const {
QSize s = b->sizeHint();
const QSize ms = b->minimumSize();
if(s.width() < minButtonWidth)
s.setWidth(minButtonWidth);
// allows the programmer to override the settings
const int msWidth = ms.width();
const int msHeight = ms.height();
if(msWidth > s.width())
s.setWidth(msWidth);
if(msHeight > s.height())
s.setHeight(msHeight);
return s;
}
void KButtonBox::virtual_hook( int, void* )
{ /*BASE::virtual_hook( id, data );*/ }