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

Applets

tabbar.cpp

Go to the documentation of this file.
00001 /*
00002     Copyright 2007 Robert Knight <robertknight@gmail.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 // Own
00021 #include "ui/tabbar.h"
00022 
00023 // KDE
00024 #include <KGlobalSettings>
00025 
00026 // Qt
00027 #include <QIcon>
00028 #include <QMouseEvent>
00029 #include <QPainter>
00030 
00031 #include <QGradient>
00032 #include <QLinearGradient>
00033 
00034 #include "plasma/plasma.h"
00035 #include "plasma/animator.h"
00036 
00037 using namespace Kickoff;
00038 
00039 TabBar::TabBar(QWidget *parent)
00040         : QTabBar(parent),
00041         m_hoveredTabIndex(-1),
00042         m_switchOnHover(true),
00043         m_animateSwitch(true)
00044 {
00045     m_lastIndex[0] = -1;
00046     connect(this, SIGNAL(currentChanged(int)), this, SLOT(startAnimation()));
00047 
00048     m_tabSwitchTimer.setSingleShot(true);
00049     connect(&m_tabSwitchTimer, SIGNAL(timeout()), this, SLOT(switchToHoveredTab()));
00050     setMouseTracking(true);
00051     setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
00052     setUsesScrollButtons( false );
00053 }
00054 
00055 void TabBar::setShape( Shape shape )
00056 {
00057   resize( 0, 0 );  // This is required, so that the custom implementation of tabSizeHint, 
00058                    // which expands the tabs to the full width of the widget does not pick up 
00059                    // the previous width, e.g. if the panel is moved from the bottom to the left
00060   QTabBar::setShape( shape );
00061 }
00062 
00063 void TabBar::setCurrentIndexWithoutAnimation(int index)
00064 {
00065     disconnect(this, SIGNAL(currentChanged(int)), this, SLOT(startAnimation()));
00066     setCurrentIndex(index);
00067     storeLastIndex();
00068     connect(this, SIGNAL(currentChanged(int)), this, SLOT(startAnimation()));
00069     animationFinished();
00070 }
00071 
00072 void TabBar::setSwitchTabsOnHover(bool switchOnHover)
00073 {
00074     m_switchOnHover = switchOnHover;
00075 }
00076 
00077 bool TabBar::switchTabsOnHover() const
00078 {
00079     return m_switchOnHover;
00080 }
00081 
00082 void TabBar::setAnimateSwitch(bool animateSwitch)
00083 {
00084     m_animateSwitch = animateSwitch;
00085 }
00086 
00087 bool TabBar::animateSwitch()
00088 {
00089     return m_animateSwitch;
00090 }
00091 
00092 QSize TabBar::tabSize(int index) const
00093 {
00094     QSize hint;
00095     const QFontMetrics metrics(KGlobalSettings::smallestReadableFont());
00096     const QSize textSize = metrics.size(Qt::TextHideMnemonic, tabText(index));
00097     hint.rwidth() = qMax(iconSize().width(), textSize.width());
00098     hint.rheight() = iconSize().height() + textSize.height();
00099     hint.rwidth() += 4 * TAB_CONTENTS_MARGIN;
00100     hint.rheight() += 2 * TAB_CONTENTS_MARGIN;
00101     return hint;
00102 }
00103 
00104 void TabBar::storeLastIndex()
00105 {
00106     // if first run
00107     if (m_lastIndex[0] == -1) {
00108         m_lastIndex[1] = currentIndex();
00109     }
00110     m_lastIndex[0] = m_lastIndex[1];
00111     m_lastIndex[1] = currentIndex();
00112 }
00113 
00114 int TabBar::lastIndex() const
00115 {
00116     return m_lastIndex[0];
00117 }
00118 
00119 QSize TabBar::tabSizeHint(int index) const
00120 {
00121     QSize hint = tabSize(index);
00122     int minwidth = 0;
00123     int minheight = 0;
00124 
00125     Shape s = shape();
00126     switch (s) {
00127         case RoundedSouth:
00128         case TriangularSouth:
00129         case RoundedNorth:
00130         case TriangularNorth:
00131             if (count() > 0) {
00132                 for (int i = count() - 1; i >= 0; i--) {
00133                     minwidth += tabSize(i).width();
00134                 }
00135                 if (minwidth < width()) {
00136                     hint.rwidth() += (width() - minwidth) / count();
00137                 }
00138             }
00139             break;
00140         case RoundedWest:
00141         case TriangularWest:
00142         case RoundedEast:
00143         case TriangularEast:
00144             if (count() > 0) {
00145                 for (int i = count() - 1; i >= 0; i--) {
00146                     minheight += tabSize(i).height();
00147                 }
00148                 if (minheight < height()) {
00149                     hint.rheight() += (height() - minheight) / count();
00150                 }
00151             }
00152             hint.rwidth() = qMax( hint.width(), width() );
00153             break;
00154     }
00155     return hint;
00156 }
00157 
00158 QPainterPath TabBar::tabPath(const QRect &_r)
00159 {
00160     const int radius = 6;
00161     Shape s = shape();
00162     QPainterPath path;
00163     QRect r = _r;
00164 
00165     switch (s) {
00166         case RoundedSouth:
00167         case TriangularSouth:
00168             r.adjust(0, 0, 0, -3);
00169             path.moveTo(rect().topLeft());
00170             path.lineTo(r.topLeft());
00171             // Top left corner
00172             path.quadTo(r.topLeft() + QPoint(radius, 0), r.topLeft() + QPoint(radius, radius));
00173             path.lineTo(r.bottomLeft() + QPoint(radius, -radius));
00174             // Bottom left corner
00175             path.quadTo(r.bottomLeft() + QPoint(radius, 0), r.bottomLeft() + QPoint(radius * 2, 0));
00176             path.lineTo(r.bottomRight() + QPoint(-radius * 2, 0));
00177             // Bottom right corner
00178             path.quadTo(r.bottomRight() + QPoint(-radius, 0), r.bottomRight() + QPoint(-radius, -radius));
00179             path.lineTo(r.topRight() + QPoint(-radius, radius));
00180             // Top right corner
00181             path.quadTo(r.topRight() + QPoint(-radius, 0), r.topRight());
00182             path.lineTo(rect().topRight());
00183             break;
00184         case RoundedNorth:
00185         case TriangularNorth:
00186             r.adjust(0, 3, 0, 0);
00187             path.moveTo(rect().bottomLeft());
00188             // Bottom left corner
00189             path.lineTo(r.bottomLeft());
00190             path.quadTo(r.bottomLeft() + QPoint(radius, 0), r.bottomLeft() + QPoint(radius, -radius));
00191             // Top left corner
00192             path.lineTo(r.topLeft() + QPoint(radius, radius));
00193             path.quadTo(r.topLeft() + QPoint(radius, 0), r.topLeft() + QPoint(radius * 2, 0));
00194             // Top right corner
00195             path.lineTo(r.topRight() + QPoint(-radius * 2, 0));
00196             path.quadTo(r.topRight() + QPoint(-radius, 0), r.topRight() + QPoint(-radius, radius));
00197             // Bottom right corner
00198             path.lineTo(r.bottomRight() + QPoint(-radius, -radius));
00199             path.quadTo(r.bottomRight() + QPoint(-radius, 0), r.bottomRight());
00200             path.lineTo(rect().bottomRight());
00201             break;
00202         case RoundedWest:
00203         case TriangularWest:
00204             r.adjust(3, 0, 0, 0);
00205             path.moveTo(rect().topRight());
00206             // Top right corner
00207             path.lineTo(r.topRight());
00208             path.quadTo(r.topRight() + QPoint(0, radius), r.topRight() + QPoint(-radius, radius));
00209             // Top left corner
00210             path.lineTo(r.topLeft() + QPoint(radius, radius));
00211             path.quadTo(r.topLeft() + QPoint(0, radius), r.topLeft() + QPoint(0, radius * 2));
00212             // Bottom left corner
00213             path.lineTo(r.bottomLeft() + QPoint(0, -radius * 2));
00214             path.quadTo(r.bottomLeft() + QPoint(0, -radius), r.bottomLeft() + QPoint(radius, -radius));
00215             // Bottom right corner
00216             path.lineTo(r.bottomRight() + QPoint(-radius, -radius));
00217             path.quadTo(r.bottomRight() + QPoint(0, -radius), r.bottomRight());
00218             path.lineTo(rect().bottomRight());
00219             break;
00220         case RoundedEast:
00221         case TriangularEast:
00222             r.adjust(0, 0, -3, 0);
00223             path.moveTo(rect().topLeft());
00224             // Top left corner
00225             path.lineTo(r.topLeft());
00226             path.quadTo(r.topLeft() + QPoint(0, radius), r.topLeft() + QPoint(radius, radius));
00227             // Top right corner
00228             path.lineTo(r.topRight() + QPoint(-radius, radius));
00229             path.quadTo(r.topRight() + QPoint(0, radius), r.topRight() + QPoint(0, radius * 2));
00230             // Bottom right corner
00231             path.lineTo(r.bottomRight() + QPoint(0, -radius * 2));
00232             path.quadTo(r.bottomRight() + QPoint(0, -radius), r.bottomRight() + QPoint(-radius, -radius));
00233             // Bottom left corner
00234             path.lineTo(r.bottomLeft() + QPoint(radius, -radius));
00235             path.quadTo(r.bottomLeft() + QPoint(0, -radius), r.bottomLeft());
00236             path.lineTo(rect().bottomLeft());
00237             break;
00238     }
00239 
00240     return path;
00241 }
00242 
00243 void TabBar::paintEvent(QPaintEvent *event)
00244 {
00245     Q_UNUSED(event)
00246     QPainter painter(this);
00247     //int numTabs = count();
00248     int currentTab = currentIndex();
00249     //bool ltr = painter.layoutDirection() == Qt::LeftToRight; // Not yet used
00250     painter.setFont(KGlobalSettings::smallestReadableFont());
00251 
00252     // Drawing Tabborders
00253     QRect movingRect;
00254 
00255     if (m_currentAnimRect.isNull()) {
00256         movingRect = tabRect(currentIndex());
00257     } else {
00258         movingRect = m_currentAnimRect;
00259     }
00260     QPainterPath path = tabPath(movingRect);
00261 
00262     painter.save();
00263     painter.setPen(QPen(palette().base(), 1));
00264 
00265     // Cover the disturbing line between the tabbar and the content area
00266     switch (shape()) {
00267       case RoundedSouth:
00268       case TriangularSouth:
00269         painter.drawLine(rect().topLeft(), rect().topRight());
00270         break;
00271       case RoundedNorth:
00272       case TriangularNorth:
00273         painter.drawLine(rect().bottomLeft(), rect().bottomRight());
00274         break;
00275       case RoundedWest:
00276       case TriangularWest:
00277         painter.drawLine(rect().topRight(), rect().bottomRight());
00278         break;
00279       case RoundedEast:
00280       case TriangularEast:
00281         painter.drawLine(rect().topLeft(), rect().bottomLeft());
00282         break;
00283     }
00284 
00285     painter.translate(0.5, 0.5);
00286     painter.setRenderHint(QPainter::Antialiasing);
00287     painter.fillPath(path, palette().base());
00288     painter.setPen(QPen(palette().mid(), 1));
00289     painter.drawPath(path);
00290     painter.restore();
00291 
00292     QFontMetrics metrics(painter.font());
00293     int textHeight = metrics.height();
00294 
00295     for (int i = 0; i < count(); i++) {
00296         QRect rect = tabRect(i).adjusted(TAB_CONTENTS_MARGIN, TAB_CONTENTS_MARGIN,
00297                                          -TAB_CONTENTS_MARGIN, -TAB_CONTENTS_MARGIN);
00298         // draw tab icon
00299         QRect iconRect = rect;
00300         iconRect.setBottom(iconRect.bottom() - textHeight);
00301         iconRect.adjust(0, (isVertical() ? 1 : 0) * TAB_CONTENTS_MARGIN + 3, 0, 0);
00302         tabIcon(i).paint(&painter, iconRect);
00303 
00304         // draw tab text
00305         QRect textRect = rect;
00306         textRect.setTop(textRect.bottom() - textHeight);
00307         painter.drawText(textRect, Qt::AlignCenter | Qt::TextHideMnemonic, tabText(i));
00308     }
00309 }
00310 
00311 void TabBar::leaveEvent(QEvent *event)
00312 {
00313     Q_UNUSED(event)
00314     m_hoveredTabIndex = -1;
00315 }
00316 
00317 void TabBar::mouseMoveEvent(QMouseEvent *event)
00318 {
00319     m_hoveredTabIndex = tabAt(event->pos());
00320     if (m_switchOnHover && m_hoveredTabIndex > -1 && m_hoveredTabIndex != currentIndex()) {
00321         m_tabSwitchTimer.stop();
00322         m_tabSwitchTimer.start(50);
00323     }
00324 }
00325 
00326 void TabBar::resizeEvent(QResizeEvent* event)
00327 {
00328     QTabBar::resizeEvent(event);
00329     m_currentAnimRect = tabRect(currentIndex());
00330     update();
00331 }
00332 
00333 void TabBar::switchToHoveredTab()
00334 {
00335     if (m_hoveredTabIndex < 0 || m_hoveredTabIndex == currentIndex()) {
00336         return;
00337     }
00338 
00339     if (m_animateSwitch) {
00340         setCurrentIndex(m_hoveredTabIndex);
00341     }
00342     else {
00343         setCurrentIndexWithoutAnimation(m_hoveredTabIndex);
00344     }
00345 }
00346 
00347 void TabBar::startAnimation()
00348 {
00349     storeLastIndex();
00350     Plasma::Animator::self()->customAnimation(10, 150, Plasma::Animator::EaseInOutCurve, this, "onValueChanged");
00351 
00352 }
00353 
00354 void TabBar::onValueChanged(qreal value)
00355 {
00356     if ((m_animProgress = value) == 1.0) {
00357         animationFinished();
00358         return;
00359     }
00360 
00361     // animation rect
00362     QRect rect = tabRect(currentIndex());
00363     QRect lastRect = tabRect(lastIndex());
00364     int x = isHorizontal() ? (int)(lastRect.x() - value * (lastRect.x() - rect.x())) : rect.x();
00365     int y = isHorizontal() ? rect.y() : (int)(lastRect.y() - value * (lastRect.y() - rect.y()));
00366     QSizeF sz = lastRect.size() - value * (lastRect.size() - rect.size());
00367     m_currentAnimRect = QRect(x, y, (int)(sz.width()), (int)(sz.height()));
00368     update();
00369 }
00370 
00371 void TabBar::animationFinished()
00372 {
00373     m_currentAnimRect = QRect();
00374     update();
00375 }
00376 
00377 bool TabBar::isVertical() const
00378 {
00379     Shape s = shape();
00380     if( s == RoundedWest ||
00381         s == RoundedEast ||
00382         s == TriangularWest ||
00383         s == TriangularEast ) {
00384         return true;
00385     }
00386     return false;
00387 }
00388 
00389 bool TabBar::isHorizontal() const
00390 {
00391   return !isVertical();
00392 }
00393 
00394 #include "tabbar.moc"

Applets

Skip menu "Applets"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
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