KDEUI
kmultitabbar.cpp
Go to the documentation of this file.
00001 /*************************************************************************** 00002 kmultitabbar.cpp - description 00003 ------------------- 00004 begin : 2001 00005 copyright : (C) 2001,2002,2003 by Joseph Wenninger <jowenn@kde.org> 00006 ***************************************************************************/ 00007 00008 /*************************************************************************** 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Library General Public 00011 License as published by the Free Software Foundation; either 00012 version 2 of the License, or (at your option) any later version. 00013 00014 This library is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 Library General Public License for more details. 00018 00019 You should have received a copy of the GNU Library General Public License 00020 along with this library; see the file COPYING.LIB. If not, write to 00021 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00022 Boston, MA 02110-1301, USA. 00023 ***************************************************************************/ 00024 00025 #include "kmultitabbar.h" 00026 #include "kmultitabbar_p.h" 00027 #include "kmultitabbar.moc" 00028 #include "kmultitabbar_p.moc" 00029 00030 #include <QtGui/QActionEvent> 00031 #include <QtGui/QLayout> 00032 #include <QtGui/QPainter> 00033 #include <QtGui/QFontMetrics> 00034 #include <QtGui/QStyle> 00035 #include <QStyleOptionButton> 00036 00037 #include <kiconloader.h> 00038 #include <kdebug.h> 00039 #include <QtGui/QApplication> 00040 #include <math.h> 00041 00049 class KMultiTabBarPrivate 00050 { 00051 public: 00052 class KMultiTabBarInternal *m_internal; 00053 QBoxLayout *m_l; 00054 QFrame *m_btnTabSep; 00055 QList<KMultiTabBarButton*> m_buttons; 00056 KMultiTabBar::KMultiTabBarPosition m_position; 00057 }; 00058 00059 00060 KMultiTabBarInternal::KMultiTabBarInternal(QWidget *parent, KMultiTabBar::KMultiTabBarPosition pos):QFrame(parent) 00061 { 00062 m_position = pos; 00063 if (pos == KMultiTabBar::Left || pos == KMultiTabBar::Right) 00064 mainLayout=new QVBoxLayout(this); 00065 else 00066 mainLayout=new QHBoxLayout(this); 00067 mainLayout->setMargin(0); 00068 mainLayout->setSpacing(0); 00069 mainLayout->addStretch(); 00070 setFrameStyle(NoFrame); 00071 setBackgroundRole(QPalette::Background); 00072 } 00073 00074 KMultiTabBarInternal::~KMultiTabBarInternal() 00075 { 00076 qDeleteAll(m_tabs); 00077 m_tabs.clear(); 00078 } 00079 00080 void KMultiTabBarInternal::setStyle(enum KMultiTabBar::KMultiTabBarStyle style) 00081 { 00082 m_style=style; 00083 for (int i=0;i<m_tabs.count();i++) 00084 m_tabs.at(i)->setStyle(m_style); 00085 00086 updateGeometry(); 00087 } 00088 00089 void KMultiTabBarInternal::contentsMousePressEvent(QMouseEvent *ev) 00090 { 00091 ev->ignore(); 00092 } 00093 00094 void KMultiTabBarInternal::mousePressEvent(QMouseEvent *ev) 00095 { 00096 ev->ignore(); 00097 } 00098 00099 KMultiTabBarTab* KMultiTabBarInternal::tab(int id) const 00100 { 00101 QListIterator<KMultiTabBarTab*> it(m_tabs); 00102 while (it.hasNext()) { 00103 KMultiTabBarTab *tab = it.next(); 00104 if (tab->id()==id) return tab; 00105 } 00106 return 0; 00107 } 00108 00109 int KMultiTabBarInternal::appendTab(const QPixmap &pic, int id, const QString& text) 00110 { 00111 KMultiTabBarTab *tab; 00112 m_tabs.append(tab= new KMultiTabBarTab(pic,text,id,this,m_position,m_style)); 00113 00114 // Insert before the stretch.. 00115 mainLayout->insertWidget(m_tabs.size()-1, tab); 00116 tab->show(); 00117 return 0; 00118 } 00119 00120 void KMultiTabBarInternal::removeTab(int id) 00121 { 00122 for (int pos=0;pos<m_tabs.count();pos++) 00123 { 00124 if (m_tabs.at(pos)->id()==id) 00125 { 00126 // remove & delete the tab 00127 delete m_tabs.takeAt(pos); 00128 break; 00129 } 00130 } 00131 } 00132 00133 void KMultiTabBarInternal::setPosition(enum KMultiTabBar::KMultiTabBarPosition pos) 00134 { 00135 m_position=pos; 00136 for (int i=0;i<m_tabs.count();i++) 00137 m_tabs.at(i)->setPosition(m_position); 00138 updateGeometry(); 00139 } 00140 00141 // KMultiTabBarButton 00143 00144 KMultiTabBarButton::KMultiTabBarButton(const QPixmap& pic, const QString& text, 00145 int id, QWidget *parent) 00146 : QPushButton(QIcon(pic), text, parent), m_id(id), d(0) 00147 { 00148 connect(this,SIGNAL(clicked()),this,SLOT(slotClicked())); 00149 00150 // we can't see the focus, so don't take focus. #45557 00151 // If keyboard navigation is wanted, then only the bar should take focus, 00152 // and arrows could change the focused button; but generally, tabbars don't take focus anyway. 00153 setFocusPolicy(Qt::NoFocus); 00154 } 00155 00156 KMultiTabBarButton::~KMultiTabBarButton() 00157 { 00158 } 00159 00160 void KMultiTabBarButton::setText(const QString &text) 00161 { 00162 QPushButton::setText(text); 00163 } 00164 00165 void KMultiTabBarButton::slotClicked() 00166 { 00167 updateGeometry(); 00168 emit clicked(m_id); 00169 } 00170 00171 int KMultiTabBarButton::id() const 00172 { 00173 return m_id; 00174 } 00175 00176 void KMultiTabBarButton::hideEvent( QHideEvent* he) { 00177 QPushButton::hideEvent(he); 00178 KMultiTabBar *tb=dynamic_cast<KMultiTabBar*>(parentWidget()); 00179 if (tb) tb->updateSeparator(); 00180 } 00181 00182 void KMultiTabBarButton::showEvent( QShowEvent* he) { 00183 QPushButton::showEvent(he); 00184 KMultiTabBar *tb=dynamic_cast<KMultiTabBar*>(parentWidget()); 00185 if (tb) tb->updateSeparator(); 00186 } 00187 00188 void KMultiTabBarButton::paintEvent(QPaintEvent *) { 00189 QStyleOptionButton opt; 00190 opt.initFrom(this); 00191 opt.icon = icon(); 00192 opt.iconSize = iconSize(); 00193 // removes the QStyleOptionButton::HasMenu ButtonFeature 00194 opt.features = QStyleOptionButton::Flat; 00195 QPainter painter(this); 00196 style()->drawControl(QStyle::CE_PushButton, &opt, &painter, this); 00197 } 00198 00199 // KMultiTabBarTab 00201 00202 KMultiTabBarTab::KMultiTabBarTab(const QPixmap& pic, const QString& text, 00203 int id, QWidget *parent, 00204 KMultiTabBar::KMultiTabBarPosition pos, 00205 KMultiTabBar::KMultiTabBarStyle style) 00206 : KMultiTabBarButton(pic, text, id, parent), m_style(style), d(0) 00207 { 00208 m_position=pos; 00209 setToolTip(text); 00210 setCheckable(true); 00211 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); 00212 // shrink down to icon only, but prefer to show text if it's there 00213 } 00214 00215 KMultiTabBarTab::~KMultiTabBarTab() 00216 { 00217 } 00218 00219 void KMultiTabBarTab::setPosition(KMultiTabBar::KMultiTabBarPosition pos) 00220 { 00221 m_position=pos; 00222 updateGeometry(); 00223 } 00224 00225 void KMultiTabBarTab::setStyle(KMultiTabBar::KMultiTabBarStyle style) 00226 { 00227 m_style=style; 00228 updateGeometry(); 00229 } 00230 00231 QPixmap KMultiTabBarTab::iconPixmap() const 00232 { 00233 int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this); 00234 return icon().pixmap(iconSize); 00235 } 00236 00237 void KMultiTabBarTab::initStyleOption(QStyleOptionToolButton* opt) const 00238 { 00239 opt->initFrom(this); 00240 00241 // Setup icon.. 00242 if (!icon().isNull()) { 00243 opt->iconSize = iconPixmap().size(); 00244 opt->icon = icon(); 00245 } 00246 00247 // Should we draw text? 00248 if (shouldDrawText()) 00249 opt->text = text(); 00250 00251 if (underMouse()) 00252 opt->state |= QStyle::State_AutoRaise | QStyle::State_MouseOver | QStyle::State_Raised; 00253 00254 if (isChecked()) 00255 opt->state |= QStyle::State_Sunken | QStyle::State_On; 00256 00257 opt->font = font(); 00258 opt->toolButtonStyle = shouldDrawText() ? Qt::ToolButtonTextBesideIcon : Qt::ToolButtonIconOnly; 00259 opt->subControls = QStyle::SC_ToolButton; 00260 } 00261 00262 QSize KMultiTabBarTab::sizeHint() const 00263 { 00264 return computeSizeHint(shouldDrawText()); 00265 } 00266 00267 QSize KMultiTabBarTab::minimumSizeHint() const 00268 { 00269 return computeSizeHint(false); 00270 } 00271 00272 void KMultiTabBarTab::computeMargins(int* hMargin, int* vMargin) const 00273 { 00274 // Unfortunately, QStyle does not give us enough information to figure out 00275 // where to place things, so we try to reverse-engineer it 00276 QStyleOptionToolButton opt; 00277 initStyleOption(&opt); 00278 00279 QPixmap iconPix = iconPixmap(); 00280 QSize trialSize = iconPix.size(); 00281 QSize expandSize = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, trialSize, this); 00282 00283 *hMargin = (expandSize.width() - trialSize.width())/2; 00284 *vMargin = (expandSize.height() - trialSize.height())/2; 00285 } 00286 00287 QSize KMultiTabBarTab::computeSizeHint(bool withText) const 00288 { 00289 // Compute as horizontal first, then flip around if need be. 00290 QStyleOptionToolButton opt; 00291 initStyleOption(&opt); 00292 00293 int hMargin, vMargin; 00294 computeMargins(&hMargin, &vMargin); 00295 00296 // Compute interior size, starting from pixmap.. 00297 QPixmap iconPix = iconPixmap(); 00298 QSize size = iconPix.size(); 00299 00300 // Always include text height in computation, to avoid resizing the minor direction 00301 // when expanding text.. 00302 QSize textSize = fontMetrics().size(Qt::TextShowMnemonic, text()); 00303 size.setHeight(qMax(size.height(), textSize.height())); 00304 00305 // Pick margins for major/minor direction, depending on orientation 00306 int majorMargin = isVertical() ? vMargin : hMargin; 00307 int minorMargin = isVertical() ? hMargin : vMargin; 00308 00309 size.setWidth (size.width() + 2*majorMargin); 00310 size.setHeight(size.height() + 2*minorMargin); 00311 00312 if (withText) 00313 // Add enough room for the text, and an extra major margin. 00314 size.setWidth(size.width() + textSize.width() + majorMargin); 00315 00316 // flip time? 00317 if (isVertical()) 00318 return QSize(size.height(), size.width()); 00319 else 00320 return size; 00321 } 00322 00323 void KMultiTabBarTab::setState(bool newState) 00324 { 00325 setChecked(newState); 00326 updateGeometry(); 00327 } 00328 00329 void KMultiTabBarTab::setIcon(const QString& icon) 00330 { 00331 QPixmap pic=SmallIcon(icon); 00332 setIcon(pic); 00333 } 00334 00335 void KMultiTabBarTab::setIcon(const QPixmap& icon) 00336 { 00337 QPushButton::setIcon(icon); 00338 } 00339 00340 bool KMultiTabBarTab::shouldDrawText() const 00341 { 00342 return (m_style==KMultiTabBar::KDEV3ICON) || isChecked(); 00343 } 00344 00345 bool KMultiTabBarTab::isVertical() const 00346 { 00347 return m_position==KMultiTabBar::Right || m_position==KMultiTabBar::Left; 00348 } 00349 00350 void KMultiTabBarTab::paintEvent(QPaintEvent*) { 00351 QPainter painter(this); 00352 00353 QStyleOptionToolButton opt; 00354 initStyleOption(&opt); 00355 00356 // Paint bevel.. 00357 if (underMouse() || isChecked()) { 00358 opt.text.clear(); 00359 opt.icon = QIcon(); 00360 style()->drawComplexControl(QStyle::CC_ToolButton, &opt, &painter, this); 00361 } 00362 00363 int hMargin, vMargin; 00364 computeMargins(&hMargin, &vMargin); 00365 00366 // We first figure out how much room we have for the text, based on 00367 // icon size and margin, try to fit in by eliding, and perhaps 00368 // give up on drawing the text entirely if we're too short on room 00369 QPixmap icon = iconPixmap(); 00370 int textRoom = 0; 00371 int iconRoom = 0; 00372 00373 QString t; 00374 if (shouldDrawText()) { 00375 if (isVertical()) { 00376 iconRoom = icon.height() + 2*vMargin; 00377 textRoom = height() - iconRoom - vMargin; 00378 } else { 00379 iconRoom = icon.width() + 2*hMargin; 00380 textRoom = width() - iconRoom - hMargin; 00381 } 00382 00383 t = painter.fontMetrics().elidedText(text(), Qt::ElideRight, textRoom); 00384 00385 // See whether anything is left. Qt will return either 00386 // ... or the ellipsis unicode character, 0x2026 00387 if (t == QLatin1String("...") || t == QChar(0x2026)) 00388 t.clear(); 00389 } 00390 00391 // Label time.... Simple case: no text, so just plop down the icon right in the center 00392 // We only do this when the button never draws the text, to avoid jumps in icon position 00393 // when resizing 00394 if (!shouldDrawText()) { 00395 style()->drawItemPixmap(&painter, rect(), Qt::AlignCenter | Qt::AlignVCenter, icon); 00396 return; 00397 } 00398 00399 // Now where the icon/text goes depends on text direction and tab position 00400 QRect iconArea; 00401 QRect labelArea; 00402 00403 bool bottomIcon = false; 00404 bool rtl = layoutDirection() == Qt::RightToLeft; 00405 if (isVertical()) { 00406 if (m_position == KMultiTabBar::Left && !rtl) 00407 bottomIcon = true; 00408 if (m_position == KMultiTabBar::Right && rtl) 00409 bottomIcon = true; 00410 } 00411 //alignFlags = Qt::AlignLeading | Qt::AlignVCenter; 00412 00413 if (isVertical()) { 00414 if (bottomIcon) { 00415 labelArea = QRect(0, vMargin, width(), textRoom); 00416 iconArea = QRect(0, vMargin + textRoom, width(), iconRoom); 00417 } else { 00418 labelArea = QRect(0, iconRoom, width(), textRoom); 00419 iconArea = QRect(0, 0, width(), iconRoom); 00420 } 00421 } else { 00422 // Pretty simple --- depends only on RTL/LTR 00423 if (rtl) { 00424 labelArea = QRect(hMargin, 0, textRoom, height()); 00425 iconArea = QRect(hMargin + textRoom, 0, iconRoom, height()); 00426 } else { 00427 labelArea = QRect(iconRoom, 0, textRoom, height()); 00428 iconArea = QRect(0, 0, iconRoom, height()); 00429 } 00430 } 00431 00432 style()->drawItemPixmap(&painter, iconArea, Qt::AlignCenter | Qt::AlignVCenter, icon); 00433 00434 if (t.isEmpty()) 00435 return; 00436 00437 QRect labelPaintArea = labelArea; 00438 00439 if (isVertical()) { 00440 // If we're vertical, we paint to a simple 0,0 origin rect, 00441 // and get the transformations to get us in the right place 00442 labelPaintArea = QRect(0, 0, labelArea.height(), labelArea.width()); 00443 00444 QTransform tr; 00445 00446 if (bottomIcon) { 00447 tr.translate(labelArea.x(), labelPaintArea.width() + labelArea.y()); 00448 tr.rotate(-90); 00449 } else { 00450 tr.translate(labelPaintArea.height() + labelArea.x(), labelArea.y()); 00451 tr.rotate(90); 00452 } 00453 painter.setTransform(tr); 00454 } 00455 00456 style()->drawItemText(&painter, labelPaintArea, Qt::AlignLeading | Qt::AlignVCenter, 00457 palette(), true, t, QPalette::ButtonText); 00458 } 00459 00460 // KMultiTabBar 00462 00463 KMultiTabBar::KMultiTabBar(KMultiTabBarPosition pos, QWidget *parent) 00464 : QWidget(parent), 00465 d(new KMultiTabBarPrivate) 00466 { 00467 if (pos == Left || pos == Right) 00468 { 00469 d->m_l=new QVBoxLayout(this); 00470 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding/*, true*/); 00471 } 00472 else 00473 { 00474 d->m_l=new QHBoxLayout(this); 00475 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed/*, true*/); 00476 } 00477 d->m_l->setMargin(0); 00478 d->m_l->setSpacing(0); 00479 00480 d->m_internal=new KMultiTabBarInternal(this, pos); 00481 setPosition(pos); 00482 setStyle(VSNET); 00483 d->m_l->insertWidget(0,d->m_internal); 00484 d->m_l->insertWidget(0,d->m_btnTabSep=new QFrame(this)); 00485 d->m_btnTabSep->setFixedHeight(4); 00486 d->m_btnTabSep->setFrameStyle(QFrame::Panel | QFrame::Sunken); 00487 d->m_btnTabSep->setLineWidth(2); 00488 d->m_btnTabSep->hide(); 00489 00490 updateGeometry(); 00491 } 00492 00493 KMultiTabBar::~KMultiTabBar() 00494 { 00495 qDeleteAll( d->m_buttons ); 00496 d->m_buttons.clear(); 00497 delete d; 00498 } 00499 00500 int KMultiTabBar::appendButton(const QPixmap &pic, int id, QMenu *popup, const QString&) 00501 { 00502 KMultiTabBarButton *btn = new KMultiTabBarButton(pic, QString(), id, this); 00503 // a button with a QMenu can have another size. Make sure the button has always the same size. 00504 btn->setFixedWidth(btn->height()); 00505 btn->setMenu(popup); 00506 d->m_buttons.append(btn); 00507 d->m_l->insertWidget(0,btn); 00508 btn->show(); 00509 d->m_btnTabSep->show(); 00510 return 0; 00511 } 00512 00513 void KMultiTabBar::updateSeparator() { 00514 bool hideSep=true; 00515 QListIterator<KMultiTabBarButton*> it(d->m_buttons); 00516 while (it.hasNext()){ 00517 if (it.next()->isVisibleTo(this)) { 00518 hideSep=false; 00519 break; 00520 } 00521 } 00522 if (hideSep) 00523 d->m_btnTabSep->hide(); 00524 else 00525 d->m_btnTabSep->show(); 00526 } 00527 00528 int KMultiTabBar::appendTab(const QPixmap &pic, int id, const QString& text) 00529 { 00530 d->m_internal->appendTab(pic,id,text); 00531 return 0; 00532 } 00533 00534 KMultiTabBarButton* KMultiTabBar::button(int id) const 00535 { 00536 QListIterator<KMultiTabBarButton*> it(d->m_buttons); 00537 while ( it.hasNext() ) { 00538 KMultiTabBarButton *button = it.next(); 00539 if ( button->id() == id ) 00540 return button; 00541 } 00542 00543 return 0; 00544 } 00545 00546 KMultiTabBarTab* KMultiTabBar::tab(int id) const 00547 { 00548 return d->m_internal->tab(id); 00549 } 00550 00551 void KMultiTabBar::removeButton(int id) 00552 { 00553 for (int pos=0;pos<d->m_buttons.count();pos++) 00554 { 00555 if (d->m_buttons.at(pos)->id()==id) 00556 { 00557 d->m_buttons.takeAt(pos)->deleteLater(); 00558 break; 00559 } 00560 } 00561 00562 if (d->m_buttons.count()==0) 00563 d->m_btnTabSep->hide(); 00564 } 00565 00566 void KMultiTabBar::removeTab(int id) 00567 { 00568 d->m_internal->removeTab(id); 00569 } 00570 00571 void KMultiTabBar::setTab(int id,bool state) 00572 { 00573 KMultiTabBarTab *ttab=tab(id); 00574 if (ttab) 00575 ttab->setState(state); 00576 } 00577 00578 bool KMultiTabBar::isTabRaised(int id) const 00579 { 00580 KMultiTabBarTab *ttab=tab(id); 00581 if (ttab) 00582 return ttab->isChecked(); 00583 00584 return false; 00585 } 00586 00587 void KMultiTabBar::setStyle(KMultiTabBarStyle style) 00588 { 00589 d->m_internal->setStyle(style); 00590 } 00591 00592 KMultiTabBar::KMultiTabBarStyle KMultiTabBar::tabStyle() const 00593 { 00594 return d->m_internal->m_style; 00595 } 00596 00597 void KMultiTabBar::setPosition(KMultiTabBarPosition pos) 00598 { 00599 d->m_position=pos; 00600 d->m_internal->setPosition(pos); 00601 } 00602 00603 KMultiTabBar::KMultiTabBarPosition KMultiTabBar::position() const 00604 { 00605 return d->m_position; 00606 } 00607 00608 void KMultiTabBar::fontChange(const QFont& /* oldFont */) 00609 { 00610 updateGeometry(); 00611 } 00612 00613 // vim: ts=4 sw=4 noet 00614 // kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
KDE 4.6 API Reference