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