File indexing completed on 2024-05-12 16:35:47
0001 /* This file is part of the KDE project 0002 Copyright (C) 2003 Ariya Hidayat <ariya@kde.org> 0003 Copyright (C) 2003 Norbert Andres <nandres@web.de> 0004 Copyright (C) 2002 Laurent Montel <montel@kde.org> 0005 Copyright (C) 1999 David Faure <faure@kde.org> 0006 Copyright (C) 1999 Boris Wedl <boris.wedl@kfunigraz.ac.at> 0007 Copyright (C) 1998-2000 Torben Weis <weis@kde.org> 0008 0009 This library is free software; you can redistribute it and/or 0010 modify it under the terms of the GNU Library General Public 0011 License as published by the Free Software Foundation; either 0012 version 2 of the License, or (at your option) any later version. 0013 0014 This library is distributed in the hope that it will be useful, 0015 but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0017 Library General Public License for more details. 0018 0019 You should have received a copy of the GNU Library General Public License 0020 along with this library; see the file COPYING.LIB. If not, write to 0021 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0022 * Boston, MA 02110-1301, USA. 0023 */ 0024 0025 #include "TabBar.h" 0026 0027 #include <QList> 0028 #include <QMouseEvent> 0029 #include <QPaintEvent> 0030 #include <QPainter> 0031 #include <QPolygon> 0032 #include <QPixmap> 0033 #include <QResizeEvent> 0034 #include <QString> 0035 #include <QStringList> 0036 #include <QStyle> 0037 #include <QTimer> 0038 #include <QToolButton> 0039 #include <QWidget> 0040 #include <QWheelEvent> 0041 #include <QFontDatabase> 0042 0043 // TODO 0044 // improvement possibilities 0045 // - use offscreen buffer to reduce flicker even more 0046 // - keep track of tabs, only (re)layout when necessary 0047 // - paint all tabs to buffer, show only by shifting 0048 // - customizable button pixmaps 0049 // - use QStyle to paint the tabs & buttons (is it good/possible?) 0050 0051 namespace Calligra 0052 { 0053 namespace Sheets 0054 { 0055 0056 class TabBarPrivate 0057 { 0058 public: 0059 TabBar* tabbar; 0060 0061 // scroll buttons 0062 QToolButton* scrollFirstButton; 0063 QToolButton* scrollLastButton; 0064 QToolButton* scrollBackButton; 0065 QToolButton* scrollForwardButton; 0066 0067 // read-only: no mouse drag, double-click, right-click 0068 bool readOnly; 0069 0070 // list of all tabs, in order of appearance 0071 QStringList tabs; 0072 0073 // array of QRect for each visible tabs 0074 QList<QRect> tabRects; 0075 0076 // leftmost tab (or rightmost for right-to-left layouts) 0077 int firstTab; 0078 0079 // rightmost tab (or leftmost for right-to-left layouts) 0080 int lastTab; 0081 0082 // the active tab in the range form 1..n. 0083 // if this value is 0, that means that no tab is active. 0084 int activeTab; 0085 0086 // unusable space on the left, taken by the scroll buttons 0087 int offset; 0088 0089 // when the user drag the tab (in order to move it) 0090 // this is the target position, it's 0 if no tab is dragged 0091 int targetTab; 0092 0093 // wheel movement since selected tab was last changed by the 0094 // mouse wheel 0095 int wheelDelta; 0096 0097 // true if autoscroll is active 0098 bool autoScroll; 0099 0100 // calculate the bounding rectangle for each visible tab 0101 void layoutTabs(); 0102 0103 // reposition scroll buttons 0104 void layoutButtons(); 0105 0106 // find a tab whose bounding rectangle contains the pos 0107 // return -1 if no such tab is found 0108 int tabAt(const QPoint& pos); 0109 0110 // draw a single tab 0111 void drawTab(QPainter& painter, QRect& rect, const QString& text, bool active); 0112 0113 // draw a marker to indicate tab moving 0114 void drawMoveMarker(QPainter& painter, int x, int y); 0115 0116 // update the enable/disable status of scroll buttons 0117 void updateButtons(); 0118 0119 // get the font to use on the tabs 0120 QFont font(bool selected); 0121 }; 0122 0123 // built-in pixmap for scroll-first button 0124 static const char * const arrow_leftmost_xpm[] = { 0125 "10 10 2 1", 0126 " c None", 0127 ". c #000000", 0128 " ", 0129 " . . ", 0130 " . .. ", 0131 " . ... ", 0132 " . .... ", 0133 " . ... ", 0134 " . .. ", 0135 " . . ", 0136 " ", 0137 " " 0138 }; 0139 0140 // built-in pixmap for scroll-last button 0141 static const char * const arrow_rightmost_xpm[] = { 0142 "10 10 2 1", 0143 " c None", 0144 ". c #000000", 0145 " ", 0146 " . . ", 0147 " .. . ", 0148 " ... . ", 0149 " .... . ", 0150 " ... . ", 0151 " .. . ", 0152 " . . ", 0153 " ", 0154 " " 0155 }; 0156 0157 // built-in pixmap for scroll-left button 0158 static const char * const arrow_left_xpm[] = { 0159 "10 10 2 1", 0160 " c None", 0161 ". c #000000", 0162 " ", 0163 " . ", 0164 " .. ", 0165 " ... ", 0166 " .... ", 0167 " ... ", 0168 " .. ", 0169 " . ", 0170 " ", 0171 " " 0172 }; 0173 0174 // built-in pixmap for scroll-right button 0175 static const char * const arrow_right_xpm[] = { 0176 "10 10 2 1", 0177 " c None", 0178 ". c #000000", 0179 " ", 0180 " . ", 0181 " .. ", 0182 " ... ", 0183 " .... ", 0184 " ... ", 0185 " .. ", 0186 " . ", 0187 " ", 0188 " " 0189 }; 0190 0191 0192 void TabBarPrivate::layoutTabs() 0193 { 0194 tabRects.clear(); 0195 0196 QFont f = font(true); 0197 QFontMetrics fm(f, tabbar); 0198 if (tabbar->isLeftToRight()) { 0199 // left to right 0200 int x = 0; 0201 for (int c = 0; c < tabs.count(); c++) { 0202 QRect rect; 0203 if (c >= firstTab - 1) { 0204 QString text = tabs[ c ]; 0205 int tw = fm.width(text) + 4; 0206 rect = QRect(x, 0, tw + 20, tabbar->height()); 0207 x = x + tw + 20; 0208 } 0209 tabRects.append(rect); 0210 } 0211 0212 lastTab = tabRects.count(); 0213 for (int i = 0; i < tabRects.count(); i++) 0214 if (tabRects[i].right() - 10 + offset > tabbar->width()) { 0215 lastTab = i; 0216 break; 0217 } 0218 } else { 0219 // right to left 0220 int x = tabbar->width() - offset; 0221 for (int c = 0; c < tabs.count(); c++) { 0222 QRect rect; 0223 if (c >= firstTab - 1) { 0224 QString text = tabs[ c ]; 0225 int tw = fm.width(text) + 4; 0226 rect = QRect(x - tw - 20, 0, tw + 20, tabbar->height()); 0227 x = x - tw - 20; 0228 } 0229 tabRects.append(rect); 0230 } 0231 0232 lastTab = tabRects.count(); 0233 for (int i = tabRects.count() - 1; i > 0; i--) 0234 if (tabRects[i].left() > 0) { 0235 lastTab = i + 1; 0236 break; 0237 } 0238 } 0239 tabbar->updateGeometry(); 0240 } 0241 0242 int TabBarPrivate::tabAt(const QPoint& pos) 0243 { 0244 for (int i = 0; i < tabRects.count(); i++) { 0245 QRect rect = tabRects[ i ]; 0246 if (rect.isNull()) continue; 0247 if (rect.contains(pos)) return i; 0248 } 0249 0250 return -1; // not found 0251 } 0252 0253 void TabBarPrivate::drawTab(QPainter& painter, QRect& rect, const QString& text, bool active) 0254 { 0255 QPolygon polygon; 0256 0257 if (tabbar->isLeftToRight()) 0258 polygon << QPoint(rect.x(), rect.y()) 0259 << QPoint(rect.x(), rect.bottom() - 3) 0260 << QPoint(rect.x() + 2, rect.bottom()) 0261 << QPoint(rect.right() - 4, rect.bottom()) 0262 << QPoint(rect.right() - 2, rect.bottom() - 2) 0263 << QPoint(rect.right() + 5, rect.top()); 0264 else 0265 polygon << QPoint(rect.right(), rect.top()) 0266 << QPoint(rect.right(), rect.bottom() - 3) 0267 << QPoint(rect.right() - 2, rect.bottom()) 0268 << QPoint(rect.x() + 4, rect.bottom()) 0269 << QPoint(rect.x() + 2, rect.bottom() - 2) 0270 << QPoint(rect.x() - 5, rect.top()); 0271 0272 painter.save(); 0273 0274 // fill it first 0275 QBrush bg = tabbar->palette().background(); 0276 if (active) 0277 bg = tabbar->palette().base(); 0278 painter.setBrush(bg); 0279 painter.setPen(QPen(Qt::NoPen)); 0280 painter.drawPolygon(polygon); 0281 0282 // draw the lines 0283 painter.setPen(QPen(tabbar->palette().color(QPalette::Dark), 0)); 0284 painter.setRenderHint(QPainter::Antialiasing); 0285 if (!active) { 0286 const bool reverseLayout = tabbar->isRightToLeft(); 0287 painter.drawLine(rect.x() - (reverseLayout ? 5 : 0), rect.y(), 0288 rect.right() + (reverseLayout ? 0 : 5), rect.top()); 0289 } 0290 0291 painter.drawPolyline(polygon); 0292 0293 painter.setPen(tabbar->palette().color(QPalette::ButtonText)); 0294 QFont f = font(active); 0295 painter.setFont(f); 0296 QFontMetrics fm = painter.fontMetrics(); 0297 int tx = rect.x() + (rect.width() - fm.width(text)) / 2; 0298 int ty = rect.y() + (rect.height() - fm.height()) / 2 + fm.ascent(); 0299 painter.drawText(tx, ty, text); 0300 0301 painter.restore(); 0302 } 0303 0304 void TabBarPrivate::drawMoveMarker(QPainter& painter, int x, int y) 0305 { 0306 QPolygon movmark; 0307 0308 movmark << QPoint(x, y) << QPoint(x + 7, y) << QPoint(x + 4, y + 6); 0309 QBrush oldBrush = painter.brush(); 0310 painter.setBrush(Qt::black); 0311 painter.drawPolygon(movmark); 0312 painter.setBrush(oldBrush); 0313 } 0314 0315 void TabBarPrivate::layoutButtons() 0316 { 0317 int bw = tabbar->height(); 0318 int w = tabbar->width(); 0319 offset = bw * 4; 0320 0321 if (tabbar->isLeftToRight()) { 0322 scrollFirstButton->setGeometry(0, 0, bw, bw); 0323 scrollFirstButton->setIcon(QIcon(QPixmap(arrow_leftmost_xpm))); 0324 scrollBackButton->setGeometry(bw, 0, bw, bw); 0325 scrollBackButton->setIcon(QIcon(QPixmap(arrow_left_xpm))); 0326 scrollForwardButton->setGeometry(bw*2, 0, bw, bw); 0327 scrollForwardButton->setIcon(QIcon(QPixmap(arrow_right_xpm))); 0328 scrollLastButton->setGeometry(bw*3, 0, bw, bw); 0329 scrollLastButton->setIcon(QIcon(QPixmap(arrow_rightmost_xpm))); 0330 } else { 0331 scrollFirstButton->setGeometry(w - bw, 0, bw, bw); 0332 scrollFirstButton->setIcon(QIcon(QPixmap(arrow_rightmost_xpm))); 0333 scrollBackButton->setGeometry(w - 2*bw, 0, bw, bw); 0334 scrollBackButton->setIcon(QIcon(QPixmap(arrow_right_xpm))); 0335 scrollForwardButton->setGeometry(w - 3*bw, 0, bw, bw); 0336 scrollForwardButton->setIcon(QIcon(QPixmap(arrow_left_xpm))); 0337 scrollLastButton->setGeometry(w - 4*bw, 0, bw, bw); 0338 scrollLastButton->setIcon(QIcon(QPixmap(arrow_leftmost_xpm))); 0339 } 0340 } 0341 0342 void TabBarPrivate::updateButtons() 0343 { 0344 scrollFirstButton->setEnabled(tabbar->canScrollBack()); 0345 scrollBackButton->setEnabled(tabbar->canScrollBack()); 0346 scrollForwardButton->setEnabled(tabbar->canScrollForward()); 0347 scrollLastButton->setEnabled(tabbar->canScrollForward()); 0348 } 0349 0350 QFont TabBarPrivate::font(bool selected) 0351 { 0352 QFont f = QFontDatabase::systemFont(QFontDatabase::TitleFont); 0353 if (selected) f.setBold(true); 0354 return f; 0355 } 0356 0357 // creates a new tabbar 0358 TabBar::TabBar(QWidget* parent, const char* /*name*/) 0359 : QWidget(parent) 0360 , d(new TabBarPrivate) 0361 { 0362 d->tabbar = this; 0363 d->readOnly = false; 0364 d->firstTab = 1; 0365 d->lastTab = 0; 0366 d->activeTab = 0; 0367 d->targetTab = 0; 0368 d->wheelDelta = 0; 0369 d->autoScroll = false; 0370 d->offset = 64; 0371 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); 0372 0373 // initialize the scroll buttons 0374 d->scrollFirstButton = new QToolButton(this); 0375 connect(d->scrollFirstButton, SIGNAL(clicked()), 0376 this, SLOT(scrollFirst())); 0377 d->scrollLastButton = new QToolButton(this); 0378 connect(d->scrollLastButton, SIGNAL(clicked()), 0379 this, SLOT(scrollLast())); 0380 d->scrollBackButton = new QToolButton(this); 0381 connect(d->scrollBackButton, SIGNAL(clicked()), 0382 this, SLOT(scrollBack())); 0383 d->scrollForwardButton = new QToolButton(this); 0384 connect(d->scrollForwardButton, SIGNAL(clicked()), 0385 this, SLOT(scrollForward())); 0386 d->layoutButtons(); 0387 d->updateButtons(); 0388 } 0389 0390 // destroys the tabbar 0391 TabBar::~TabBar() 0392 { 0393 delete d; 0394 } 0395 0396 // adds a new visible tab 0397 void TabBar::addTab(const QString& text) 0398 { 0399 d->tabs.append(text); 0400 0401 update(); 0402 } 0403 0404 // removes a tab 0405 void TabBar::removeTab(const QString& text) 0406 { 0407 int i = d->tabs.indexOf(text); 0408 if (i == -1) return; 0409 0410 if (d->activeTab == i + 1) 0411 d->activeTab = 0; 0412 0413 d->tabs.removeAll(text); 0414 0415 update(); 0416 } 0417 0418 // removes all tabs 0419 void TabBar::clear() 0420 { 0421 d->tabs.clear(); 0422 d->activeTab = 0; 0423 d->firstTab = 1; 0424 0425 update(); 0426 } 0427 0428 bool TabBar::readOnly() const 0429 { 0430 return d->readOnly; 0431 } 0432 0433 void TabBar::setReadOnly(bool ro) 0434 { 0435 d->readOnly = ro; 0436 } 0437 0438 void TabBar::setTabs(const QStringList& list) 0439 { 0440 QString left, active; 0441 0442 if (d->activeTab > 0) 0443 active = d->tabs[ d->activeTab-1 ]; 0444 if (d->firstTab > 0 && d->firstTab <= d->tabs.size()) 0445 left = d->tabs[ d->firstTab-1 ]; 0446 0447 d->tabs = list; 0448 0449 if (!left.isNull()) { 0450 d->firstTab = d->tabs.indexOf(left) + 1; 0451 if (d->firstTab > (int)d->tabs.count()) 0452 d->firstTab = 1; 0453 if (d->firstTab <= 0) 0454 d->firstTab = 1; 0455 } 0456 0457 d->activeTab = 0; 0458 if (!active.isNull()) 0459 setActiveTab(active); 0460 0461 update(); 0462 } 0463 0464 QStringList TabBar::tabs() const 0465 { 0466 return d->tabs; 0467 } 0468 0469 unsigned TabBar::count() const 0470 { 0471 return d->tabs.count(); 0472 } 0473 0474 bool TabBar::canScrollBack() const 0475 { 0476 if (d->tabs.count() == 0) 0477 return false; 0478 0479 return d->firstTab > 1; 0480 } 0481 0482 bool TabBar::canScrollForward() const 0483 { 0484 if (d->tabs.count() == 0) 0485 return false; 0486 0487 return d->lastTab < (int)d->tabs.count(); 0488 } 0489 0490 void TabBar::scrollBack() 0491 { 0492 if (!canScrollBack()) 0493 return; 0494 0495 d->firstTab--; 0496 if (d->firstTab < 1) d->firstTab = 1; 0497 0498 d->layoutTabs(); 0499 d->updateButtons(); 0500 update(); 0501 } 0502 0503 void TabBar::scrollForward() 0504 { 0505 if (!canScrollForward()) 0506 return; 0507 0508 d->firstTab ++; 0509 if (d->firstTab > (int)d->tabs.count()) 0510 d->firstTab = d->tabs.count(); 0511 0512 d->layoutTabs(); 0513 d->updateButtons(); 0514 update(); 0515 } 0516 0517 void TabBar::scrollFirst() 0518 { 0519 if (!canScrollBack()) 0520 return; 0521 0522 d->firstTab = 1; 0523 d->layoutTabs(); 0524 d->updateButtons(); 0525 update(); 0526 } 0527 0528 void TabBar::scrollLast() 0529 { 0530 if (!canScrollForward()) 0531 return; 0532 0533 d->layoutTabs(); 0534 0535 if (!isRightToLeft()) { 0536 int fullWidth = d->tabRects[ d->tabRects.count()-1 ].right(); 0537 int delta = fullWidth - width() + d->offset; 0538 for (int i = 0; i < d->tabRects.count(); i++) 0539 if (d->tabRects[i].x() > delta) { 0540 d->firstTab = i + 1; 0541 break; 0542 } 0543 } else { 0544 // FIXME optimize this, perhaps without loop 0545 for (; d->firstTab <= (int)d->tabRects.count();) { 0546 int x = d->tabRects[ d->tabRects.count()-1 ].x(); 0547 if (x > 0) break; 0548 d->firstTab++; 0549 d->layoutTabs(); 0550 } 0551 } 0552 0553 d->layoutTabs(); 0554 d->updateButtons(); 0555 update(); 0556 } 0557 0558 void TabBar::ensureVisible(const QString& tab) 0559 { 0560 int i = d->tabs.indexOf(tab); 0561 if (i == -1) 0562 return; 0563 i++; 0564 0565 // already visible, then do nothing 0566 if ((i >= d->firstTab) && (i <= d->lastTab)) 0567 return; 0568 0569 if (i < d->firstTab) 0570 while (i < d->firstTab) 0571 scrollBack(); 0572 0573 if (i > d->lastTab) 0574 while (i > d->lastTab) 0575 scrollForward(); 0576 } 0577 0578 void TabBar::moveTab(int tab, int target) 0579 { 0580 QString tabName = d->tabs.takeAt(tab); 0581 0582 if (target > tab) 0583 target--; 0584 0585 if (target >= d->tabs.count()) 0586 d->tabs.append(tabName); 0587 else 0588 d->tabs.insert(target, tabName); 0589 0590 if (d->activeTab == tab + 1) 0591 d->activeTab = target + 1; 0592 0593 update(); 0594 } 0595 0596 void TabBar::setActiveTab(const QString& text) 0597 { 0598 int i = d->tabs.indexOf(text); 0599 if (i == -1) 0600 return; 0601 0602 if (i + 1 == d->activeTab) 0603 return; 0604 0605 d->activeTab = i + 1; 0606 d->updateButtons(); 0607 update(); 0608 0609 emit tabChanged(text); 0610 } 0611 0612 void TabBar::autoScrollBack() 0613 { 0614 if (!d->autoScroll) return; 0615 0616 scrollBack(); 0617 0618 if (!canScrollBack()) 0619 d->autoScroll = false; 0620 else 0621 QTimer::singleShot(400, this, SLOT(autoScrollBack())); 0622 } 0623 0624 void TabBar::autoScrollForward() 0625 { 0626 if (!d->autoScroll) return; 0627 0628 scrollForward(); 0629 0630 if (!canScrollForward()) 0631 d->autoScroll = false; 0632 else 0633 QTimer::singleShot(400, this, SLOT(autoScrollForward())); 0634 } 0635 0636 void TabBar::paintEvent(QPaintEvent*) 0637 { 0638 if (d->tabs.count() == 0) { 0639 update(); 0640 return; 0641 } 0642 0643 d->layoutTabs(); 0644 d->updateButtons(); 0645 0646 QPainter painter(this); 0647 if (!isRightToLeft()) 0648 painter.translate(d->offset, 0); 0649 0650 if (!isRightToLeft()) 0651 painter.translate(5, 0); 0652 0653 // draw first all non-active, visible tabs 0654 for (int c = d->tabRects.count() - 1; c >= 0; c--) { 0655 QRect rect = d->tabRects[ c ]; 0656 if (rect.isNull()) continue; 0657 QString text = d->tabs[ c ]; 0658 d->drawTab(painter, rect, text, false); 0659 } 0660 0661 // draw the active tab 0662 if (d->activeTab > 0) { 0663 QRect rect = d->tabRects[ d->activeTab-1 ]; 0664 if (!rect.isNull()) { 0665 QString text = d->tabs[ d->activeTab-1 ]; 0666 d->drawTab(painter, rect, text, true); 0667 } 0668 } 0669 0670 // draw the move marker 0671 if (d->targetTab > 0) { 0672 int p = qMin(d->targetTab, (int)d->tabRects.count()); 0673 QRect rect = d->tabRects[ p-1 ]; 0674 if (!rect.isNull()) { 0675 int x = !isRightToLeft() ? rect.x() : rect.right() - 7; 0676 if (d->targetTab > (int)d->tabRects.count()) 0677 x = !isRightToLeft() ? rect.right() - 7 : rect.x() - 3; 0678 d->drawMoveMarker(painter, x, rect.y()); 0679 } 0680 } 0681 } 0682 0683 void TabBar::resizeEvent(QResizeEvent*) 0684 { 0685 d->layoutButtons(); 0686 d->updateButtons(); 0687 update(); 0688 } 0689 0690 QSize TabBar::sizeHint() const 0691 { 0692 int h = style()->pixelMetric(QStyle::PM_ScrollBarExtent); 0693 int w = 5 * h; // we have 4 buttons, the 5 is to give some free space too 0694 if (d->tabRects.size()) w += d->tabRects[d->tabRects.size() - 1].right(); 0695 0696 return QSize(w, h); 0697 } 0698 0699 void TabBar::renameTab(const QString& old_name, const QString& new_name) 0700 { 0701 d->tabs.replace(d->tabs.indexOf(old_name), new_name); 0702 0703 update(); 0704 } 0705 0706 QString TabBar::activeTab() const 0707 { 0708 if (d->activeTab == 0) 0709 return QString(); 0710 else 0711 return d->tabs[ d->activeTab-1 ]; 0712 } 0713 0714 void TabBar::mousePressEvent(QMouseEvent* ev) 0715 { 0716 if (d->tabs.count() == 0) { 0717 update(); 0718 return; 0719 } 0720 0721 d->layoutTabs(); 0722 0723 QPoint pos = ev->pos(); 0724 if (!isRightToLeft()) pos = pos - QPoint(d->offset, 0); 0725 0726 int tab = d->tabAt(pos) + 1; 0727 if ((tab > 0) && (tab != d->activeTab)) { 0728 d->activeTab = tab; 0729 update(); 0730 0731 emit tabChanged(d->tabs[ d->activeTab-1]); 0732 0733 // scroll if partially visible 0734 if (d->tabRects[ tab-1 ].right() > width() - d->offset) 0735 scrollForward(); 0736 } 0737 0738 if (ev->button() == Qt::RightButton) 0739 if (!d->readOnly) 0740 emit contextMenu(ev->globalPos()); 0741 } 0742 0743 void TabBar::mouseReleaseEvent(QMouseEvent* ev) 0744 { 0745 if (d->readOnly) return; 0746 0747 d->autoScroll = false; 0748 0749 if (ev->button() == Qt::LeftButton && d->targetTab != 0) { 0750 emit tabMoved(d->activeTab - 1, d->targetTab - 1); 0751 d->targetTab = 0; 0752 } 0753 } 0754 0755 void TabBar::mouseMoveEvent(QMouseEvent* ev) 0756 { 0757 if (d->readOnly) return; 0758 0759 QPoint pos = ev->pos(); 0760 if (!isRightToLeft()) pos = pos - QPoint(d->offset, 0); 0761 0762 // check if user drags a tab to move it 0763 int i = d->tabAt(pos) + 1; 0764 if ((i > 0) && (i != d->targetTab)) { 0765 if (i == d->activeTab) i = 0; 0766 if (i == d->activeTab + 1) i = 0; 0767 0768 if (i != d->targetTab) { 0769 d->targetTab = i; 0770 d->autoScroll = false; 0771 update(); 0772 } 0773 } 0774 0775 // drag past the very latest visible tab 0776 // e.g move a tab to the last ordering position 0777 QRect r = d->tabRects[ d->tabRects.count()-1 ]; 0778 bool moveToLast = false; 0779 if (r.isValid()) { 0780 if (!isRightToLeft()) 0781 if (pos.x() > r.right()) 0782 if (pos.x() < width()) 0783 moveToLast = true; 0784 if (isRightToLeft()) 0785 if (pos.x() < r.x()) 0786 if (pos.x() > 0) 0787 moveToLast = true; 0788 } 0789 if (moveToLast) 0790 if (d->targetTab != (int)d->tabRects.count() + 1) { 0791 d->targetTab = d->tabRects.count() + 1; 0792 d->autoScroll = false; 0793 update(); 0794 } 0795 0796 // outside far too left ? activate autoscroll... 0797 if (pos.x() < 0 && !d->autoScroll) { 0798 d->autoScroll = true; 0799 autoScrollBack(); 0800 } 0801 0802 // outside far too right ? activate autoscroll... 0803 int w = width() - d->offset; 0804 if (pos.x() > w && !d->autoScroll) { 0805 d->autoScroll = true; 0806 autoScrollForward(); 0807 } 0808 } 0809 0810 void TabBar::mouseDoubleClickEvent(QMouseEvent* ev) 0811 { 0812 int offset = isRightToLeft() ? 0 : d->offset; 0813 if (ev->pos().x() > offset) 0814 if (!d->readOnly) 0815 emit doubleClicked(); 0816 } 0817 0818 void TabBar::wheelEvent(QWheelEvent * e) 0819 { 0820 if (d->tabs.count() == 0) { 0821 update(); 0822 return; 0823 } 0824 0825 // Currently one wheel movement is a delta of 120. 0826 // The 'unused' delta is stored for devices that allow 0827 // a higher scrolling resolution. 0828 // The delta required to move one tab is one wheel movement: 0829 const int deltaRequired = 120; 0830 0831 d->wheelDelta += e->delta(); 0832 int tabDelta = - (d->wheelDelta / deltaRequired); 0833 d->wheelDelta = d->wheelDelta % deltaRequired; 0834 int numTabs = d->tabs.size(); 0835 0836 if (d->activeTab + tabDelta > numTabs) { 0837 // Would take us past the last tab 0838 d->activeTab = numTabs; 0839 } else if (d->activeTab + tabDelta < 1) { 0840 // Would take us before the first tab 0841 d->activeTab = 1; 0842 } else { 0843 d->activeTab = d->activeTab + tabDelta; 0844 } 0845 0846 // Find the left and right edge of the new tab. If we're 0847 // going forward, and the right of the new tab isn't visible 0848 // then scroll forward. Likewise, if going back, and the 0849 // left of the new tab isn't visible, then scroll back. 0850 int activeTabRight = d->tabRects[ d->activeTab-1 ].right(); 0851 int activeTabLeft = d->tabRects[ d->activeTab-1 ].left(); 0852 if (tabDelta > 0 && activeTabRight > width() - d->offset) { 0853 scrollForward(); 0854 } else if (tabDelta < 0 && activeTabLeft < width() - d->offset) { 0855 scrollBack(); 0856 } 0857 0858 update(); 0859 emit tabChanged(d->tabs[ d->activeTab-1]); 0860 } 0861 0862 } // namespace Sheets 0863 } // namespace Calligra