00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "nativetabbar_p.h"
00023
00024
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
00036 #include <kdebug.h>
00037 #include <kcolorutils.h>
00038
00039 #include "plasma/plasma.h"
00040 #include "plasma/theme.h"
00041 #include "plasma/animator.h"
00042 #include "plasma/framesvg.h"
00043 #include "plasma/paintutils.h"
00044
00045
00046
00047 namespace Plasma
00048 {
00049
00050 class NativeTabBarPrivate
00051 {
00052 public:
00053 NativeTabBarPrivate(NativeTabBar *parent)
00054 : q(parent),
00055 backgroundSvg(0),
00056 buttonSvg(0),
00057 animationId(-1)
00058 {
00059 }
00060
00061 ~NativeTabBarPrivate()
00062 {
00063 delete backgroundSvg;
00064 delete buttonSvg;
00065 }
00066
00067 void syncBorders();
00068 void storeLastIndex();
00069
00070 NativeTabBar *q;
00071 QTabBar::Shape shape;
00072 FrameSvg *backgroundSvg;
00073 qreal left, top, right, bottom;
00074 FrameSvg *buttonSvg;
00075 qreal buttonLeft, buttonTop, buttonRight, buttonBottom;
00076
00077 int animationId;
00078
00079 QRect currentAnimRect;
00080 int lastIndex[2];
00081 qreal animProgress;
00082 };
00083
00084 void NativeTabBarPrivate::syncBorders()
00085 {
00086 backgroundSvg->getMargins(left, top, right, bottom);
00087 buttonSvg->getMargins(buttonLeft, buttonTop, buttonRight, buttonBottom);
00088 }
00089
00090 void NativeTabBarPrivate::storeLastIndex()
00091 {
00092
00093 if (lastIndex[0] == -1) {
00094 lastIndex[1] = q->currentIndex();
00095 }
00096 lastIndex[0] = lastIndex[1];
00097 lastIndex[1] = q->currentIndex();
00098 }
00099
00100 NativeTabBar::NativeTabBar(QWidget *parent)
00101 : KTabBar(parent),
00102 d(new NativeTabBarPrivate(this))
00103 {
00104 d->backgroundSvg = new Plasma::FrameSvg();
00105 d->backgroundSvg->setImagePath("widgets/frame");
00106 d->backgroundSvg->setElementPrefix("sunken");
00107
00108 d->buttonSvg = new Plasma::FrameSvg();
00109 d->buttonSvg->setImagePath("widgets/button");
00110 d->buttonSvg->setElementPrefix("normal");
00111
00112 d->syncBorders();
00113
00114 d->lastIndex[0] = -1;
00115 connect(this, SIGNAL(currentChanged(int)), this, SLOT(startAnimation()));
00116
00117 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
00118 }
00119
00120 NativeTabBar::~NativeTabBar()
00121 {
00122 delete d;
00123 }
00124
00125 QRect NativeTabBar::tabRect(int index) const
00126 {
00127 QRect rect = KTabBar::tabRect(index).translated(d->left, d->top);
00128
00129 return rect;
00130 }
00131
00132 int NativeTabBar::lastIndex() const
00133 {
00134 return d->lastIndex[0];
00135 }
00136
00137 QSize NativeTabBar::tabSizeHint(int index) const
00138 {
00139
00140 QSize hint = tabSize(index);
00141 int minwidth = 0;
00142 int minheight = 0;
00143 int maxwidth = 0;
00144
00145 Shape s = shape();
00146 switch (s) {
00147 case RoundedSouth:
00148 case TriangularSouth:
00149 case RoundedNorth:
00150 case TriangularNorth:
00151 if (count() > 0) {
00152 for (int i = count() - 1; i >= 0; i--) {
00153 minwidth += tabSize(i).width();
00154 }
00155
00156 if (minwidth < width() - d->left - d->right) {
00157 hint.rwidth() += (width() - d->left - d->right - minwidth) / count();
00158 }
00159 }
00160 break;
00161 case RoundedWest:
00162 case TriangularWest:
00163 case RoundedEast:
00164 case TriangularEast:
00165 if (count() > 0) {
00166 for (int i = count() - 1; i >= 0; i--) {
00167 minheight += tabSize(i).height();
00168 if (tabSize(i).width() > maxwidth) {
00169 maxwidth = tabSize(i).width();
00170 }
00171 }
00172
00173 if (minheight < height()) {
00174 hint.rheight() += (height() - minheight) / count();
00175 }
00176 }
00177 break;
00178 }
00179 return hint;
00180 }
00181
00182
00183 QSize NativeTabBar::sizeHint() const
00184 {
00185 int width = 0;
00186 int height = 0;
00187
00188 if (isVertical()) {
00189 for (int i = count() - 1; i >= 0; i--) {
00190 height += tabRect(i).height();
00191 }
00192
00193 width = tabRect(0).width();
00194 } else {
00195 for (int i = count() - 1; i >= 0; i--) {
00196 width += tabRect(i).width();
00197 }
00198
00199 height = tabRect(0).height();
00200 }
00201 return QSize(width + d->left + d->right, height + d->top + d->bottom);
00202 }
00203
00204 void NativeTabBar::paintEvent(QPaintEvent *event)
00205 {
00206 if (!styleSheet().isNull()) {
00207 KTabBar::paintEvent(event);
00208 return;
00209 }
00210
00211 QPainter painter(this);
00212
00213
00214
00215 if (drawBase()) {
00216 d->backgroundSvg->paintFrame(&painter);
00217 }
00218
00219
00220 QRect movingRect;
00221
00222 if (d->currentAnimRect.isNull()) {
00223 movingRect = tabRect(currentIndex());
00224 } else {
00225 movingRect = d->currentAnimRect;
00226 }
00227
00228
00229 d->buttonSvg->resizeFrame(movingRect.size());
00230 d->buttonSvg->paintFrame(&painter, movingRect.topLeft());
00231
00232 QFontMetrics metrics(painter.font());
00233
00234 for (int i = 0; i < count(); i++) {
00235 QRect rect = tabRect(i).adjusted(d->buttonLeft, d->buttonTop,
00236 -d->buttonRight, -d->buttonBottom);
00237
00238 QRect iconRect = QRect(rect.x(), rect.y(), iconSize().width(), iconSize().height());
00239
00240 iconRect.moveCenter(QPoint(iconRect.center().x(), rect.center().y()));
00241 tabIcon(i).paint(&painter, iconRect);
00242
00243
00244 if (i == currentIndex() && d->animProgress == 1) {
00245 painter.setPen(Plasma::Theme::defaultTheme()->color(Theme::ButtonTextColor));
00246 } else {
00247 QColor color(Plasma::Theme::defaultTheme()->color(Theme::TextColor));
00248 if (!isTabEnabled(i)) {
00249 color.setAlpha(140);
00250 }
00251
00252 painter.setPen(color);
00253 }
00254 QRect textRect = rect;
00255
00256 if (!tabIcon(i).isNull()) {
00257 textRect.setLeft(iconRect.right());
00258 }
00259
00260 painter.setFont(Plasma::Theme::defaultTheme()->font(Plasma::Theme::DefaultFont));
00261 painter.drawText(textRect, Qt::AlignCenter | Qt::TextHideMnemonic, tabText(i));
00262 }
00263
00264 QRect scrollButtonsRect;
00265 foreach (QObject *child, children()) {
00266 QToolButton *childWidget = qobject_cast<QToolButton *>(child);
00267 if (childWidget) {
00268 if (!childWidget->isVisible()) {
00269 continue;
00270 }
00271
00272 if (scrollButtonsRect.isValid()) {
00273 scrollButtonsRect = scrollButtonsRect.united(childWidget->geometry());
00274 } else {
00275 scrollButtonsRect = childWidget->geometry();
00276 }
00277 }
00278 }
00279
00280 if (scrollButtonsRect.isValid()) {
00281 scrollButtonsRect.adjust(2, 4, -2, -4);
00282 painter.save();
00283
00284 QColor background(Plasma::Theme::defaultTheme()->color(Theme::BackgroundColor));
00285 background.setAlphaF(0.75);
00286
00287 painter.setRenderHint(QPainter::Antialiasing);
00288 painter.fillPath(PaintUtils::roundedRectangle(scrollButtonsRect, 5), background);
00289 painter.restore();
00290
00291 QStyleOption so;
00292 so.initFrom(this);
00293 so.palette.setColor(QPalette::ButtonText,
00294 Plasma::Theme::defaultTheme()->color(Theme::TextColor));
00295
00296 so.rect = scrollButtonsRect.adjusted(0, 0, -scrollButtonsRect.width() / 2, 0);
00297 style()->drawPrimitive(QStyle::PE_IndicatorArrowLeft, &so, &painter, this);
00298
00299 so.rect = scrollButtonsRect.adjusted(scrollButtonsRect.width() / 2, 0, 0, 0);
00300 style()->drawPrimitive(QStyle::PE_IndicatorArrowRight, &so, &painter, this);
00301 }
00302 }
00303
00304 void NativeTabBar::resizeEvent(QResizeEvent *event)
00305 {
00306 KTabBar::resizeEvent(event);
00307 d->currentAnimRect = tabRect(currentIndex());
00308 d->backgroundSvg->resizeFrame(size());
00309
00310 update();
00311 }
00312
00313 void NativeTabBar::tabInserted(int index)
00314 {
00315 KTabBar::tabInserted(index);
00316 emit sizeHintChanged();
00317 }
00318
00319 void NativeTabBar::tabRemoved(int index)
00320 {
00321 KTabBar::tabRemoved(index);
00322 emit sizeHintChanged();
00323 }
00324
00325 void NativeTabBar::tabLayoutChange()
00326 {
00327 KTabBar::tabLayoutChange();
00328
00329 if (shape() != d->shape) {
00330 d->shape = shape();
00331 emit shapeChanged(d->shape);
00332 }
00333 }
00334
00335 void NativeTabBar::startAnimation()
00336 {
00337 d->storeLastIndex();
00338 Plasma::Animator::self()->customAnimation(
00339 10, 150, Plasma::Animator::EaseInOutCurve, this, "onValueChanged");
00340 }
00341
00342 void NativeTabBar::onValueChanged(qreal value)
00343 {
00344 if ((d->animProgress = value) == 1.0) {
00345 animationFinished();
00346 return;
00347 }
00348
00349
00350 QRect rect = tabRect(currentIndex());
00351 QRect lastRect = tabRect(lastIndex());
00352 int x = isHorizontal() ? (int)(lastRect.x() - value * (lastRect.x() - rect.x())) : rect.x();
00353 int y = isHorizontal() ? rect.y() : (int)(lastRect.y() - value * (lastRect.y() - rect.y()));
00354 QSizeF sz = lastRect.size() - value * (lastRect.size() - rect.size());
00355 d->currentAnimRect = QRect(x, y, (int)(sz.width()), (int)(sz.height()));
00356 update();
00357 }
00358
00359 void NativeTabBar::animationFinished()
00360 {
00361 d->currentAnimRect = QRect();
00362 update();
00363 }
00364
00365 bool NativeTabBar::isVertical() const
00366 {
00367 Shape s = shape();
00368 if(s == RoundedWest ||
00369 s == RoundedEast ||
00370 s == TriangularWest ||
00371 s == TriangularEast) {
00372 return true;
00373 }
00374 return false;
00375 }
00376
00377 bool NativeTabBar::isHorizontal() const
00378 {
00379 return !isVertical();
00380 }
00381
00382 QSize NativeTabBar::tabSize(int index) const
00383 {
00384 QSize hint;
00385 const QFontMetrics metrics(QApplication::font());
00386 const QSize textSize = metrics.size(Qt::TextHideMnemonic, tabText(index));
00387 hint.rwidth() = textSize.width() + iconSize().width();
00388 hint.rheight() = qMax(iconSize().height(), textSize.height());
00389 hint.rwidth() += d->buttonLeft + d->buttonRight;
00390 hint.rheight() += d->buttonTop + d->buttonBottom;
00391
00392 if (isVertical()) {
00393 hint.rwidth() = qMax(hint.width(), int(minimumWidth() - d->left - d->right));
00394 } else {
00395 hint.rheight() = qMax(hint.height(), int(minimumHeight() - d->top - d->bottom));
00396 }
00397
00398 return hint;
00399 }
00400
00401 }
00402
00403 #include "nativetabbar_p.moc"
00404