diff --git a/kate/katetabbutton.cpp b/kate/katetabbutton.cpp index d7e037e52..0f306f4be 100644 --- a/kate/katetabbutton.cpp +++ b/kate/katetabbutton.cpp @@ -1,295 +1,296 @@ /* This file is part of the KDE project * * Copyright (C) 2014 Dominik Haumann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "katetabbutton.h" #include #include // #include #include #include #include #include #include #include #include #include #include #include TabCloseButton::TabCloseButton(QWidget *parent) : QPushButton(parent) { // should never have focus setFocusPolicy(Qt::NoFocus); // closing a tab closes the document setToolTip(i18n("Close Document")); - setIcon(QIcon::fromTheme(QStringLiteral("document-close"))); + setIcon(QIcon::fromTheme(QStringLiteral("tab-close"))); } void TabCloseButton::paintEvent(QPaintEvent *) { // get the tab this close button belongs to KateTabButton *tabButton = qobject_cast(parent()); const bool isActive = underMouse() || (tabButton && tabButton->isChecked()); QStyleOptionButton opt; opt.initFrom(this); opt.icon = icon(); opt.iconSize = sizeHint(); // removes the QStyleOptionButton::HasMenu ButtonFeature opt.features = QStyleOptionButton::Flat; opt.state.setFlag(QStyle::State_Enabled, isActive); + opt.state.setFlag(QStyle::State_MouseOver, false); QPainter painter(this); style()->drawControl(QStyle::CE_PushButton, &opt, &painter, this); } QSize TabCloseButton::sizeHint() const { // make sure the widget is polished ensurePolished(); // read the metrics from the style const int w = style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth, nullptr, this); const int h = style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight, nullptr, this); return QSize(w, h); } void TabCloseButton::enterEvent(QEvent *event) { update(); // repaint on hover QPushButton::enterEvent(event); } void TabCloseButton::leaveEvent(QEvent *event) { update(); // repaint on hover QPushButton::leaveEvent(event); } KateTabButton::KateTabButton(const QString &text, QWidget *parent) : QAbstractButton(parent) , m_geometryAnimation(nullptr) { setCheckable(true); setFocusPolicy(Qt::NoFocus); setText(text); // add close button const int margin = style()->pixelMetric(QStyle::PM_ButtonMargin, nullptr, this); m_closeButton = new TabCloseButton(this); QHBoxLayout *hbox = new QHBoxLayout(this); hbox->setSpacing(0); hbox->setContentsMargins(margin, 0, margin, 0); hbox->addStretch(); hbox->addWidget(m_closeButton); setLayout(hbox); connect(m_closeButton, &TabCloseButton::clicked, this, &KateTabButton::closeButtonClicked); } void KateTabButton::closeButtonClicked() { emit closeRequest(this); } void KateTabButton::paintEvent(QPaintEvent *ev) { Q_UNUSED(ev) QColor barColor(palette().color(QPalette::Highlight)); // read from the parent widget (=KateTabBar) the isActiveTabBar property if (!isActiveTabBar()) { // if inactive, convert color to gray value const int g = qGray(barColor.rgb()); barColor = QColor(g, g, g); } // compute sane margins const int margin = style()->pixelMetric(QStyle::PM_ButtonMargin, nullptr, this); const int barMargin = margin / 2; const int barHeight = ceil(height() / 10.0); QPainter p(this); // paint bar if inactive but hovered if (!isChecked() && underMouse()) { barColor.setAlpha(80); p.fillRect(QRect(barMargin, height() - barHeight, width() - 2 * barMargin, barHeight), barColor); } // paint bar if (isChecked()) { barColor.setAlpha(255); p.fillRect(QRect(barMargin, height() - barHeight, width() - 2 * barMargin, barHeight), barColor); } // icon, if applicable int leftMargin = margin; if (!icon().isNull()) { const int y = (height() - 16) / 2; icon().paint(&p, margin, y, 16, 16); leftMargin += 16; leftMargin += margin; } // the width of the text is reduced by the close button + 2 * margin const int w = width() // width of widget - m_closeButton->width() - 2 * margin // close button - leftMargin; // modified button // draw text, we need to elide to xxx...xxx is too long const QString elidedText = QFontMetrics(font()).elidedText(text(), Qt::ElideMiddle, w); QRect textRect(leftMargin, 0, w, height()); if (layoutDirection() == Qt::RightToLeft) { textRect.moveLeft(textRect.left() + 16); } const QPalette pal = QApplication::palette(); style()->drawItemText(&p, textRect, Qt::AlignHCenter | Qt::AlignVCenter, pal, true, elidedText, QPalette::WindowText); } void KateTabButton::mousePressEvent(QMouseEvent *ev) { ev->accept(); // save mouse position for possible drag start event m_mouseDownPosition = ev->globalPos(); // activation code if (ev->button() == Qt::LeftButton) { if (!isChecked()) { // make sure we stay checked setChecked(true); } // notify that this button was activated emit activated(this); } else if (ev->button() == Qt::MiddleButton) { emit closeRequest(this); } else { ev->ignore(); } } void KateTabButton::mouseMoveEvent(QMouseEvent *event) { // possibly start drag event if (QPoint(event->globalPos() - m_mouseDownPosition).manhattanLength() > QApplication::startDragDistance()) { QMimeData *mimeData = new QMimeData; mimeData->setData(QStringLiteral("application/x-dndkatetabbutton"), QByteArray()); mimeData->setUrls({m_url}); auto drag = new QDrag(this); drag->setMimeData(mimeData); drag->setDragCursor(QPixmap(), Qt::MoveAction); drag->exec(Qt::MoveAction); event->accept(); } QAbstractButton::mouseMoveEvent(event); } void KateTabButton::mouseDoubleClickEvent(QMouseEvent *event) { event->accept(); } void KateTabButton::enterEvent(QEvent *event) { update(); // repaint on hover QAbstractButton::enterEvent(event); } void KateTabButton::leaveEvent(QEvent *event) { update(); // repaint on hover QAbstractButton::leaveEvent(event); } void KateTabButton::moveEvent(QMoveEvent *event) { // tell the tabbar to redraw its separators. Since the separators overlap // the tab buttons geometry, we need to adjust the width by the separator's // width to avoid artifacts if (parentWidget()) { const int w = style()->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, nullptr, this); QRect rect = geometry(); rect.moveLeft(event->oldPos().x()); rect.adjust(-w, 0, w, 0); parentWidget()->update(rect); } QAbstractButton::moveEvent(event); } bool KateTabButton::isActiveTabBar() const { Q_ASSERT(parentWidget()); // read from the parent widget (=KateTabBar) the isActive property return parentWidget()->property("isActive").toBool(); } void KateTabButton::setAnimatedGeometry(const QRect &startGeom, const QRect &endGeom) { // stop animation in case it is running if (m_geometryAnimation && m_geometryAnimation->state() != QAbstractAnimation::Stopped) { m_geometryAnimation->stop(); } // already at desired position if (startGeom == geometry() && endGeom == startGeom) { return; } // if the style does not want animations, just set geometry if (!style()->styleHint(QStyle::SH_Widget_Animate, nullptr, this) || (isVisible() && endGeom == startGeom)) { setGeometry(endGeom); return; } if (!m_geometryAnimation) { m_geometryAnimation = new QPropertyAnimation(this, "geometry", this); m_geometryAnimation->setDuration(100); } // finally start geometry animation m_geometryAnimation->setStartValue(startGeom); m_geometryAnimation->setEndValue(endGeom); m_geometryAnimation->start(); } bool KateTabButton::geometryAnimationRunning() const { return m_geometryAnimation && (m_geometryAnimation->state() != QAbstractAnimation::Stopped); } QUrl KateTabButton::url() const { return m_url; } void KateTabButton::setUrl(const QUrl &url) { m_url = url; }