• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Plasma

nativetabbar.cpp

Go to the documentation of this file.
00001 /*
00002     Copyright 2007 Robert Knight <robertknight@gmail.com>
00003     Copyright 2008 Marco Martin <notmart@gmail.com>
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 */
00020 
00021 // Own
00022 #include "nativetabbar_p.h"
00023 
00024 // Qt
00025 #include <QIcon>
00026 #include <QMouseEvent>
00027 #include <QPainter>
00028 #include <QApplication>
00029 #include <QStyleOption>
00030 #include <QToolButton>
00031 
00032 #include <QGradient>
00033 #include <QLinearGradient>
00034 
00035 // KDE
00036 #include <kdebug.h>
00037 #include <kcolorutils.h>
00038 #include <kicon.h>
00039 #include <kiconloader.h>
00040 
00041 #include "plasma/plasma.h"
00042 #include "plasma/theme.h"
00043 #include "plasma/animator.h"
00044 #include "plasma/framesvg.h"
00045 #include "plasma/paintutils.h"
00046 
00047 //#include "private/style_p.h"
00048 
00049 namespace Plasma
00050 {
00051 
00052 class NativeTabBarPrivate
00053 {
00054 public:
00055     NativeTabBarPrivate(NativeTabBar *parent)
00056         : q(parent),
00057           shape(NativeTabBar::RoundedNorth),
00058           backgroundSvg(0),
00059           buttonSvg(0),
00060           closeIcon("window-close"),
00061           animationId(-1),
00062           mousePressOffset(0)
00063     {
00064     }
00065 
00066     ~NativeTabBarPrivate()
00067     {
00068         delete backgroundSvg;
00069         delete buttonSvg;
00070     }
00071 
00072     void syncBorders();
00073     void storeLastIndex();
00074 
00075     NativeTabBar *q;
00076     QTabBar::Shape shape; //used to keep track of shape() changes
00077     FrameSvg *backgroundSvg;
00078     qreal left, top, right, bottom;
00079     FrameSvg *buttonSvg;
00080     qreal buttonLeft, buttonTop, buttonRight, buttonBottom;
00081     KIcon closeIcon;
00082 
00083     int animationId;
00084 
00085     QRect currentAnimRect;
00086     QRect startAnimRect;
00087     int mousePressOffset;
00088     int lastIndex[2];
00089     qreal animProgress;
00090 };
00091 
00092 void NativeTabBarPrivate::syncBorders()
00093 {
00094     backgroundSvg->getMargins(left, top, right, bottom);
00095     buttonSvg->getMargins(buttonLeft, buttonTop, buttonRight, buttonBottom);
00096 }
00097 
00098 void NativeTabBarPrivate::storeLastIndex()
00099 {
00100     // if first run
00101     if (lastIndex[0] == -1) {
00102         lastIndex[1] = q->currentIndex();
00103     }
00104     lastIndex[0] = lastIndex[1];
00105     lastIndex[1] = q->currentIndex();
00106 }
00107 
00108 NativeTabBar::NativeTabBar(QWidget *parent)
00109         : KTabBar(parent),
00110           d(new NativeTabBarPrivate(this))
00111 {
00112     d->backgroundSvg = new Plasma::FrameSvg();
00113     d->backgroundSvg->setImagePath("widgets/frame");
00114     d->backgroundSvg->setElementPrefix("sunken");
00115 
00116     d->buttonSvg = new Plasma::FrameSvg();
00117     d->buttonSvg->setImagePath("widgets/button");
00118     d->buttonSvg->setElementPrefix("normal");
00119 
00120     d->syncBorders();
00121 
00122     d->lastIndex[0] = -1;
00123     connect(this, SIGNAL(currentChanged(int)), this, SLOT(startAnimation()));
00124 
00125     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00126 }
00127 
00128 NativeTabBar::~NativeTabBar()
00129 {
00130     delete d;
00131 }
00132 
00133 QRect NativeTabBar::tabRect(int index) const
00134 {
00135     QRect rect = KTabBar::tabRect(index).translated(d->left, d->top);
00136 
00137     if (isVertical()) {
00138         rect.setWidth(width() - d->left - d->right);
00139 
00140         if (index == count() - 1) {
00141             rect.adjust(0, 0, 0, -d->bottom);
00142         }
00143     } else {
00144         rect.setHeight(height() - d->top- d->bottom);
00145 
00146         if (index == count() - 1) {
00147             rect.adjust(0, 0, -d->right, 0);
00148         }
00149     }
00150 
00151     return rect;
00152 }
00153 
00154 int NativeTabBar::lastIndex() const
00155 {
00156     return d->lastIndex[0];
00157 }
00158 
00159 QSize NativeTabBar::tabSizeHint(int index) const
00160 {
00161     //return KTabBar::tabSizeHint(index);
00162     QSize hint = tabSize(index);
00163     int minwidth = 0;
00164     int minheight = 0;
00165     int maxwidth = 0;
00166 
00167     Shape s = shape();
00168     switch (s) {
00169         case RoundedSouth:
00170         case TriangularSouth:
00171         case RoundedNorth:
00172         case TriangularNorth:
00173             if (count() > 0) {
00174                 for (int i = count() - 1; i >= 0; i--) {
00175                     minwidth += tabSize(i).width();
00176                 }
00177 
00178                 if (minwidth < width() - d->left - d->right) {
00179                     hint.rwidth() += (width() - d->left - d->right - minwidth) / count();
00180                 }
00181             }
00182             break;
00183         case RoundedWest:
00184         case TriangularWest:
00185         case RoundedEast:
00186         case TriangularEast:
00187             if (count() > 0) {
00188                 for (int i = count() - 1; i >= 0; i--) {
00189                     minheight += tabSize(i).height();
00190                     if (tabSize(i).width() > maxwidth) {
00191                         maxwidth = tabSize(i).width();
00192                     }
00193                 }
00194 
00195                 if (minheight < height()) {
00196                     hint.rheight() += (height() - minheight) / count();
00197                 }
00198             }
00199             break;
00200     }
00201     return hint;
00202 }
00203 
00204 
00205 QSize NativeTabBar::sizeHint() const
00206 {
00207     return KTabBar::sizeHint();
00208 }
00209 
00210 void NativeTabBar::paintEvent(QPaintEvent *event)
00211 {
00212     if (!styleSheet().isNull()) {
00213         KTabBar::paintEvent(event);
00214         return;
00215     }
00216 
00217     QPainter painter(this);
00218     //int numTabs = count();
00219     //bool ltr = painter.layoutDirection() == Qt::LeftToRight; // Not yet used
00220 
00221     if (drawBase()) {
00222         d->backgroundSvg->paintFrame(&painter);
00223     }
00224 
00225     // Drawing Tabborders
00226     QRect movingRect;
00227 
00228     if (d->currentAnimRect.isNull()) {
00229         movingRect = tabRect(currentIndex());
00230     } else {
00231         movingRect = d->currentAnimRect;
00232     }
00233 
00234     //resizing here because in resizeevent the first time is invalid (still no tabs)
00235     d->buttonSvg->resizeFrame(movingRect.size());
00236     d->buttonSvg->paintFrame(&painter, movingRect.topLeft());
00237 
00238     QFontMetrics metrics(painter.font());
00239 
00240     for (int i = 0; i < count(); ++i) {
00241         QRect rect = tabRect(i).adjusted(d->buttonLeft, d->buttonTop,
00242                                          -d->buttonRight, -d->buttonBottom);
00243         // draw tab icon
00244         QRect iconRect = QRect(rect.x(), rect.y(), iconSize().width(), iconSize().height());
00245 
00246         iconRect.moveCenter(QPoint(iconRect.center().x(), rect.center().y()));
00247         tabIcon(i).paint(&painter, iconRect);
00248 
00249         // draw tab text
00250         if (i == currentIndex() && d->animProgress == 1) {
00251             painter.setPen(Plasma::Theme::defaultTheme()->color(Theme::ButtonTextColor));
00252         } else {
00253             QColor color(Plasma::Theme::defaultTheme()->color(Theme::TextColor));
00254             if (!isTabEnabled(i)) {
00255                 color.setAlpha(140);
00256             }
00257 
00258             painter.setPen(color);
00259         }
00260         QRect textRect = rect;
00261 
00262         if (!tabIcon(i).isNull()) {
00263             textRect.setLeft(iconRect.right());
00264         }
00265 
00266         painter.setFont(Plasma::Theme::defaultTheme()->font(Plasma::Theme::DefaultFont));
00267         painter.drawText(textRect, Qt::AlignCenter | Qt::TextHideMnemonic, tabText(i));
00268 
00269         if (isCloseButtonEnabled()) {
00270             d->closeIcon.paint(&painter, QRect(closeButtonPos(i), QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall)) );
00271         }
00272     }
00273 
00274 
00275     QRect scrollButtonsRect;
00276     foreach (QObject *child, children()) {
00277         QToolButton *childWidget = qobject_cast<QToolButton *>(child);
00278         if (childWidget) {
00279             if (!childWidget->isVisible()) {
00280                 continue;
00281             }
00282 
00283             if (scrollButtonsRect.isValid()) {
00284                 scrollButtonsRect = scrollButtonsRect.united(childWidget->geometry());
00285             } else {
00286                 scrollButtonsRect = childWidget->geometry();
00287             }
00288         }
00289     }
00290 
00291     if (scrollButtonsRect.isValid()) {
00292         scrollButtonsRect.adjust(2, 4, -2, -4);
00293         painter.save();
00294 
00295         QColor background(Plasma::Theme::defaultTheme()->color(Theme::BackgroundColor));
00296         background.setAlphaF(0.75);
00297 
00298         painter.setRenderHint(QPainter::Antialiasing);
00299         painter.fillPath(PaintUtils::roundedRectangle(scrollButtonsRect, 5), background);
00300         painter.restore();
00301 
00302         QStyleOption so;
00303         so.initFrom(this);
00304         so.palette.setColor(QPalette::ButtonText,
00305                             Plasma::Theme::defaultTheme()->color(Theme::TextColor));
00306 
00307         so.rect = scrollButtonsRect.adjusted(0, 0, -scrollButtonsRect.width() / 2, 0);
00308         style()->drawPrimitive(QStyle::PE_IndicatorArrowLeft, &so, &painter, this);
00309 
00310         so.rect = scrollButtonsRect.adjusted(scrollButtonsRect.width() / 2, 0, 0, 0);
00311         style()->drawPrimitive(QStyle::PE_IndicatorArrowRight, &so, &painter, this);
00312     }
00313 }
00314 
00315 void NativeTabBar::resizeEvent(QResizeEvent *event)
00316 {
00317     KTabBar::resizeEvent(event);
00318     d->currentAnimRect = tabRect(currentIndex());
00319     d->backgroundSvg->resizeFrame(size());
00320     d->syncBorders();
00321 
00322     update();
00323 }
00324 
00325 void NativeTabBar::tabInserted(int index)
00326 {
00327     KTabBar::tabInserted(index);
00328     emit sizeHintChanged();
00329 }
00330 
00331 void NativeTabBar::tabRemoved(int index)
00332 {
00333     KTabBar::tabRemoved(index);
00334     emit sizeHintChanged();
00335 }
00336 
00337 void NativeTabBar::tabLayoutChange()
00338 {
00339     KTabBar::tabLayoutChange();
00340 
00341     if (shape() != d->shape) {
00342         d->shape = shape();
00343         emit shapeChanged(d->shape);
00344     }
00345 }
00346 
00347 void NativeTabBar::startAnimation()
00348 {
00349     d->storeLastIndex();
00350     Plasma::Animator::self()->customAnimation(
00351         10, 150, Plasma::Animator::EaseInOutCurve, this, "onValueChanged");
00352 }
00353 
00354 void NativeTabBar::onValueChanged(qreal value)
00355 {
00356     if ((d->animProgress = value) == 1.0) {
00357         animationFinished();
00358         return;
00359     }
00360 
00361     // animation rect
00362     QRect rect = tabRect(currentIndex());
00363     QRect lastRect = d->startAnimRect.isNull() ? tabRect(lastIndex())
00364                                                : d->startAnimRect;
00365     int x = isHorizontal() ? (int)(lastRect.x() - value * (lastRect.x() - rect.x())) : rect.x();
00366     int y = isHorizontal() ? rect.y() : (int)(lastRect.y() - value * (lastRect.y() - rect.y()));
00367     QSizeF sz = lastRect.size() - value * (lastRect.size() - rect.size());
00368     d->currentAnimRect = QRect(x, y, (int)(sz.width()), (int)(sz.height()));
00369     update();
00370 }
00371 
00372 void NativeTabBar::animationFinished()
00373 {
00374     d->startAnimRect = QRect();
00375     d->currentAnimRect = QRect();
00376     update();
00377 }
00378 
00379 bool NativeTabBar::isVertical() const
00380 {
00381     Shape s = shape();
00382     if(s == RoundedWest ||
00383        s == RoundedEast ||
00384        s == TriangularWest ||
00385        s == TriangularEast) {
00386         return true;
00387     }
00388     return false;
00389 }
00390 
00391 bool NativeTabBar::isHorizontal() const
00392 {
00393     return !isVertical();
00394 }
00395 
00396 QSize NativeTabBar::tabSize(int index) const
00397 {
00398     QSize hint;
00399     const QFontMetrics metrics(QApplication::font());
00400     const QSize textSize = metrics.size(Qt::TextHideMnemonic, tabText(index));
00401     hint.rwidth() = textSize.width() + iconSize().width();
00402     hint.rheight() = qMax(iconSize().height(), textSize.height());
00403     hint.rwidth() += d->buttonLeft + d->buttonRight;
00404     hint.rheight() += d->buttonTop + d->buttonBottom;
00405 
00406     if (isVertical()) {
00407         hint.rwidth() = qMax(hint.width(), int(minimumWidth() - d->left - d->right));
00408     } else {
00409         hint.rheight() = qMax(hint.height(), int(minimumHeight() - d->top - d->bottom));
00410     }
00411 
00412     return hint;
00413 }
00414 
00415 //Unfortunately copied from KTabBar
00416 QPoint NativeTabBar::closeButtonPos( int tabIndex ) const
00417 {
00418   QPoint buttonPos;
00419   if ( tabIndex < 0 ) {
00420     return buttonPos;
00421   }
00422 
00423   int availableHeight = height();
00424   if ( tabIndex == currentIndex() ) {
00425     QStyleOption option;
00426     option.initFrom(this);
00427     availableHeight -= style()->pixelMetric( QStyle::PM_TabBarTabShiftVertical, &option, this );
00428   }
00429 
00430   const QRect tabBounds = tabRect( tabIndex );
00431   const int xInc = (height() - KIconLoader::SizeSmall) / 2;
00432 
00433   if ( layoutDirection() == Qt::RightToLeft ) {
00434     buttonPos = tabBounds.topLeft();
00435     buttonPos.rx() += xInc;
00436   } else {
00437     buttonPos = tabBounds.topRight();
00438     buttonPos.rx() -= KIconLoader::SizeSmall + xInc;
00439   }
00440   buttonPos.ry() += (availableHeight - KIconLoader::SizeSmall) / 2;
00441 
00442   return buttonPos;
00443 }
00444 
00445 void NativeTabBar::mousePressEvent(QMouseEvent *event)
00446 {
00447     if (d->currentAnimRect.isNull()) {
00448         QRect rect = tabRect(currentIndex());
00449 
00450         if (rect.contains(event->pos())) {
00451             d->mousePressOffset = event->pos().x();
00452             event->accept();
00453             return;
00454         }
00455     }
00456 
00457     KTabBar::mousePressEvent(event);
00458 }
00459 
00460 void NativeTabBar::mouseMoveEvent(QMouseEvent *event)
00461 {
00462     if (d->mousePressOffset) {
00463         d->currentAnimRect = tabRect(currentIndex());
00464 
00465         int pos = qBound(0, d->currentAnimRect.left() + (event->pos().x() - d->mousePressOffset),
00466                          width() - d->currentAnimRect.width());
00467         d->currentAnimRect.moveLeft(pos);
00468         update();
00469     } else {
00470         KTabBar::mouseMoveEvent(event);
00471     }
00472 }
00473 
00474 void NativeTabBar::mouseReleaseEvent(QMouseEvent *event)
00475 {
00476     if (d->mousePressOffset) {
00477         bool left = event->pos().x() - d->mousePressOffset < 0;
00478         int index = tabAt(QPoint(left ? d->currentAnimRect.left() : d->currentAnimRect.right(), 1));
00479         d->mousePressOffset = 0;
00480 
00481         if (index != currentIndex() && isTabEnabled(index)) {
00482             d->startAnimRect = d->currentAnimRect;
00483             setCurrentIndex(index);
00484         } else {
00485             d->currentAnimRect = QRect();
00486         }
00487 
00488         update();
00489     } else {
00490         KTabBar::mouseReleaseEvent(event);
00491     }
00492 }
00493 
00494 void NativeTabBar::wheelEvent(QWheelEvent *event)
00495 {
00496     if (underMouse()) {
00497         //Cycle tabs with the circular array tecnique
00498         if (event->delta() < 0) {
00499             int index = currentIndex();
00500             //search for an enabled tab
00501             for (int i = 0; i < count()-1; ++i) {
00502                 index = (index + 1) % count();
00503                 if (isTabEnabled(index)) {
00504                     break;
00505                 }
00506             }
00507 
00508             setCurrentIndex(index);
00509         } else {
00510             int index = currentIndex();
00511             for (int i = 0; i < count()-1; ++i) {
00512                 index = (count() + index -1) % count();
00513                 if (isTabEnabled(index)) {
00514                     break;
00515                 }
00516             }
00517 
00518             setCurrentIndex(index);
00519         }
00520     } else {
00521         QTabBar::wheelEvent(event);
00522     }
00523 }
00524 
00525 } // namespace Plasma
00526 
00527 #include "nativetabbar_p.moc"
00528 

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal