Commit 829b7e43 authored by Noah Davis's avatar Noah Davis 🌵
Browse files

Make sidebar tab button style adapt to tab width

Use larger icon size, always use icon size in tabSizeHint

Don't elide text, use minimumSizeHint to reduce size without eliding
parent 2027581c
......@@ -620,13 +620,13 @@ struct MainWindow::Private
// Fill sidebar
SideBarPage* page;
page = new SideBarPage(i18n("Folders"));
page = new SideBarPage(QIcon::fromTheme("folder"), i18n("Folders"));
page->setObjectName(QLatin1String("folders"));
page->addWidget(folderViewItem->widget());
page->layout()->setContentsMargins(0, 0, 0, 0);
mSideBar->addPage(page);
page = new SideBarPage(i18n("Information"));
page = new SideBarPage(QIcon::fromTheme("documentinfo"), i18n("Information"));
page->setObjectName(QLatin1String("information"));
page->addWidget(infoItem->widget());
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
......@@ -640,7 +640,7 @@ struct MainWindow::Private
#endif
mSideBar->addPage(page);
page = new SideBarPage(i18n("Operations"));
page = new SideBarPage(QIcon::fromTheme("document-edit"), i18n("Operations"));
page->setObjectName(QLatin1String("operations"));
page->addWidget(imageOpsItem->widget());
QFrame *separator = new QFrame;
......
......@@ -29,6 +29,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <QVBoxLayout>
#include <QIcon>
#include <QFontDatabase>
#include <QStyleOptionTab>
#include <QStylePainter>
// KF
#include <KIconLoader>
......@@ -151,16 +153,17 @@ void SideBarGroup::addAction(QAction* action)
//- SideBarPage ----------------------------------------------------------------
struct SideBarPagePrivate
{
QIcon mIcon;
QString mTitle;
QVBoxLayout* mLayout;
};
SideBarPage::SideBarPage(const QString& title)
SideBarPage::SideBarPage(const QIcon& icon, const QString& title)
: QWidget()
, d(new SideBarPagePrivate)
{
d->mIcon = icon;
d->mTitle = title;
d->mLayout = new QVBoxLayout(this);
QMargins margins = d->mLayout->contentsMargins();
margins.setRight(qMax(0, margins.right() - style()->pixelMetric(QStyle::PM_SplitterWidth)));
......@@ -172,6 +175,11 @@ SideBarPage::~SideBarPage()
delete d;
}
const QIcon & SideBarPage::icon() const
{
return d->mIcon;
}
const QString& SideBarPage::title() const
{
return d->mTitle;
......@@ -187,6 +195,180 @@ void SideBarPage::addStretch()
d->mLayout->addStretch();
}
//- SideBarTabBar --------------------------------------------------------------
struct SideBarTabBarPrivate
{
SideBarTabBar::TabButtonStyle tabButtonStyle = SideBarTabBar::TabButtonTextBesideIcon;
};
SideBarTabBar::SideBarTabBar(QWidget* parent)
: QTabBar(parent)
, d(new SideBarTabBarPrivate)
{
setIconSize(QSize(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium));
}
SideBarTabBar::~SideBarTabBar()
{
}
SideBarTabBar::TabButtonStyle SideBarTabBar::tabButtonStyle() const
{
return d->tabButtonStyle;
}
QSize SideBarTabBar::sizeHint(const TabButtonStyle tabButtonStyle) const
{
QRect tabBarRect(0, 0, 0, 0);
for (int i = 0; i < count(); ++i) {
const QRect tabRect(tabBarRect.topRight(), tabSizeHint(i, tabButtonStyle));
tabBarRect = tabBarRect.united(tabRect);
}
return tabBarRect.size();
}
QSize SideBarTabBar::sizeHint() const
{
return sizeHint(d->tabButtonStyle);
}
QSize SideBarTabBar::minimumSizeHint() const
{
return sizeHint(TabButtonIconOnly);
}
QSize SideBarTabBar::tabContentSize(const int index,
const TabButtonStyle tabButtonStyle,
const QStyleOptionTab &opt) const
{
if (index < 0 || index > count() - 1) {
return QSize();
}
const int textWidth = opt.fontMetrics.size(Qt::TextShowMnemonic, tabText(index)).width();
if (tabButtonStyle == TabButtonIconOnly) {
return QSize(opt.iconSize.width(),
qMax(opt.iconSize.height(), opt.fontMetrics.height()));
}
if (tabButtonStyle == TabButtonTextOnly) {
return QSize(textWidth,
qMax(opt.iconSize.height(), opt.fontMetrics.height()));
}
// 4 is the hardcoded spacing between icons and text used in Qt Widgets
const int spacing = !opt.icon.isNull() ? 4 : 0;
return QSize(opt.iconSize.width() + spacing + textWidth,
qMax(opt.iconSize.height(), opt.fontMetrics.height()));
}
QSize SideBarTabBar::tabSizeHint(const int index, const TabButtonStyle tabButtonStyle) const
{
if (index < 0 || index > count() - 1) {
return QSize();
}
QStyleOptionTab opt;
initStyleOption(&opt, index);
if (tabButtonStyle == TabButtonIconOnly) {
opt.text.clear();
} else if (tabButtonStyle == TabButtonTextOnly) {
opt.icon = QIcon();
}
const QSize contentSize = tabContentSize(index, tabButtonStyle, opt);
const int buttonMargin = style()->pixelMetric(QStyle::PM_ButtonMargin);
const int toolBarMargin = style()->pixelMetric(QStyle::PM_ToolBarFrameWidth)
+ style()->pixelMetric(QStyle::PM_ToolBarItemMargin);
return QSize(contentSize.width() + buttonMargin * 2 + toolBarMargin * 2,
contentSize.height() + buttonMargin * 2 + toolBarMargin * 2);
}
QSize SideBarTabBar::tabSizeHint(const int index) const
{
return tabSizeHint(index, d->tabButtonStyle);
}
QSize SideBarTabBar::minimumTabSizeHint(int index) const
{
return tabSizeHint(index, TabButtonIconOnly);
}
void SideBarTabBar::tabLayoutChange()
{
const int width = this->width();
if (width < sizeHint(TabButtonTextOnly).width()) {
d->tabButtonStyle = TabButtonIconOnly;
} else if (width < sizeHint(TabButtonTextBesideIcon).width()) {
d->tabButtonStyle = TabButtonTextOnly;
} else {
d->tabButtonStyle = TabButtonTextBesideIcon;
}
}
void SideBarTabBar::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event)
QStylePainter painter(this);
// Don't need to draw PE_FrameTabBarBase because it's in a QTabWidget
const int selected = currentIndex();
for (int i = 0; i < this->count(); ++i) {
if (i == selected) {
continue;
}
drawTab(i, painter);
}
// draw selected tab last so it appears on top
if (selected >= 0) {
drawTab(selected, painter);
}
}
void SideBarTabBar::drawTab(int index, QStylePainter &painter) const
{
QStyleOptionTabV4 opt;
QTabBar::initStyleOption(&opt, index);
// draw background before doing anything else
painter.drawControl(QStyle::CE_TabBarTabShape, opt);
const TabButtonStyle tabButtonStyle = this->tabButtonStyle();
if (tabButtonStyle == TabButtonTextOnly) {
opt.icon = QIcon();
} else if (tabButtonStyle == TabButtonIconOnly) {
opt.text.clear();
}
const bool hasIcon = !opt.icon.isNull();
const bool hasText = !opt.text.isEmpty();
int flags = Qt::TextShowMnemonic;
flags |= hasIcon && hasText ? Qt::AlignLeft | Qt::AlignVCenter : Qt::AlignCenter;
if (!style()->styleHint(QStyle::SH_UnderlineShortcut, &opt, this)) {
flags |= Qt::TextHideMnemonic;
}
const QSize contentSize = tabContentSize(index, tabButtonStyle, opt);
const QRect contentRect = QStyle::alignedRect(this->layoutDirection(), Qt::AlignCenter, contentSize, opt.rect);
if (hasIcon) {
painter.drawItemPixmap(contentRect, flags, opt.icon.pixmap(opt.iconSize));
}
if (hasText) {
// The available space to draw the text depends on wether we already drew an icon into our contentRect.
const QSize availableSizeForText = !hasIcon ? contentSize
: QSize(contentSize.width() - opt.iconSize.width() - 4, contentSize.height());
// The '4' above is the hardcoded spacing between icons and text used in Qt Widgets.
const QRect availableRectForText = !hasIcon ? contentRect
: QStyle::alignedRect(this->layoutDirection(), Qt::AlignRight, availableSizeForText, contentRect);
painter.drawItemText(availableRectForText, flags, opt.palette, opt.state & QStyle::State_Enabled, opt.text, QPalette::WindowText);
}
}
//- SideBar --------------------------------------------------------------------
struct SideBarPrivate
{
......@@ -196,12 +378,13 @@ SideBar::SideBar(QWidget* parent)
: QTabWidget(parent)
, d(new SideBarPrivate)
{
setTabBar(new SideBarTabBar(this));
setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
tabBar()->setDocumentMode(true);
tabBar()->setUsesScrollButtons(false);
tabBar()->setFocusPolicy(Qt::NoFocus);
tabBar()->setExpanding(true);
setTabPosition(QTabWidget::South);
setElideMode(Qt::ElideRight);
connect(tabBar(), &QTabBar::currentChanged, [=]() {
GwenviewConfig::setSideBarPage(currentPage());
......@@ -222,7 +405,9 @@ void SideBar::addPage(SideBarPage* page)
{
// Prevent emitting currentChanged() while populating pages
SignalBlocker blocker(tabBar());
addTab(page, page->title());
addTab(page, page->icon(), page->title());
const int thisTabIndex = this->count() - 1;
this->setTabToolTip(thisTabIndex, page->title());
}
QString SideBar::currentPage() const
......
......@@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
// Qt
#include <QFrame>
#include <QTabWidget>
#include <QTabBar>
#include <QStylePainter>
namespace Gwenview
{
......@@ -50,17 +52,56 @@ class SideBarPage : public QWidget
{
Q_OBJECT
public:
SideBarPage(const QString& title);
SideBarPage(const QIcon& icon, const QString& title);
~SideBarPage() override;
void addWidget(QWidget*);
void addStretch();
const QIcon& icon() const;
const QString& title() const;
private:
SideBarPagePrivate* const d;
};
struct SideBarTabBarPrivate;
class SideBarTabBar : public QTabBar
{
Q_OBJECT
public:
explicit SideBarTabBar(QWidget* parent);
~SideBarTabBar() override;
enum TabButtonStyle {
TabButtonIconOnly,
TabButtonTextOnly,
TabButtonTextBesideIcon
};
Q_ENUM(TabButtonStyle)
TabButtonStyle tabButtonStyle() const;
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
protected:
QSize tabSizeHint(const int index) const override;
QSize minimumTabSizeHint(int index) const override;
// Switches the TabButtonStyle based on the width
void tabLayoutChange() override;
void paintEvent(QPaintEvent *event) override;
private:
// Like sizeHint, but just for content size
QSize tabContentSize(const int index, const TabButtonStyle tabButtonStyle, const QStyleOptionTab& opt) const;
// Gets the tab size hint for the given TabButtonStyle
QSize tabSizeHint(const int index, const TabButtonStyle tabButtonStyle) const;
// Gets the size hint for the given TabButtonStyle
QSize sizeHint(const TabButtonStyle tabButtonStyle) const;
void drawTab(int index, QStylePainter &painter) const;
const std::unique_ptr<SideBarTabBarPrivate> d;
};
struct SideBarPrivate;
class SideBar : public QTabWidget
{
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment