1
mirror of https://invent.kde.org/network/falkon.git synced 2024-12-20 18:56:34 +01:00

TabTreeView: Draw real tabbar close button and make it stylable

This commit is contained in:
David Rosca 2018-02-03 12:46:42 +01:00
parent 6985a8567a
commit ad387fe712
No known key found for this signature in database
GPG Key ID: EBC3FC294452C6D8
4 changed files with 70 additions and 7 deletions

View File

@ -21,9 +21,11 @@
#include "tabmodel.h" #include "tabmodel.h"
#include "tabicon.h" #include "tabicon.h"
#include "iconprovider.h"
#include <QTabBar>
#include <QPainter> #include <QPainter>
#include <QPushButton>
#include <QApplication>
TabTreeDelegate::TabTreeDelegate(TabTreeView *view) TabTreeDelegate::TabTreeDelegate(TabTreeView *view)
: QStyledItemDelegate() : QStyledItemDelegate()
@ -36,6 +38,19 @@ TabTreeDelegate::TabTreeDelegate(TabTreeView *view)
connect(m_loadingAnimator, &LoadingAnimator::updateIndex, this, [this](const QModelIndex &index) { connect(m_loadingAnimator, &LoadingAnimator::updateIndex, this, [this](const QModelIndex &index) {
m_view->update(index); m_view->update(index);
}); });
// Needed to make it stylable the same way as real tabbar close button
QTabBar *tabBar = new QTabBar(m_view);
tabBar->setObjectName(QSL("treeview_tabbar"));
tabBar->lower();
m_closeButton = new QPushButton(tabBar);
m_closeButton->setObjectName(QSL("treeview_close_button"));
m_closeButton->lower();
int width = m_closeButton->style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth, nullptr, m_closeButton);
int height = m_closeButton->style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight, nullptr, m_closeButton);
m_closeButton->resize(width, height);
} }
static int indexDepth(QModelIndex index) static int indexDepth(QModelIndex index)
@ -70,7 +85,9 @@ QRect TabTreeDelegate::closeButtonRect(const QModelIndex &index) const
{ {
const QRect rect = m_view->visualRect(index); const QRect rect = m_view->visualRect(index);
const int center = rect.height() / 2 + rect.top(); const int center = rect.height() / 2 + rect.top();
return QRect(rect.right() - m_padding - 16, center - 16 / 2, 16, 16); QSize size = m_closeButton->size();
size.setHeight(qMin(rect.height() - m_padding, size.height()));
return QRect(QPoint(rect.right() - m_padding - size.width(), center - size.height() / 2), size);
} }
void TabTreeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const void TabTreeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
@ -91,7 +108,7 @@ void TabTreeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio
const int center = height / 2 + opt.rect.top(); const int center = height / 2 + opt.rect.top();
int leftPosition = opt.rect.left() + m_indentation + m_indentation * depth + m_padding; int leftPosition = opt.rect.left() + m_indentation + m_indentation * depth + m_padding;
int rightPosition = opt.rect.right() - m_padding * 2 - 16; // always reserve close button size int rightPosition = opt.rect.right() - m_padding * 2 - m_closeButton->size().width();
const QIcon::Mode iconMode = opt.state & QStyle::State_Selected ? QIcon::Selected : QIcon::Normal; const QIcon::Mode iconMode = opt.state & QStyle::State_Selected ? QIcon::Selected : QIcon::Normal;
const QPalette::ColorRole colorRole = opt.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text; const QPalette::ColorRole colorRole = opt.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text;
@ -136,10 +153,20 @@ void TabTreeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio
// Draw close button // Draw close button
if (opt.state.testFlag(QStyle::State_MouseOver) || opt.state.testFlag(QStyle::State_Selected)) { if (opt.state.testFlag(QStyle::State_MouseOver) || opt.state.testFlag(QStyle::State_Selected)) {
QSize closeSize(16, 16); QStyleOptionButton o;
o.init(m_closeButton);
const bool hovered = closeButtonRect(index).contains(m_view->viewport()->mapFromGlobal(QCursor::pos()));
const bool pressed = hovered && QApplication::mouseButtons() == Qt::LeftButton;
QSize closeSize = QSize(o.rect.size().width(), qMin(height - m_padding, o.rect.size().height()));
QPoint pos(opt.rect.right() - m_padding - closeSize.width(), center - closeSize.height() / 2); QPoint pos(opt.rect.right() - m_padding - closeSize.width(), center - closeSize.height() / 2);
QRect closeRect(pos, closeSize); o.rect = QRect(pos, closeSize);
painter->drawPixmap(closeRect, IconProvider::standardIcon(QStyle::SP_DialogCloseButton).pixmap(closeSize, iconMode)); o.state |= QStyle::State_AutoRaise | QStyle::State_Enabled | QStyle::State_Selected;
o.state.setFlag(QStyle::State_Raised, hovered && !pressed);
o.state.setFlag(QStyle::State_Sunken, pressed);
o.state.setFlag(QStyle::State_MouseOver, hovered);
style->drawPrimitive(QStyle::PE_IndicatorTabClose, &o, painter, m_closeButton);
} }
// Draw audio icon // Draw audio icon

View File

@ -19,6 +19,8 @@
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
class QPushButton;
class TabTreeView; class TabTreeView;
class LoadingAnimator; class LoadingAnimator;
@ -37,6 +39,7 @@ public:
private: private:
TabTreeView *m_view; TabTreeView *m_view;
LoadingAnimator *m_loadingAnimator; LoadingAnimator *m_loadingAnimator;
QPushButton *m_closeButton;
int m_padding; int m_padding;
int m_indentation; int m_indentation;
}; };

View File

@ -46,6 +46,9 @@ TabTreeView::TabTreeView(QWidget *parent)
// Move scrollbar to the left // Move scrollbar to the left
setLayoutDirection(isRightToLeft() ? Qt::LeftToRight : Qt::RightToLeft); setLayoutDirection(isRightToLeft() ? Qt::LeftToRight : Qt::RightToLeft);
// Enable hover to force redrawing close button
viewport()->setAttribute(Qt::WA_Hover);
} }
bool TabTreeView::areTabsInOrder() const bool TabTreeView::areTabsInOrder() const
@ -109,6 +112,7 @@ bool TabTreeView::viewportEvent(QEvent *event)
case QEvent::MouseButtonPress: { case QEvent::MouseButtonPress: {
QMouseEvent *me = static_cast<QMouseEvent*>(event); QMouseEvent *me = static_cast<QMouseEvent*>(event);
const QModelIndex index = indexAt(me->pos()); const QModelIndex index = indexAt(me->pos());
update(index);
WebTab *tab = index.data(TabModel::WebTabRole).value<WebTab*>(); WebTab *tab = index.data(TabModel::WebTabRole).value<WebTab*>();
if (me->buttons() == Qt::MiddleButton && tab) { if (me->buttons() == Qt::MiddleButton && tab) {
tab->closeTab(); tab->closeTab();
@ -131,6 +135,19 @@ bool TabTreeView::viewportEvent(QEvent *event)
tab->makeCurrentTab(); tab->makeCurrentTab();
} }
} }
if (m_pressedButton == CloseButton) {
me->accept();
return true;
}
break;
}
case QEvent::MouseMove: {
QMouseEvent *me = static_cast<QMouseEvent*>(event);
if (m_pressedButton == CloseButton) {
me->accept();
return true;
}
break; break;
} }
@ -140,6 +157,7 @@ bool TabTreeView::viewportEvent(QEvent *event)
break; break;
} }
const QModelIndex index = indexAt(me->pos()); const QModelIndex index = indexAt(me->pos());
update(index);
if (m_pressedIndex != index) { if (m_pressedIndex != index) {
break; break;
} }
@ -158,6 +176,20 @@ bool TabTreeView::viewportEvent(QEvent *event)
} }
} }
} }
if (m_pressedButton == CloseButton) {
me->accept();
return true;
}
break;
}
case QEvent::HoverEnter:
case QEvent::HoverLeave:
case QEvent::HoverMove: {
QHoverEvent *he = static_cast<QHoverEvent*>(event);
update(m_hoveredIndex);
m_hoveredIndex = indexAt(he->pos());
update(m_hoveredIndex);
break; break;
} }

View File

@ -50,6 +50,7 @@ private:
TabTreeDelegate *m_delegate; TabTreeDelegate *m_delegate;
DelegateButton m_pressedButton = NoButton; DelegateButton m_pressedButton = NoButton;
QModelIndex m_pressedIndex; QPersistentModelIndex m_pressedIndex;
QPersistentModelIndex m_hoveredIndex;
bool m_tabsInOrder = false; bool m_tabsInOrder = false;
}; };