2 Copyright 2007 Robert Knight <robertknight@gmail.com>
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
21 #include "ui/tabbar.h"
24 #include <KGlobalSettings>
25 #include <KColorScheme>
29 #include <QMouseEvent>
33 #include <QLinearGradient>
35 #include <Plasma/Plasma>
36 #include <Plasma/Animator>
37 #include <Plasma/Theme>
38 #include <Plasma/FrameSvg>
40 using namespace Kickoff
;
42 TabBar::TabBar(QWidget
*parent
)
44 m_hoveredTabIndex(-1),
45 m_switchOnHover(true),
46 m_animateSwitch(true),
50 connect(this, SIGNAL(currentChanged(int)), this, SLOT(startAnimation()));
52 m_tabSwitchTimer
.setSingleShot(true);
53 connect(&m_tabSwitchTimer
, SIGNAL(timeout()), this, SLOT(switchToHoveredTab()));
54 setMouseTracking(true);
55 setSizePolicy(QSizePolicy::Preferred
, QSizePolicy::Preferred
);
56 setUsesScrollButtons(false);
58 background
= new Plasma::FrameSvg(this);
59 background
->setImagePath("dialogs/kickoff");
60 background
->setEnabledBorders(
61 Plasma::FrameSvg::BottomBorder
|
62 Plasma::FrameSvg::LeftBorder
|
63 Plasma::FrameSvg::RightBorder
65 background
->resizeFrame(size());
66 background
->setElementPrefix("plain");
68 connect(background
, SIGNAL(repaintNeeded()), this, SLOT(update()));
71 void TabBar::setShape(Shape shape
)
73 resize(0, 0); // This is required, so that the custom implementation of tabSizeHint,
74 // which expands the tabs to the full width of the widget does not pick up
75 // the previous width, e.g. if the panel is moved from the bottom to the left
76 QTabBar::setShape(shape
);
80 void TabBar::setCurrentIndexWithoutAnimation(int index
)
82 disconnect(this, SIGNAL(currentChanged(int)), this, SLOT(startAnimation()));
83 setCurrentIndex(index
);
85 connect(this, SIGNAL(currentChanged(int)), this, SLOT(startAnimation()));
89 void TabBar::setSwitchTabsOnHover(bool switchOnHover
)
91 m_switchOnHover
= switchOnHover
;
94 bool TabBar::switchTabsOnHover() const
96 return m_switchOnHover
;
99 void TabBar::setAnimateSwitch(bool animateSwitch
)
101 m_animateSwitch
= animateSwitch
;
104 bool TabBar::animateSwitch()
106 return m_animateSwitch
;
109 QSize
TabBar::tabSize(int index
) const
112 const QFontMetrics
metrics(KGlobalSettings::smallestReadableFont());
113 const QSize textSize
= metrics
.size(Qt::TextHideMnemonic
, tabText(index
));
114 hint
.rwidth() = qMax(iconSize().width(), textSize
.width());
115 hint
.rheight() = iconSize().height() + textSize
.height();
116 hint
.rwidth() += 4 * TAB_CONTENTS_MARGIN
;
117 hint
.rheight() += 2 * TAB_CONTENTS_MARGIN
;
121 void TabBar::storeLastIndex()
124 if (m_lastIndex
[0] == -1) {
125 m_lastIndex
[1] = currentIndex();
127 m_lastIndex
[0] = m_lastIndex
[1];
128 m_lastIndex
[1] = currentIndex();
131 int TabBar::lastIndex() const
133 return m_lastIndex
[0];
136 QSize
TabBar::tabSizeHint(int index
) const
138 QSize hint
= tabSize(index
);
145 case TriangularSouth
:
147 case TriangularNorth
:
149 for (int i
= count() - 1; i
>= 0; i
--) {
150 minwidth
+= tabSize(i
).width();
152 if (minwidth
< width()) {
153 hint
.rwidth() += (width() - minwidth
) / count();
162 for (int i
= count() - 1; i
>= 0; i
--) {
163 minheight
+= tabSize(i
).height();
165 if (minheight
< height()) {
166 hint
.rheight() += (height() - minheight
) / count();
169 hint
.rwidth() = qMax(hint
.width(), width());
175 QSize
TabBar::sizeHint() const
181 for (int i
= count() - 1; i
>= 0; i
--) {
182 height
+= tabSize(i
).height();
185 width
= tabSize(0).width();
187 for (int i
= count() - 1; i
>= 0; i
--) {
188 width
+= tabSize(i
).width();
191 height
= tabSize(0).height();
193 return QSize(width
, height
);
196 QPainterPath
TabBar::tabPath(const QRect
&_r
)
198 const int radius
= 6;
205 case TriangularSouth
:
206 r
.adjust(0, 0, 0, -3);
207 path
.moveTo(r
.topLeft());
209 path
.quadTo(r
.topLeft() + QPoint(radius
, 0), r
.topLeft() + QPoint(radius
, radius
));
210 path
.lineTo(r
.bottomLeft() + QPoint(radius
, -radius
));
211 // Bottom left corner
212 path
.quadTo(r
.bottomLeft() + QPoint(radius
, 0), r
.bottomLeft() + QPoint(radius
* 2, 0));
213 path
.lineTo(r
.bottomRight() + QPoint(-radius
* 2, 0));
214 // Bottom right corner
215 path
.quadTo(r
.bottomRight() + QPoint(-radius
, 0), r
.bottomRight() + QPoint(-radius
, -radius
));
216 path
.lineTo(r
.topRight() + QPoint(-radius
, radius
));
218 path
.quadTo(r
.topRight() + QPoint(-radius
, 0), r
.topRight());
221 case TriangularNorth
:
222 r
.adjust(0, 3, 0, 1);
223 path
.moveTo(r
.bottomLeft());
224 // Bottom left corner
225 path
.quadTo(r
.bottomLeft() + QPoint(radius
, 0), r
.bottomLeft() + QPoint(radius
, -radius
));
227 path
.lineTo(r
.topLeft() + QPoint(radius
, radius
));
228 path
.quadTo(r
.topLeft() + QPoint(radius
, 0), r
.topLeft() + QPoint(radius
* 2, 0));
230 path
.lineTo(r
.topRight() + QPoint(-radius
* 2, 0));
231 path
.quadTo(r
.topRight() + QPoint(-radius
, 0), r
.topRight() + QPoint(-radius
, radius
));
232 // Bottom right corner
233 path
.lineTo(r
.bottomRight() + QPoint(-radius
, -radius
));
234 path
.quadTo(r
.bottomRight() + QPoint(-radius
, 0), r
.bottomRight());
238 r
.adjust(3, 0, 1, 0);
239 path
.moveTo(r
.topRight());
241 path
.lineTo(r
.topRight());
242 path
.quadTo(r
.topRight() + QPoint(0, radius
), r
.topRight() + QPoint(-radius
, radius
));
244 path
.lineTo(r
.topLeft() + QPoint(radius
, radius
));
245 path
.quadTo(r
.topLeft() + QPoint(0, radius
), r
.topLeft() + QPoint(0, radius
* 2));
246 // Bottom left corner
247 path
.lineTo(r
.bottomLeft() + QPoint(0, -radius
* 2));
248 path
.quadTo(r
.bottomLeft() + QPoint(0, -radius
), r
.bottomLeft() + QPoint(radius
, -radius
));
249 // Bottom right corner
250 path
.lineTo(r
.bottomRight() + QPoint(-radius
, -radius
));
251 path
.quadTo(r
.bottomRight() + QPoint(0, -radius
), r
.bottomRight());
255 r
.adjust(0, 0, -3, 0);
256 path
.moveTo(r
.topLeft());
258 path
.quadTo(r
.topLeft() + QPoint(0, radius
), r
.topLeft() + QPoint(radius
, radius
));
260 path
.lineTo(r
.topRight() + QPoint(-radius
, radius
));
261 path
.quadTo(r
.topRight() + QPoint(0, radius
), r
.topRight() + QPoint(0, radius
* 2));
262 // Bottom right corner
263 path
.lineTo(r
.bottomRight() + QPoint(0, -radius
* 2));
264 path
.quadTo(r
.bottomRight() + QPoint(0, -radius
), r
.bottomRight() + QPoint(-radius
, -radius
));
265 // Bottom left corner
266 path
.lineTo(r
.bottomLeft() + QPoint(radius
, -radius
));
267 path
.quadTo(r
.bottomLeft() + QPoint(0, -radius
), r
.bottomLeft());
274 void TabBar::paintEvent(QPaintEvent
*event
)
277 QPainter
painter(this);
278 //int numTabs = count();
279 int currentTab
= currentIndex();
281 background
->paintFrame(&painter
);
283 //bool ltr = painter.layoutDirection() == Qt::LeftToRight; // Not yet used
284 painter
.setFont(KGlobalSettings::smallestReadableFont());
286 // Drawing Tabborders
289 if (m_currentAnimRect
.isNull()) {
290 movingRect
= tabRect(currentIndex());
292 movingRect
= m_currentAnimRect
;
294 QPainterPath path
= tabPath(movingRect
);
297 painter
.setPen(QPen(palette().base(), 1));
299 painter
.setRenderHint(QPainter::Antialiasing
);
300 painter
.fillPath(path
, palette().base());
304 QFontMetrics
metrics(painter
.font());
305 int textHeight
= metrics
.height();
307 for (int i
= 0; i
< count(); i
++) {
308 QRect rect
= tabRect(i
).adjusted(TAB_CONTENTS_MARGIN
, TAB_CONTENTS_MARGIN
,
309 -TAB_CONTENTS_MARGIN
, -TAB_CONTENTS_MARGIN
);
311 QRect iconRect
= rect
;
312 iconRect
.setBottom(iconRect
.bottom() - textHeight
);
313 iconRect
.adjust(0, (isVertical() ? 1 : 0) * TAB_CONTENTS_MARGIN
+ 3, 0, 0);
314 tabIcon(i
).paint(&painter
, iconRect
);
317 if (i
!= currentTab
|| m_animProgress
< 0.9) {
318 //painter.setPen(QPen(KColorScheme(QPalette::Active).foreground(KColorScheme::InactiveText), 0));
319 painter
.setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor
));
321 painter
.setPen(QPen(KColorScheme(QPalette::Active
).foreground(KColorScheme::NormalText
), 0));
323 QRect textRect
= rect
;
324 textRect
.setTop(textRect
.bottom() - textHeight
);
325 painter
.drawText(textRect
, Qt::AlignCenter
| Qt::TextHideMnemonic
, tabText(i
));
329 void TabBar::leaveEvent(QEvent
*event
)
332 m_hoveredTabIndex
= -1;
335 void TabBar::mouseMoveEvent(QMouseEvent
*event
)
337 m_hoveredTabIndex
= tabAt(event
->pos());
338 if (m_switchOnHover
&& m_hoveredTabIndex
> -1 && m_hoveredTabIndex
!= currentIndex()) {
339 m_tabSwitchTimer
.stop();
340 m_tabSwitchTimer
.start(50);
344 void TabBar::resizeEvent(QResizeEvent
* event
)
346 QTabBar::resizeEvent(event
);
347 m_currentAnimRect
= tabRect(currentIndex());
349 background
->resizeFrame(event
->size());
354 void TabBar::switchToHoveredTab()
356 if (m_hoveredTabIndex
< 0 || m_hoveredTabIndex
== currentIndex()) {
360 if (m_animateSwitch
) {
361 setCurrentIndex(m_hoveredTabIndex
);
363 setCurrentIndexWithoutAnimation(m_hoveredTabIndex
);
367 void TabBar::startAnimation()
370 Plasma::Animator::self()->customAnimation(10, 150, Plasma::Animator::EaseInOutCurve
, this, "onValueChanged");
374 void TabBar::onValueChanged(qreal value
)
376 if ((m_animProgress
= value
) == 1.0) {
382 QRect rect
= tabRect(currentIndex());
383 QRect lastRect
= tabRect(lastIndex());
384 int x
= isHorizontal() ? (int)(lastRect
.x() - value
* (lastRect
.x() - rect
.x())) : rect
.x();
385 int y
= isHorizontal() ? rect
.y() : (int)(lastRect
.y() - value
* (lastRect
.y() - rect
.y()));
386 QSizeF sz
= lastRect
.size() - value
* (lastRect
.size() - rect
.size());
387 m_currentAnimRect
= QRect(x
, y
, (int)(sz
.width()), (int)(sz
.height()));
391 void TabBar::animationFinished()
393 m_currentAnimRect
= QRect();
397 bool TabBar::isVertical() const
400 if (s
== RoundedWest
||
402 s
== TriangularWest
||
403 s
== TriangularEast
) {
409 bool TabBar::isHorizontal() const
411 return !isVertical();
414 #include "tabbar.moc"