kbuttonbox.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 1997 Mario Weilguni (mweilguni@sime.com) 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 /* 00021 * KButtonBox class 00022 * 00023 * A container widget for buttons. Uses Qt layout control to place the 00024 * buttons, can handle both vertical and horizontal button placement. 00025 * 00026 * HISTORY 00027 * 00028 * 05/11/2004 Andrew Coles <andrew_coles@yahoo.co.uk> 00029 * Now uses QPtrListIterators instead of indexing through data->buttons 00030 * Item.button and data are now const pointers, set in the relevant constructors 00031 * 00032 * 03/08/2000 Mario Weilguni <mweilguni@kde.org> 00033 * Removed all those long outdated Motif stuff 00034 * Improved and clarified some if conditions (easier to understand) 00035 * 00036 * 11/13/98 Reginald Stadlbauer <reggie@kde.org> 00037 * Now in Qt 1.4x motif default buttons have no extra width/height anymore. 00038 * So the KButtonBox doesn't add this width/height to default buttons anymore 00039 * which makes the buttons look better. 00040 * 00041 * 01/17/98 Mario Weilguni <mweilguni@sime.com> 00042 * Fixed a bug in sizeHint() 00043 * Improved the handling of Motif default buttons 00044 * 00045 * 01/09/98 Mario Weilguni <mweilguni@sime.com> 00046 * The last button was to far right away from the right/bottom border. 00047 * Fixed this. Removed old code. Buttons get now a minimum width. 00048 * Programmer may now override minimum width and height of a button. 00049 * 00050 */ 00051 00052 #include "kbuttonbox.moc" 00053 #include <kglobalsettings.h> 00054 #include <kguiitem.h> 00055 #include <kpushbutton.h> 00056 #include <qptrlist.h> 00057 #include <assert.h> 00058 00059 #define minButtonWidth 50 00060 00061 class KButtonBox::Item { 00062 public: 00063 KPushButton* const button; 00064 bool noexpand; 00065 unsigned short stretch; 00066 unsigned short actual_size; 00067 00068 Item(KPushButton* const _button) : button(_button) {} 00069 }; 00070 00071 template class QPtrList<KButtonBox::Item>; 00072 00073 class KButtonBoxPrivate { 00074 public: 00075 unsigned short border; 00076 unsigned short autoborder; 00077 unsigned short orientation; 00078 bool activated; 00079 QPtrList<KButtonBox::Item> buttons; 00080 }; 00081 00082 KButtonBox::KButtonBox(QWidget *parent, Orientation _orientation, 00083 int border, int autoborder) 00084 : QWidget(parent), data(new KButtonBoxPrivate) 00085 { 00086 assert(data); 00087 00088 data->orientation = _orientation; 00089 data->border = border; 00090 data->autoborder = autoborder < 0 ? border : autoborder; 00091 data->buttons.setAutoDelete(true); 00092 } 00093 00094 KButtonBox::~KButtonBox() { 00095 delete data; 00096 } 00097 00098 QPushButton *KButtonBox::addButton(const QString& text, bool noexpand) { 00099 Item* const item = new Item(new KPushButton(text, this)); 00100 00101 item->noexpand = noexpand; 00102 data->buttons.append(item); 00103 item->button->adjustSize(); 00104 00105 this->updateGeometry(); 00106 00107 return item->button; 00108 } 00109 00110 QPushButton *KButtonBox::addButton(const KGuiItem& guiitem, bool noexpand) { 00111 Item* const item = new Item(new KPushButton(guiitem, this)); 00112 00113 item->noexpand = noexpand; 00114 data->buttons.append(item); 00115 item->button->adjustSize(); 00116 00117 this->updateGeometry(); 00118 00119 return item->button; 00120 } 00121 00122 QPushButton * 00123 KButtonBox::addButton( 00124 const QString & text, 00125 QObject * receiver, 00126 const char * slot, 00127 bool noexpand 00128 ) 00129 { 00130 QPushButton * pb = addButton(text, noexpand); 00131 00132 if ((0 != receiver) && (0 != slot)) 00133 QObject::connect(pb, SIGNAL(clicked()), receiver, slot); 00134 00135 return pb; 00136 } 00137 00138 QPushButton * 00139 KButtonBox::addButton( 00140 const KGuiItem& guiitem, 00141 QObject * receiver, 00142 const char * slot, 00143 bool noexpand 00144 ) 00145 { 00146 QPushButton * pb = addButton(guiitem, noexpand); 00147 00148 if ((0 != receiver) && (0 != slot)) 00149 QObject::connect(pb, SIGNAL(clicked()), receiver, slot); 00150 00151 return pb; 00152 } 00153 00154 void KButtonBox::addStretch(int scale) { 00155 if(scale > 0) { 00156 Item* const item = new Item(0); 00157 item->noexpand = false; 00158 item->stretch = scale; 00159 data->buttons.append(item); 00160 } 00161 } 00162 00163 void KButtonBox::layout() { 00164 // resize all buttons 00165 const QSize bs = bestButtonSize(); 00166 00167 QPtrListIterator<KButtonBox::Item> itr(data->buttons); 00168 Item* item; 00169 00170 while ( (item = itr.current()) != 0 ) { 00171 QPushButton* const b = item->button; 00172 if(b) { 00173 if(item->noexpand) 00174 b->setFixedSize(buttonSizeHint(b)); 00175 else 00176 b->setFixedSize(bs); 00177 } 00178 ++itr; 00179 } 00180 00181 setMinimumSize(sizeHint()); 00182 } 00183 00184 void KButtonBox::placeButtons() { 00185 00186 if(data->orientation == Horizontal) { 00187 // calculate free size and stretches 00188 int fs = width() - 2 * data->border; 00189 int stretch = 0; 00190 { 00191 QPtrListIterator<KButtonBox::Item> itr(data->buttons); 00192 Item *item; 00193 00194 while ( (item = itr.current()) != 0 ) { 00195 QPushButton* const b = item->button; 00196 if(b) { 00197 fs -= b->width(); 00198 00199 // Last button? 00200 if(!itr.atLast()) 00201 fs -= data->autoborder; 00202 } else { 00203 stretch +=item->stretch; 00204 } 00205 00206 ++itr; 00207 } 00208 } 00209 00210 // distribute buttons 00211 int x_pos = data->border; 00212 { 00213 QPtrListIterator<KButtonBox::Item> itr(data->buttons); 00214 Item *item; 00215 00216 while ( (item = itr.current()) != 0 ) { 00217 QPushButton* const b = item->button; 00218 if(b) { 00219 b->move(x_pos, (height() - b->height()) / 2); 00220 00221 x_pos += b->width() + data->autoborder; 00222 } else { 00223 x_pos += (int)((((double)fs) * item->stretch) / stretch); 00224 } 00225 00226 ++itr; 00227 } 00228 } 00229 00230 } else { // VERTICAL 00231 // calcualte free size and stretches 00232 int fs = height() - 2 * data->border; 00233 int stretch = 0; 00234 { 00235 QPtrListIterator<KButtonBox::Item> itr(data->buttons); 00236 Item *item; 00237 00238 while ( (item = itr.current()) != 0 ) { 00239 QPushButton* const b = item->button; 00240 if(b) 00241 fs -= b->height() + data->autoborder; 00242 else 00243 stretch +=item->stretch; 00244 00245 ++itr; 00246 } 00247 00248 } 00249 00250 // distribute buttons 00251 int y_pos = data->border; 00252 { 00253 QPtrListIterator<KButtonBox::Item> itr(data->buttons); 00254 Item *item; 00255 00256 while ( (item = itr.current()) != 0 ) { 00257 QPushButton* const b = item->button; 00258 if(b) { 00259 b->move((width() - b->width()) / 2, y_pos); 00260 00261 y_pos += b->height() + data->autoborder; 00262 } else { 00263 y_pos += (int)((((double)fs) * item->stretch) / stretch); 00264 } 00265 00266 ++itr; 00267 } 00268 } 00269 } 00270 } 00271 00272 void KButtonBox::resizeEvent(QResizeEvent *) { 00273 placeButtons(); 00274 } 00275 00276 QSize KButtonBox::bestButtonSize() const { 00277 QSize s(0, 0); 00278 00279 // calculate optimal size 00280 QPtrListIterator<KButtonBox::Item> itr(data->buttons); 00281 Item *item; 00282 00283 while ( (item = itr.current()) != 0 ) { 00284 QPushButton* const b = item->button; 00285 00286 if(b && !item->noexpand) { 00287 const QSize bs = buttonSizeHint(b); 00288 00289 const int bsWidth = bs.width(); 00290 const int bsHeight = bs.height(); 00291 00292 if(bsWidth > s.width()) 00293 s.setWidth(bsWidth); 00294 if(bsHeight > s.height()) 00295 s.setHeight(bsHeight); 00296 } 00297 ++itr; 00298 } 00299 00300 return s; 00301 } 00302 00303 QSize KButtonBox::sizeHint() const { 00304 unsigned int dw; 00305 00306 if(data->buttons.isEmpty()) 00307 return QSize(0, 0); 00308 else { 00309 dw = 2 * data->border; 00310 00311 const QSize bs = bestButtonSize(); 00312 00313 QPtrListIterator<KButtonBox::Item> itr(data->buttons); 00314 Item *item; 00315 00316 while ( (item = itr.current()) != 0 ) { 00317 QPushButton* const b = item->button; 00318 00319 if(b) { 00320 QSize s; 00321 if(item->noexpand) 00322 s = buttonSizeHint(b); 00323 else 00324 s = bs; 00325 00326 if(data->orientation == Horizontal) 00327 dw += s.width(); 00328 else 00329 dw += s.height(); 00330 00331 if( !itr.atLast() ) 00332 dw += data->autoborder; 00333 } 00334 00335 ++itr; 00336 } 00337 00338 if(data->orientation == Horizontal) 00339 return QSize(dw, bs.height() + 2 * data->border); 00340 else 00341 return QSize(bs.width() + 2 * data->border, dw); 00342 } 00343 } 00344 00345 QSizePolicy KButtonBox::sizePolicy() const 00346 { 00347 return data->orientation == Horizontal? 00348 QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) : 00349 QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ); 00350 } 00351 00352 /* 00353 * Returns the best size for a button. If a button is less than 00354 * minButtonWidth pixels wide, return minButtonWidth pixels 00355 * as minimum width 00356 */ 00357 QSize KButtonBox::buttonSizeHint(QPushButton *b) const { 00358 QSize s = b->sizeHint(); 00359 const QSize ms = b->minimumSize(); 00360 if(s.width() < minButtonWidth) 00361 s.setWidth(minButtonWidth); 00362 00363 // allows the programmer to override the settings 00364 const int msWidth = ms.width(); 00365 const int msHeight = ms.height(); 00366 00367 if(msWidth > s.width()) 00368 s.setWidth(msWidth); 00369 if(msHeight > s.height()) 00370 s.setHeight(msHeight); 00371 00372 return s; 00373 } 00374 00375 void KButtonBox::virtual_hook( int, void* ) 00376 { /*BASE::virtual_hook( id, data );*/ } 00377