From c05fb33ea2af4c878d0ed5fb37e399b7be5c40b5 Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Fri, 19 Oct 2018 19:10:22 +0200 Subject: [PATCH] Replace FancyTabWidget with improved version --- src/core/mainwindow.cpp | 68 +- src/core/mainwindow.h | 7 + src/settings/deezersettingspage.cpp | 9 +- src/settings/deezersettingspage.ui | 7 + src/settings/tidalsettingspage.cpp | 3 +- src/settings/tidalsettingspage.ui | 7 + src/widgets/fancytabwidget.cpp | 1093 +++++++++++---------------- src/widgets/fancytabwidget.h | 278 ++----- 8 files changed, 578 insertions(+), 894 deletions(-) diff --git a/src/core/mainwindow.cpp b/src/core/mainwindow.cpp index cebaaf0dc..3eec31d3f 100644 --- a/src/core/mainwindow.cpp +++ b/src/core/mainwindow.cpp @@ -260,25 +260,24 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co StyleHelper::setBaseColor(palette().color(QPalette::Highlight).darker()); // Add tabs to the fancy tab widget - ui_->tabs->addTab(context_view_, IconLoader::Load("strawberry"), tr("Context")); - ui_->tabs->addTab(collection_view_, IconLoader::Load("vinyl"), tr("Collection")); - ui_->tabs->addTab(file_view_, IconLoader::Load("document-open"), tr("Files")); - ui_->tabs->addTab(playlist_list_, IconLoader::Load("view-media-playlist"), tr("Playlists")); + ui_->tabs->addTab(context_view_, IconLoader::Load("strawberry"), "Context"); + ui_->tabs->addTab(collection_view_, IconLoader::Load("vinyl"), "Collection"); + ui_->tabs->addTab(file_view_, IconLoader::Load("document-open"), "Files"); + ui_->tabs->addTab(playlist_list_, IconLoader::Load("view-media-playlist"), "Playlists"); #ifndef Q_OS_WIN - ui_->tabs->addTab(device_view_, IconLoader::Load("device"), tr("Devices")); + ui_->tabs->addTab(device_view_, IconLoader::Load("device"), "Devices"); #endif #ifdef HAVE_STREAM_TIDAL - ui_->tabs->addTab(tidal_search_view_, IconLoader::Load("tidal"), tr("Tidal", "Tidal")); + ui_->tabs->addTab(tidal_search_view_, IconLoader::Load("tidal"), "Tidal"); #endif #ifdef HAVE_STREAM_DEEZER - ui_->tabs->addTab(deezer_search_view_, IconLoader::Load("deezer"), tr("Deezer", "Deezer")); + ui_->tabs->addTab(deezer_search_view_, IconLoader::Load("deezer"), "Deezer"); #endif - //ui_->tabs->AddSpacer(); // Add the playing widget to the fancy tab widget ui_->tabs->addBottomWidget(ui_->widget_playing); - //ui_->tabs->SetBackgroundPixmap(QPixmap(":/pictures/strawberry-background.png")); + ui_->tabs->loadSettings(kSettingsGroup); track_position_timer_->setInterval(kTrackPositionUpdateTimeMs); connect(track_position_timer_, SIGNAL(timeout()), SLOT(UpdateTrackPosition())); @@ -722,7 +721,10 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co ui_->tabs->setCurrentIndex(settings_.value("current_tab", 1 /* Collection tab */ ).toInt()); FancyTabWidget::Mode default_mode = FancyTabWidget::Mode_LargeSidebar; - ui_->tabs->SetMode(FancyTabWidget::Mode(settings_.value("tab_mode", default_mode).toInt())); + int tab_mode_int = settings_.value("tab_mode", default_mode).toInt(); + FancyTabWidget::Mode tab_mode = FancyTabWidget::Mode(tab_mode_int); + if (tab_mode == FancyTabWidget::Mode_None) tab_mode = default_mode; + ui_->tabs->SetMode(tab_mode); file_view_->SetPath(settings_.value("file_path", QDir::homePath()).toString()); TabSwitched(); @@ -811,6 +813,28 @@ void MainWindow::ReloadSettings() { album_cover_choice_controller_->search_cover_auto_action()->setChecked(settings.value("search_for_cover_auto", true).toBool()); settings.endGroup(); +#ifdef HAVE_STREAM_TIDAL + settings.beginGroup(TidalSettingsPage::kSettingsGroup); + bool enable_tidal = settings.value("enabled", false).toBool(); + settings.endGroup(); + if (enable_tidal) + ui_->tabs->addTab(tidal_search_view_, IconLoader::Load("tidal"), "Tidal"); + else + ui_->tabs->delTab("tidal"); +#endif + +#ifdef HAVE_STREAM_DEEZER + settings.beginGroup(DeezerSettingsPage::kSettingsGroup); + bool enable_deezer = settings.value("enabled", false).toBool(); + settings.endGroup(); + if (enable_deezer) + ui_->tabs->addTab(deezer_search_view_, IconLoader::Load("deezer"), "Deezer"); + else + ui_->tabs->delTab("deezer"); +#endif + + ui_->tabs->loadSettings(kSettingsGroup); + } void MainWindow::ReloadAllSettings() { @@ -884,12 +908,14 @@ void MainWindow::MediaPlaying() { ui_->action_play_pause->setIcon(IconLoader::Load("media-pause")); ui_->action_play_pause->setText(tr("Pause")); - bool enable_play_pause = !(app_->player()->GetCurrentItem()->options() & PlaylistItem::PauseDisabled); + bool enable_play_pause(false); + bool can_seek(false); + if (app_->player()->GetCurrentItem()) { + enable_play_pause = !(app_->player()->GetCurrentItem()->options() & PlaylistItem::PauseDisabled); + can_seek = !(app_->player()->GetCurrentItem()->options() & PlaylistItem::SeekDisabled); + } ui_->action_play_pause->setEnabled(enable_play_pause); - - bool can_seek = !(app_->player()->GetCurrentItem()->options() & PlaylistItem::SeekDisabled); ui_->track_slider->SetCanSeek(can_seek); - if (tray_icon_) tray_icon_->SetPlaying(enable_play_pause); track_position_timer_->start(); @@ -913,6 +939,7 @@ void MainWindow::SongChanged(const Song &song) { } void MainWindow::TrackSkipped(PlaylistItemPtr item) { + // If it was a collection item then we have to increment its skipped count in the database. if (item && item->IsLocalCollectionItem() && item->Metadata().id() != -1) { @@ -929,6 +956,7 @@ void MainWindow::TrackSkipped(PlaylistItemPtr item) { app_->collection_backend()->IncrementSkipCountAsync(song.id(), percentage); } } + } void MainWindow::changeEvent(QEvent *event) { @@ -937,16 +965,18 @@ void MainWindow::changeEvent(QEvent *event) { } void MainWindow::resizeEvent(QResizeEvent *event) { + if (!initialised_) return; SaveGeometry(); } void MainWindow::TabSwitched() { - if (ui_->tabs->currentIndex() > 0) - ui_->widget_playing->SetEnabled(); - else + if (ui_->tabs->tabBar()->tabData(ui_->tabs->currentIndex()).toString().toLower() == "context") ui_->widget_playing->SetDisabled(); + else + ui_->widget_playing->SetEnabled(); + if (!initialised_) return; SaveGeometry(); } @@ -960,6 +990,7 @@ void MainWindow::SaveGeometry() { settings_.setValue("splitter_state", ui_->splitter->saveState()); settings_.setValue("current_tab", ui_->tabs->currentIndex()); settings_.setValue("tab_mode", ui_->tabs->mode()); + ui_->tabs->saveSettings(kSettingsGroup); } @@ -1145,6 +1176,7 @@ void MainWindow::UpdateTrackPosition() { //Playlist *playlist = app_->playlist_manager()->active(); PlaylistItemPtr item(app_->player()->GetCurrentItem()); + if (!item) return; const int position = std::floor(float(app_->player()->engine()->position_nanosec()) / kNsecPerSec + 0.5); const int length = item->Metadata().length_nanosec() / kNsecPerSec; @@ -2216,8 +2248,8 @@ bool MainWindow::winEvent(MSG *msg, long*) { void MainWindow::Exit() { + SaveGeometry(); SavePlaybackStatus(); - //settings_.setValue("show_sidebar", ui_->action_toggle_show_sidebar->isChecked()); if (app_->player()->engine()->is_fadeout_enabled()) { // To shut down the application when fadeout will be finished diff --git a/src/core/mainwindow.h b/src/core/mainwindow.h index 3f7a956fd..02dedac23 100644 --- a/src/core/mainwindow.h +++ b/src/core/mainwindow.h @@ -387,6 +387,13 @@ signals: Song song_playing_; QImage image_original_; +#ifdef HAVE_STREAM_TIDAL + int tab_index_tidal_; +#endif +#ifdef HAVE_STREAM_DEEZER + int tab_index_deezer_; +#endif + }; #endif // MAINWINDOW_H diff --git a/src/settings/deezersettingspage.cpp b/src/settings/deezersettingspage.cpp index 5beeb698a..5a29727da 100644 --- a/src/settings/deezersettingspage.cpp +++ b/src/settings/deezersettingspage.cpp @@ -73,6 +73,7 @@ void DeezerSettingsPage::Load() { QSettings s; s.beginGroup(kSettingsGroup); + ui_->checkbox_enable->setChecked(s.value("enabled", false).toBool()); ui_->username->setText(s.value("username").toString()); QByteArray password = s.value("password").toByteArray(); if (password.isEmpty()) ui_->password->clear(); @@ -83,7 +84,12 @@ void DeezerSettingsPage::Load() { ui_->spinbox_songssearchlimit->setValue(s.value("songssearchlimit", 100).toInt()); ui_->checkbox_fetchalbums->setChecked(s.value("fetchalbums", false).toBool()); dialog()->ComboBoxLoadFromSettings(s, ui_->combobox_coversize, "coversize", "cover_big"); - ui_->checkbox_preview->setChecked(s.value("preview", false).toBool()); +#if defined(HAVE_DEEZER) || defined(HAVE_DZMEDIA) + bool preview(false); +#else + bool preview(true); +#endif + ui_->checkbox_preview->setChecked(s.value("preview", preview).toBool()); s.endGroup(); if (service_->authenticated()) ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn); @@ -95,6 +101,7 @@ void DeezerSettingsPage::Save() { QSettings s; s.beginGroup(kSettingsGroup); + s.setValue("enabled", ui_->checkbox_enable->isChecked()); s.setValue("username", ui_->username->text()); s.setValue("password", QString::fromUtf8(ui_->password->text().toUtf8().toBase64())); s.setValue("quality", ui_->combobox_quality->itemData(ui_->combobox_quality->currentIndex())); diff --git a/src/settings/deezersettingspage.ui b/src/settings/deezersettingspage.ui index d2938d82d..89f78bf9a 100644 --- a/src/settings/deezersettingspage.ui +++ b/src/settings/deezersettingspage.ui @@ -14,6 +14,13 @@ Deezer + + + + Enable + + + diff --git a/src/settings/tidalsettingspage.cpp b/src/settings/tidalsettingspage.cpp index f3c08b9b9..743ec062e 100644 --- a/src/settings/tidalsettingspage.cpp +++ b/src/settings/tidalsettingspage.cpp @@ -37,7 +37,6 @@ const char *TidalSettingsPage::kSettingsGroup = "Tidal"; TidalSettingsPage::TidalSettingsPage(SettingsDialog *parent) : SettingsPage(parent), ui_(new Ui::TidalSettingsPage), - //service_(dialog()->app()->internet_model()->Service()) { service_(dialog()->app()->internet_model()->Service()) { ui_->setupUi(this); @@ -75,6 +74,7 @@ void TidalSettingsPage::Load() { QSettings s; s.beginGroup(kSettingsGroup); + ui_->checkbox_enable->setChecked(s.value("enabled", false).toBool()); ui_->username->setText(s.value("username").toString()); QByteArray password = s.value("password").toByteArray(); if (password.isEmpty()) ui_->password->clear(); @@ -96,6 +96,7 @@ void TidalSettingsPage::Save() { QSettings s; s.beginGroup(kSettingsGroup); + s.setValue("enabled", ui_->checkbox_enable->isChecked()); s.setValue("username", ui_->username->text()); s.setValue("password", QString::fromUtf8(ui_->password->text().toUtf8().toBase64())); s.setValue("quality", ui_->combobox_quality->itemData(ui_->combobox_quality->currentIndex())); diff --git a/src/settings/tidalsettingspage.ui b/src/settings/tidalsettingspage.ui index dc5c3f1f7..a448aab53 100644 --- a/src/settings/tidalsettingspage.ui +++ b/src/settings/tidalsettingspage.ui @@ -14,6 +14,13 @@ Tidal + + + + Enable + + + diff --git a/src/widgets/fancytabwidget.cpp b/src/widgets/fancytabwidget.cpp index 3a56beb3d..858e6033e 100644 --- a/src/widgets/fancytabwidget.cpp +++ b/src/widgets/fancytabwidget.cpp @@ -1,749 +1,514 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://qt.nokia.com/contact. -** -**************************************************************************/ - -#include "config.h" +/* + * Strawberry Music Player + * This file was part of Clementine. + * Copyright 2018, Vikram Ambrose + * Copyright 2018, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ #include "fancytabwidget.h" +#include "stylehelper.h" +#include "core/logging.h" -#include -#include +#include + +#include #include -#include -#include -#include -#include +#include +#include #include -#include #include -#include +#include #include -#include #include -#include -#include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include #include -#include +#include +#include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include +#include -#include "core/logging.h" -#include "stylehelper.h" +const QSize FancyTabWidget::IconSize_LargeSidebar = QSize(24, 24); +const QSize FancyTabWidget::IconSize_SmallSidebar = QSize(22, 22); +const QSize FancyTabWidget::TabSize_LargeSidebar = QSize(70, 47); -using namespace Core; -using namespace Internal; +class FancyTabBar: public QTabBar { -const int FancyTabBar::m_rounding = 22; -const int FancyTabBar::m_textPadding = 4; + private: + int mouseHoverTabIndex = -1; + QMap labelCache; + QMap spacers; -void FancyTabProxyStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* p, const QWidget* widget) const { - - const QStyleOptionTabV3* v_opt = qstyleoption_cast(option); - - if (element != CE_TabBarTab || !v_opt) { - QProxyStyle::drawControl(element, option, p, widget); - return; + public: + explicit FancyTabBar(QWidget* parent=0) : QTabBar(parent) { + setMouseTracking(true); } - const QRect rect = v_opt->rect; - const bool selected = v_opt->state & State_Selected; - const bool vertical_tabs = v_opt->shape == QTabBar::RoundedWest; - const QString text = v_opt->text; + QSize sizeHint() const { - if (selected) { - //background - p->save(); - QLinearGradient grad(rect.topLeft(), rect.topRight()); - grad.setColorAt(0, QColor(255, 255, 255, 140)); - grad.setColorAt(1, QColor(255, 255, 255, 210)); - p->fillRect(rect.adjusted(0, 0, 0, -1), grad); - p->restore(); + QSize size(QTabBar::sizeHint()); - //shadows - p->setPen(QColor(0, 0, 0, 110)); - p->drawLine(rect.topLeft() + QPoint(1,-1), rect.topRight() - QPoint(0,1)); - p->drawLine(rect.bottomLeft(), rect.bottomRight()); - p->setPen(QColor(0, 0, 0, 40)); - p->drawLine(rect.topLeft(), rect.bottomLeft()); + FancyTabWidget *tabWidget = (FancyTabWidget*) parentWidget(); + if (tabWidget->mode() == FancyTabWidget::Mode_Tabs || tabWidget->mode() == FancyTabWidget::Mode_IconOnlyTabs) return size; + + QSize tabSize(tabSizeHint(0)); + size.setWidth(tabSize.width()); + int guessHeight = tabSize.height()*count(); + if (guessHeight > size.height()) + size.setHeight(guessHeight); + return size; - //highlights - p->setPen(QColor(255, 255, 255, 50)); - p->drawLine(rect.topLeft() + QPoint(0, -2), rect.topRight() - QPoint(0,2)); - p->drawLine(rect.bottomLeft() + QPoint(0, 1), rect.bottomRight() + QPoint(0,1)); - p->setPen(QColor(255, 255, 255, 40)); - p->drawLine(rect.topLeft() + QPoint(0, 0), rect.topRight()); - p->drawLine(rect.topRight() + QPoint(0, 1), rect.bottomRight() - QPoint(0, 1)); - p->drawLine(rect.bottomLeft() + QPoint(0,-1), rect.bottomRight()-QPoint(0,1)); } - QTransform m; - if (vertical_tabs) { - m = QTransform::fromTranslate(rect.left(), rect.bottom()); - m.rotate(-90); - } - else { - m = QTransform::fromTranslate(rect.left(), rect.top()); + int width() { + return tabSizeHint(0).width(); } - const QRect draw_rect(QPoint(0, 0), m.mapRect(rect).size()); + protected: + QSize tabSizeHint(int index) const { - p->save(); - p->setTransform(m); + FancyTabWidget *tabWidget = (FancyTabWidget*) parentWidget(); + QSize size = FancyTabWidget::TabSize_LargeSidebar; - QRect icon_rect(QPoint(8, 0), v_opt->iconSize); - QRect text_rect(icon_rect.topRight() + QPoint(4, 0), draw_rect.size()); - text_rect.setRight(draw_rect.width()); - icon_rect.translate(0, (draw_rect.height() - icon_rect.height()) / 2); - - QFont boldFont(p->font()); - boldFont.setPointSizeF(Utils::StyleHelper::sidebarFontSize()); - boldFont.setBold(true); - p->setFont(boldFont); - p->setPen(selected ? QColor(255, 255, 255, 160) : QColor(0, 0, 0, 110)); - int textFlags = Qt::AlignHCenter | Qt::AlignVCenter; - p->drawText(text_rect, textFlags, text); - p->setPen(selected ? QColor(60, 60, 60) : Utils::StyleHelper::panelTextColor()); -#ifndef Q_WS_MAC - if (widget) { - const QString fader_key = "tab_" + text + "_fader"; - const QString animation_key = "tab_" + text + "_animation"; - - const QString tab_hover = widget->property("tab_hover").toString(); - int fader = widget->property(fader_key.toUtf8().constData()).toInt(); - QPropertyAnimation* animation = widget->property(animation_key.toUtf8().constData()).value(); - - if (!animation) { - QWidget* mut_widget = const_cast(widget); - fader = 0; - mut_widget->setProperty(fader_key.toUtf8().constData(), fader); - animation = new QPropertyAnimation(mut_widget, fader_key.toUtf8(), mut_widget); - connect(animation, SIGNAL(valueChanged(QVariant)), mut_widget, SLOT(update())); - mut_widget->setProperty(animation_key.toUtf8().constData(), QVariant::fromValue(animation)); + if(tabWidget->mode() != FancyTabWidget::Mode_LargeSidebar) { + size = QTabBar::tabSizeHint(index); } - if (text == tab_hover) { - if (animation->state() != QAbstractAnimation::Running && fader != 40) { - animation->stop(); - animation->setDuration(80); - animation->setEndValue(40); - animation->start(); - } - } - else { - if (animation->state() != QAbstractAnimation::Running && fader != 0) { - animation->stop(); - animation->setDuration(160); - animation->setEndValue(0); - animation->start(); - } - } + return size; - if (!selected) { - p->save(); - QLinearGradient grad(draw_rect.topLeft(), vertical_tabs ? draw_rect.bottomLeft() : draw_rect.topRight()); - grad.setColorAt(0, Qt::transparent); - grad.setColorAt(0.5, QColor(255, 255, 255, fader)); - grad.setColorAt(1, Qt::transparent); - p->fillRect(draw_rect, grad); - p->setPen(QPen(grad, 1.0)); - p->drawLine(draw_rect.topLeft(), vertical_tabs ? draw_rect.bottomLeft() : draw_rect.topRight()); - p->drawLine(draw_rect.bottomRight(), vertical_tabs ? draw_rect.topRight() : draw_rect.bottomLeft()); - p->restore(); - } - } -#endif - - Utils::StyleHelper::drawIconWithShadow(v_opt->icon, icon_rect, p, QIcon::Normal); - - p->drawText(text_rect.translated(0, -1), textFlags, text); - - p->restore(); -} - -void FancyTabProxyStyle::polish(QWidget* widget) { - if (QString(widget->metaObject()->className()) == "QTabBar") { - widget->setMouseTracking(true); - widget->installEventFilter(this); - } - QProxyStyle::polish(widget); -} - -void FancyTabProxyStyle::polish(QApplication* app) { - QProxyStyle::polish(app); -} - -void FancyTabProxyStyle::polish(QPalette& palette) { - QProxyStyle::polish(palette); -} - -bool FancyTabProxyStyle::eventFilter(QObject* o, QEvent* e) { - QTabBar* bar = qobject_cast(o); - if (bar && (e->type() == QEvent::MouseMove || e->type() == QEvent::Leave)) { - QMouseEvent* event = static_cast(e); - const QString old_hovered_tab = bar->property("tab_hover").toString(); - const QString hovered_tab = e->type() == QEvent::Leave ? QString() : bar->tabText(bar->tabAt(event->pos())); - bar->setProperty("tab_hover", hovered_tab); - - if (old_hovered_tab != hovered_tab) - bar->update(); } - return false; -} - -FancyTab::FancyTab(QWidget* tabbar) - : QWidget(tabbar), tabbar(tabbar), m_fader(0) -{ - animator.setPropertyName("fader"); - animator.setTargetObject(this); - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); -} - -void FancyTab::fadeIn() -{ - animator.stop(); - animator.setDuration(80); - animator.setEndValue(40); - animator.start(); -} - -void FancyTab::fadeOut() -{ - animator.stop(); - animator.setDuration(160); - animator.setEndValue(0); - animator.start(); -} - -void FancyTab::setFader(float value) -{ - m_fader = value; - tabbar->update(); -} - -FancyTabBar::FancyTabBar(QWidget *parent) - : QWidget(parent) { - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); - setStyle(new QCommonStyle); - setMinimumWidth(qMax(2 * m_rounding, 40)); - setAttribute(Qt::WA_Hover, true); - setFocusPolicy(Qt::NoFocus); - setMouseTracking(true); // Needed for hover events - m_triggerTimer.setSingleShot(true); - - QVBoxLayout* layout = new QVBoxLayout; - layout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding)); - layout->setSpacing(0); - layout->setContentsMargins(0, 0, 0, 0); - setLayout(layout); - - // We use a zerotimer to keep the sidebar responsive - connect(&m_triggerTimer, SIGNAL(timeout()), this, SLOT(emitCurrentIndex())); -} - -FancyTabBar::~FancyTabBar() -{ - delete style(); -} - -QSize FancyTab::sizeHint() const { - QFont boldFont(font()); - boldFont.setPointSizeF(Utils::StyleHelper::sidebarFontSize()); - boldFont.setBold(true); - QFontMetrics fm(boldFont); - int spacing = 8; - int width = 60 + spacing + 2; - int iconHeight = 32; - QSize ret(width, iconHeight + spacing + fm.height()); - return ret; -} - -QSize FancyTabBar::tabSizeHint(bool minimum) const { - QFont boldFont(font()); - boldFont.setPointSizeF(Utils::StyleHelper::sidebarFontSize()); - boldFont.setBold(true); - QFontMetrics fm(boldFont); - int spacing = 8; - int width = 60 + spacing + 2; - int iconHeight = minimum ? 0 : 32; - return QSize(width, iconHeight + spacing + fm.height()); -} - -void FancyTabBar::paintEvent(QPaintEvent *event) { - Q_UNUSED(event) - QPainter p(this); - - for (int i = 0; i < count(); ++i) - if (i != currentIndex()) - paintTab(&p, i); - - // paint active tab last, since it overlaps the neighbors - if (currentIndex() != -1) - paintTab(&p, currentIndex()); -} - -bool FancyTab::event(QEvent* event) { - if (event->type() == QEvent::ToolTip) { - QFontMetrics metrics (font()); - int text_width = metrics.width(text); - - if (text_width > sizeHint().width()) { - // The text is elided: show the tooltip - QHelpEvent* he = static_cast(event); - QToolTip::showText(he->globalPos(), text); - } - else { - QToolTip::hideText(); - } - return true; + void leaveEvent(QEvent *event) { + mouseHoverTabIndex = -1; + update(); } - return QWidget::event(event); -} -void FancyTab::enterEvent(QEvent*) { - fadeIn(); -} + void mouseMoveEvent(QMouseEvent *event) { -void FancyTab::leaveEvent(QEvent*) { - fadeOut(); -} + QPoint pos = event->pos(); -QSize FancyTabBar::sizeHint() const { - QSize sh = tabSizeHint(); - return QSize(sh.width(), sh.height() * m_tabs.count()); -} - -QSize FancyTabBar::minimumSizeHint() const { - QSize sh = tabSizeHint(true); - return QSize(sh.width(), sh.height() * m_tabs.count()); -} - -QRect FancyTabBar::tabRect(int index) const { - return m_tabs[index]->geometry(); -} - -QString FancyTabBar::tabToolTip(int index) const { - return m_tabs[index]->toolTip(); -} - -void FancyTabBar::setTabToolTip(int index, const QString& toolTip) { - m_tabs[index]->setToolTip(toolTip); -} - -// This keeps the sidebar responsive since we get a repaint before loading the mode itself -void FancyTabBar::emitCurrentIndex() { - emit currentChanged(m_currentIndex); -} - -void FancyTabBar::mousePressEvent(QMouseEvent *e) { - e->accept(); - for (int index = 0; index < m_tabs.count(); ++index) { - if (tabRect(index).contains(e->pos())) { - m_currentIndex = index; + mouseHoverTabIndex = tabAt(pos); + if (mouseHoverTabIndex > -1) update(); - m_triggerTimer.start(0); - break; + QTabBar::mouseMoveEvent(event); + + } + + void paintEvent(QPaintEvent *pe) { + + FancyTabWidget *tabWidget = (FancyTabWidget*) parentWidget(); + + bool verticalTextTabs = false; + + if (tabWidget->mode() == FancyTabWidget::Mode_SmallSidebar) + verticalTextTabs = true; + + // if LargeSidebar, restore spacers + if (spacers.count() > 0 && tabWidget->mode() == FancyTabWidget::Mode_LargeSidebar) { + for (int index : spacers.keys()) { + tabWidget->insertTab(index, spacers[index], QIcon(), QString()); + tabWidget->setTabEnabled(index, false); + } + spacers.clear(); + } + if (tabWidget->mode() != FancyTabWidget::Mode_LargeSidebar) { + // traverse in the opposite order to save indices of spacers + for (int i = count() - 1; i >= 0; --i) { + // spacers are disabled tabs + if (!isTabEnabled(i) && !spacers.contains(i)) { + spacers[i] = tabWidget->widget(i); + tabWidget->removeTab(i); + --i; + } + } + } + + // Restore any label text that was hidden/cached for the IconOnlyTabs mode + if (labelCache.count() > 0 && tabWidget->mode() != FancyTabWidget::Mode_IconOnlyTabs) { + for (int i =0; i < count(); i++) { + setTabText(i, labelCache[tabWidget->widget(i)]); + } + labelCache.clear(); + } + if (tabWidget->mode() != FancyTabWidget::Mode_LargeSidebar && tabWidget->mode() != FancyTabWidget::Mode_SmallSidebar) { + // Cache and hide label text for IconOnlyTabs mode + if (tabWidget->mode() == FancyTabWidget::Mode_IconOnlyTabs && labelCache.count() == 0) { + for(int i =0; i < count(); i++) { + labelCache[tabWidget->widget(i)] = tabText(i); + setTabText(i, ""); + } + } + QTabBar::paintEvent(pe); + return; + } + + QStylePainter p(this); + + for (int index = 0; index < count(); index++) { + const bool selected = tabWidget->currentIndex() == index; + QRect tabrect = tabRect(index); + QRect selectionRect = tabrect; + if (selected) { + // Selection highlight + p.save(); + QLinearGradient grad(selectionRect.topLeft(), selectionRect.topRight()); + grad.setColorAt(0, QColor(255, 255, 255, 140)); + grad.setColorAt(1, QColor(255, 255, 255, 210)); + p.fillRect(selectionRect.adjusted(0,0,0,-1), grad); + p.restore(); + + // shadow lines + p.setPen(QColor(0, 0, 0, 110)); + p.drawLine(selectionRect.topLeft() + QPoint(1, -1), selectionRect.topRight() - QPoint(0, 1)); + p.drawLine(selectionRect.bottomLeft(), selectionRect.bottomRight()); + p.setPen(QColor(0, 0, 0, 40)); + p.drawLine(selectionRect.topLeft(), selectionRect.bottomLeft()); + + // highlights + p.setPen(QColor(255, 255, 255, 50)); + p.drawLine(selectionRect.topLeft() + QPoint(0, -2), selectionRect.topRight() - QPoint(0, 2)); + p.drawLine(selectionRect.bottomLeft() + QPoint(0, 1), selectionRect.bottomRight() + QPoint(0, 1)); + p.setPen(QColor(255, 255, 255, 40)); + p.drawLine(selectionRect.topLeft() + QPoint(0, 0), selectionRect.topRight()); + p.drawLine(selectionRect.topRight() + QPoint(0, 1), selectionRect.bottomRight() - QPoint(0, 1)); + p.drawLine(selectionRect.bottomLeft() + QPoint(0, -1), selectionRect.bottomRight() - QPoint(0, 1)); + + } + + // Mouse hover effect + if (!selected && index == mouseHoverTabIndex && isTabEnabled(index)) { + p.save(); + QLinearGradient grad(selectionRect.topLeft(), selectionRect.topRight()); + grad.setColorAt(0, Qt::transparent); + grad.setColorAt(0.5, QColor(255, 255, 255, 40)); + grad.setColorAt(1, Qt::transparent); + p.fillRect(selectionRect, grad); + p.setPen(QPen(grad, 1.0)); + p.drawLine(selectionRect.topLeft(), selectionRect.topRight()); + p.drawLine(selectionRect.bottomRight(), selectionRect.bottomLeft()); + p.restore(); + } + + // Label (Icon and Text) + { + p.save(); + QTransform m; + int textFlags; + Qt::Alignment iconFlags; + + QRect tabrectText; + QRect tabrectLabel; + + if (verticalTextTabs) { + m = QTransform::fromTranslate(tabrect.left(), tabrect.bottom()); + m.rotate(-90); + textFlags = Qt::AlignLeft | Qt::AlignVCenter ; + iconFlags = Qt::AlignLeft | Qt::AlignVCenter; + + tabrectLabel = QRect(QPoint(0, 0), m.mapRect(tabrect).size()); + + tabrectText = tabrectLabel; + tabrectText.translate(30,0); + } + else { + m = QTransform::fromTranslate(tabrect.left(), tabrect.top()); + textFlags = Qt::AlignHCenter | Qt::AlignBottom ; + iconFlags = Qt::AlignHCenter | Qt::AlignTop; + + tabrectLabel = QRect(QPoint(0, 0), m.mapRect(tabrect).size()); + + tabrectText = tabrectLabel; + tabrectText.translate(0,-5); + } + + p.setTransform(m); + + QFont boldFont(p.font()); + boldFont.setPointSizeF(Utils::StyleHelper::sidebarFontSize()); + boldFont.setBold(true); + p.setFont(boldFont); + + // Text drop shadow color + p.setPen(selected ? QColor(255, 255, 255, 160) : QColor(0, 0, 0, 110) ); + p.translate(0, 3); + p.drawText(tabrectText, textFlags, tabText(index)); + + // Text foreground color + p.translate(0, -1); + p.setPen(selected ? QColor(60, 60, 60) : Utils::StyleHelper::panelTextColor()); + p.drawText(tabrectText, textFlags, tabText(index)); + + + // Draw the icon + QRect tabrectIcon; + const int PADDING = 5; + if (verticalTextTabs) { + tabrectIcon = tabrectLabel; + tabrectIcon.setSize(FancyTabWidget::IconSize_SmallSidebar); + tabrectIcon.translate(PADDING,PADDING); + } + else { + tabrectIcon = tabrectLabel; + tabrectIcon.setSize(FancyTabWidget::IconSize_LargeSidebar); + // Center the icon + const int moveRight = (FancyTabWidget::TabSize_LargeSidebar.width() - FancyTabWidget::IconSize_LargeSidebar.width() -1)/2; + tabrectIcon.translate(moveRight,PADDING); + } + tabIcon(index).paint(&p, tabrectIcon, iconFlags); + p.restore(); + } } } -} -void FancyTabBar::addTab(const QIcon& icon, const QString& label) { - - FancyTab *tab = new FancyTab(this); - tab->icon = icon; - tab->text = label; - tab->setToolTip(label); - m_tabs.append(tab); - qobject_cast(layout())->insertWidget(layout()->count()-1, tab); -} - -void FancyTabBar::addSpacer(int size) { - qobject_cast(layout())->insertSpacerItem(layout()->count()-1, - new QSpacerItem(0, size, QSizePolicy::Fixed, QSizePolicy::Maximum)); -} - -void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const { - if (!validIndex(tabIndex)) { - qWarning("invalid index"); - return; - } - painter->save(); - - QRect rect = tabRect(tabIndex); - bool selected = (tabIndex == m_currentIndex); - - if (selected) { - //background - painter->save(); - QLinearGradient grad(rect.topLeft(), rect.topRight()); - grad.setColorAt(0, QColor(255, 255, 255, 140)); - grad.setColorAt(1, QColor(255, 255, 255, 210)); - painter->fillRect(rect.adjusted(0, 0, 0, -1), grad); - painter->restore(); - - //shadows - painter->setPen(QColor(0, 0, 0, 110)); - painter->drawLine(rect.topLeft() + QPoint(1,-1), rect.topRight() - QPoint(0,1)); - painter->drawLine(rect.bottomLeft(), rect.bottomRight()); - painter->setPen(QColor(0, 0, 0, 40)); - painter->drawLine(rect.topLeft(), rect.bottomLeft()); - - //highlights - painter->setPen(QColor(255, 255, 255, 50)); - painter->drawLine(rect.topLeft() + QPoint(0, -2), rect.topRight() - QPoint(0,2)); - painter->drawLine(rect.bottomLeft() + QPoint(0, 1), rect.bottomRight() + QPoint(0,1)); - painter->setPen(QColor(255, 255, 255, 40)); - painter->drawLine(rect.topLeft() + QPoint(0, 0), rect.topRight()); - painter->drawLine(rect.topRight() + QPoint(0, 1), rect.bottomRight() - QPoint(0, 1)); - painter->drawLine(rect.bottomLeft() + QPoint(0,-1), rect.bottomRight()-QPoint(0,1)); - } - - QString tabText(painter->fontMetrics().elidedText(this->tabText(tabIndex), Qt::ElideRight, width())); - QRect tabTextRect(tabRect(tabIndex)); - QRect tabIconRect(tabTextRect); - tabIconRect.adjust(+4, +4, -4, -4); - tabTextRect.translate(0, -2); - QFont boldFont(painter->font()); - boldFont.setPointSizeF(Utils::StyleHelper::sidebarFontSize()); - boldFont.setBold(true); - painter->setFont(boldFont); - painter->setPen(selected ? QColor(255, 255, 255, 160) : QColor(0, 0, 0, 110)); - int textFlags = Qt::AlignCenter | Qt::AlignBottom; - painter->drawText(tabTextRect, textFlags, tabText); - painter->setPen(selected ? QColor(60, 60, 60) : Utils::StyleHelper::panelTextColor()); -#ifndef Q_WS_MAC - if (!selected) { - painter->save(); - int fader = int(m_tabs[tabIndex]->fader()); - QLinearGradient grad(rect.topLeft(), rect.topRight()); - grad.setColorAt(0, Qt::transparent); - grad.setColorAt(0.5, QColor(255, 255, 255, fader)); - grad.setColorAt(1, Qt::transparent); - painter->fillRect(rect, grad); - painter->setPen(QPen(grad, 1.0)); - painter->drawLine(rect.topLeft(), rect.topRight()); - painter->drawLine(rect.bottomLeft(), rect.bottomRight()); - painter->restore(); - } -#endif - - const int textHeight = painter->fontMetrics().height(); - tabIconRect.adjust(0, 4, 0, -textHeight); - Utils::StyleHelper::drawIconWithShadow(tabIcon(tabIndex), tabIconRect, painter, QIcon::Normal); - - painter->translate(0, -1); - painter->drawText(tabTextRect, textFlags, tabText); - painter->restore(); -} - -void FancyTabBar::setCurrentIndex(int index) { - m_currentIndex = index; - update(); - emit currentChanged(m_currentIndex); -} - -////// -// FancyColorButton -////// - -class FancyColorButton : public QWidget -{ -public: - FancyColorButton(QWidget *parent) - : m_parent(parent) - { - setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); - } - - void mousePressEvent(QMouseEvent *ev) - { - if (ev->modifiers() & Qt::ShiftModifier) - Utils::StyleHelper::setBaseColor(QColorDialog::getColor(Utils::StyleHelper::requestedBaseColor(), m_parent)); - } -private: - QWidget *m_parent; }; -////// -// FancyTabWidget -////// +// Spacers are just disabled pages +void FancyTabWidget::addSpacer() { -FancyTabWidget::FancyTabWidget(QWidget* parent) - : QWidget(parent), - mode_(Mode_None), - tab_bar_(nullptr), - stack_(new QStackedLayout), - side_widget_(new QWidget), - side_layout_(new QVBoxLayout), - top_layout_(new QVBoxLayout), - use_background_(false), - menu_(nullptr), - proxy_style_(new FancyTabProxyStyle) { - side_layout_->setSpacing(0); - side_layout_->setMargin(0); - side_layout_->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding)); + QWidget *spacer = new QWidget(); + const int index = addTab(spacer, QIcon(), QString()); + setTabEnabled(index, false); - side_widget_->setLayout(side_layout_); - side_widget_->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); - - top_layout_->setMargin(0); - top_layout_->setSpacing(0); - top_layout_->addLayout(stack_); - - QHBoxLayout* main_layout = new QHBoxLayout; - main_layout->setMargin(0); - main_layout->setSpacing(1); - main_layout->addWidget(side_widget_); - main_layout->addLayout(top_layout_); - setLayout(main_layout); } -void FancyTabWidget::addTab(QWidget* tab, const QIcon& icon, const QString& label) { - stack_->addWidget(tab); - items_ << Item(icon, label); -} - -void FancyTabWidget::AddSpacer(int size) { - items_ << Item(size); -} - -void FancyTabWidget::SetBackgroundPixmap(const QPixmap& pixmap) { +void FancyTabWidget::setBackgroundPixmap(const QPixmap& pixmap) { background_pixmap_ = pixmap; update(); } -void FancyTabWidget::paintEvent(QPaintEvent*) { - - if (!use_background_) return; - - QPainter painter(this); - - QRect rect = side_widget_->rect().adjusted(0, 0, 1, 0); - rect = style()->visualRect(layoutDirection(), geometry(), rect); - Utils::StyleHelper::verticalGradient(&painter, rect, rect); - - if (!background_pixmap_.isNull()) { - QRect pixmap_rect(background_pixmap_.rect()); - pixmap_rect.moveTo(rect.topLeft()); - - while (pixmap_rect.top() < rect.bottom()) { - QRect source_rect(pixmap_rect.intersected(rect)); - source_rect.moveTo(0, 0); - painter.drawPixmap(pixmap_rect.topLeft(), background_pixmap_, source_rect); - pixmap_rect.moveTop(pixmap_rect.bottom() - 10); - } - } - - painter.setPen(Utils::StyleHelper::borderColor()); - painter.drawLine(rect.topRight(), rect.bottomRight()); - - QColor light = Utils::StyleHelper::sidebarHighlight(); - painter.setPen(light); - painter.drawLine(rect.bottomLeft(), rect.bottomRight()); -} - -int FancyTabWidget::currentIndex() const { - return stack_->currentIndex(); -} - void FancyTabWidget::setCurrentIndex(int index) { - if (FancyTabBar* bar = qobject_cast(tab_bar_)) { - bar->setCurrentIndex(index); - } - else if (QTabBar* bar = qobject_cast(tab_bar_)) { - bar->setCurrentIndex(index); - } - else { - stack_->setCurrentIndex(index); - } + + if (index >= count()) index = 0; + + QWidget *currentPage = widget(index); + QLayout *layout = currentPage->layout(); + if (bottom_widget_) layout->addWidget(bottom_widget_); + QTabWidget::setCurrentIndex(index); + } -void FancyTabWidget::setCurrentWidget(QWidget* widget) { - setCurrentIndex(stack_->indexOf(widget)); -} +void FancyTabWidget::currentTabChanged(int index) { -void FancyTabWidget::ShowWidget(int index) { - stack_->setCurrentIndex(index); + QWidget *currentPage = currentWidget(); + QLayout *layout = currentPage->layout(); + if (bottom_widget_) layout->addWidget(bottom_widget_); emit CurrentChanged(index); + +} + +FancyTabWidget::FancyTabWidget(QWidget* parent) : QTabWidget(parent), + menu_(nullptr), + mode_(Mode_None), + bottom_widget_(nullptr) + { + + FancyTabBar *tabBar = new FancyTabBar(this); + + setTabBar(tabBar); + setTabPosition(QTabWidget::West); + setMovable(true); + + connect(tabBar, SIGNAL(currentChanged(int)), this, SLOT(currentTabChanged(int))); + +} + +void FancyTabWidget::loadSettings(const char *kSettingsGroup) { + + QSettings settings; + settings.beginGroup(kSettingsGroup); + + for (int i = 0 ; i < count() ; i++) { + QString k = "tab_" + tabBar()->tabData(i).toString().toLower(); + int index = settings.value(k, i).toInt(); + if (index >= 0) + tabBar()->moveTab(i, index); + else + removeTab(i); // Does not delete page + } + + settings.endGroup(); + +} + +void FancyTabWidget::saveSettings(const char *kSettingsGroup) { + + QSettings settings; + settings.beginGroup(kSettingsGroup); + + for (int i = 0 ; i < count() ; i++) { + QString k = "tab_" + tabBar()->tabData(i).toString().toLower(); + settings.setValue(k, i); + } + + settings.endGroup(); + } void FancyTabWidget::addBottomWidget(QWidget* widget) { - top_layout_->addWidget(widget); + bottom_widget_ = widget; } -void FancyTabWidget::SetMode(Mode mode) { - // Remove previous tab bar - delete tab_bar_; - tab_bar_ = nullptr; +int FancyTabWidget::addTab(QWidget *widget, const QIcon &icon, const QString &label) { + return insertTab(count(), widget, icon, label); +} - use_background_ = false; +int FancyTabWidget::insertTab(int index, QWidget *widget, const QIcon &icon, const QString &label) { - // Create new tab bar - switch (mode) { - case Mode_None: - default: - qLog(Warning) << "Unknown fancy tab mode" << mode; - // fallthrough - - case Mode_LargeSidebar: { - FancyTabBar* bar = new FancyTabBar(this); - side_layout_->insertWidget(0, bar); - tab_bar_ = bar; - - for (const Item& item : items_) { - if (item.type_ == Item::Type_Spacer) - bar->addSpacer(item.spacer_size_); - else - bar->addTab(item.tab_icon_, item.tab_label_); - } - - bar->setCurrentIndex(stack_->currentIndex()); - connect(bar, SIGNAL(currentChanged(int)), SLOT(ShowWidget(int))); - - use_background_ = true; - - break; - } - - case Mode_Tabs: - MakeTabBar(QTabBar::RoundedNorth, true, false, false); - break; - - case Mode_IconOnlyTabs: - MakeTabBar(QTabBar::RoundedNorth, false, true, false); - break; - - case Mode_SmallSidebar: - MakeTabBar(QTabBar::RoundedWest, true, true, true); - use_background_ = true; - break; - - case Mode_PlainSidebar: - MakeTabBar(QTabBar::RoundedWest, true, true, false); - break; + QWidget *page(nullptr); + if (tabs_.contains(label)) page = tabs_.value(label); + else { + page = new QWidget(); + // In order to achieve the same effect as the "Bottom Widget" of the old Nokia based FancyTabWidget a VBoxLayout is used on each page + QVBoxLayout *layout = new QVBoxLayout(); + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(widget); + page->setLayout(layout); + tabs_.insert(label, page); } - tab_bar_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + for (int i = 0 ; i < count() ; i++) { + QString l = tabBar()->tabData(i).toString().toLower(); + if (l == label) return i; + } + + const int actualIndex = QTabWidget::insertTab(index, page, icon, label); + tabBar()->setTabData(actualIndex, QVariant(label)); + return actualIndex; + +} + +void FancyTabWidget::delTab(const QString &label) { + + for (int i = 0 ; i < count() ; i++) { + QString l = tabBar()->tabData(i).toString().toLower(); + if (l == label) QTabWidget::removeTab(i); + } + +} + +void FancyTabWidget::paintEvent(QPaintEvent *pe) { + + if (mode() != FancyTabWidget::Mode_LargeSidebar && mode() != FancyTabWidget::Mode_SmallSidebar) { + QTabWidget::paintEvent(pe); + return; + } + QStylePainter p(this); + + // The brown color (Ubuntu) you see on the background gradient + QColor baseColor = StyleHelper::baseColor(); + + QRect backgroundRect = rect(); + backgroundRect.setWidth(((FancyTabBar*)tabBar())->width()); + p.fillRect(backgroundRect, baseColor); + + // Horizontal gradient over the sidebar from transparent to dark + Utils::StyleHelper::verticalGradient(&p, backgroundRect, backgroundRect,false); + + // Draw the translucent png graphics over the gradient fill + { + if (!background_pixmap_.isNull()) { + QRect pixmap_rect(background_pixmap_.rect()); + pixmap_rect.moveTo(backgroundRect.topLeft()); + + while (pixmap_rect.top() < backgroundRect.bottom()) { + QRect source_rect(pixmap_rect.intersected(backgroundRect)); + source_rect.moveTo(0, 0); + p.drawPixmap(pixmap_rect.topLeft(), background_pixmap_,source_rect); + pixmap_rect.moveTop(pixmap_rect.bottom() - 10); + } + } + } + + // Shadow effect of the background + { + QColor light(255, 255, 255, 80); + p.setPen(light); + p.drawLine(backgroundRect.topRight() - QPoint(1, 0), backgroundRect.bottomRight() - QPoint(1, 0)); + QColor dark(0, 0, 0, 90); + p.setPen(dark); + p.drawLine(backgroundRect.topLeft(), backgroundRect.bottomLeft()); + + p.setPen(Utils::StyleHelper::borderColor()); + p.drawLine(backgroundRect.topRight(), backgroundRect.bottomRight()); + } + +} + +void FancyTabWidget::tabBarUpdateGeometry() { + tabBar()->updateGeometry(); +} + +void FancyTabWidget::SetMode(FancyTabWidget::Mode mode) { mode_ = mode; - emit ModeChanged(mode); - update(); -} -void FancyTabWidget::contextMenuEvent(QContextMenuEvent* e) { - if (!menu_) { - menu_ = new QMenu(this); - - QSignalMapper* mapper = new QSignalMapper(this); - QActionGroup* group = new QActionGroup(this); - AddMenuItem(mapper, group, tr("Large sidebar"), Mode_LargeSidebar); - AddMenuItem(mapper, group, tr("Small sidebar"), Mode_SmallSidebar); - AddMenuItem(mapper, group, tr("Plain sidebar"), Mode_PlainSidebar); - AddMenuItem(mapper, group, tr("Tabs on top"), Mode_Tabs); - AddMenuItem(mapper, group, tr("Icons on top"), Mode_IconOnlyTabs); - menu_->addActions(group->actions()); - - connect(mapper, SIGNAL(mapped(int)), SLOT(SetMode(int))); + if (mode == FancyTabWidget::Mode_Tabs || mode == FancyTabWidget::Mode_IconOnlyTabs) { + setTabPosition(QTabWidget::North); + } + else { + setTabPosition(QTabWidget::West); } - menu_->popup(e->globalPos()); + tabBar()->updateGeometry(); + updateGeometry(); + + // There appears to be a bug in QTabBar which causes tabSizeHint to be ignored thus the need for this second shot repaint + QTimer::singleShot(1, this, SLOT(tabBarUpdateGeometry())); + + emit ModeChanged(mode); + } -void FancyTabWidget::AddMenuItem(QSignalMapper* mapper, QActionGroup* group, const QString& text, Mode mode) { +void FancyTabWidget::addMenuItem(QSignalMapper* mapper, QActionGroup* group, const QString& text, Mode mode) { + QAction* action = group->addAction(text); action->setCheckable(true); mapper->setMapping(action, mode); connect(action, SIGNAL(triggered()), mapper, SLOT(map())); if (mode == mode_) action->setChecked(true); + } -void FancyTabWidget::MakeTabBar(QTabBar::Shape shape, bool text, bool icons, bool fancy) { - QTabBar* bar = new QTabBar(this); - bar->setShape(shape); - bar->setDocumentMode(true); - bar->setUsesScrollButtons(true); - bar->setElideMode(Qt::ElideRight); - if (shape == QTabBar::RoundedWest) { - bar->setIconSize(QSize(22, 22)); +void FancyTabWidget::contextMenuEvent(QContextMenuEvent* e) { + + if (!menu_) { + + menu_ = new QMenu(this); + QSignalMapper* mapper = new QSignalMapper(this); + QActionGroup* group = new QActionGroup(this); + addMenuItem(mapper, group, tr("Large sidebar"), Mode_LargeSidebar); + addMenuItem(mapper, group, tr("Small sidebar"), Mode_SmallSidebar); + addMenuItem(mapper, group, tr("Plain sidebar"), Mode_PlainSidebar); + addMenuItem(mapper, group, tr("Tabs on top"), Mode_Tabs); + addMenuItem(mapper, group, tr("Icons on top"), Mode_IconOnlyTabs); + menu_->addActions(group->actions()); + connect(mapper, SIGNAL(mapped(int)), SLOT(SetMode(int))); + } - if (fancy) { - bar->setStyle(proxy_style_.get()); - } + menu_->popup(e->globalPos()); - if (shape == QTabBar::RoundedNorth) - top_layout_->insertWidget(0, bar); - else - side_layout_->insertWidget(0, bar); - - for (const Item& item : items_) { - if (item.type_ != Item::Type_Tab) continue; - - QString label = item.tab_label_; - if (shape == QTabBar::RoundedWest) { - label = QFontMetrics(font()).elidedText(label, Qt::ElideMiddle, 100); - } - - int tab_id = -1; - if (icons && text) - tab_id = bar->addTab(item.tab_icon_, label); - else if (icons) - tab_id = bar->addTab(item.tab_icon_, QString()); - else if (text) - tab_id = bar->addTab(label); - - bar->setTabToolTip(tab_id, item.tab_label_); - } - - bar->setCurrentIndex(stack_->currentIndex()); - connect(bar, SIGNAL(currentChanged(int)), SLOT(ShowWidget(int))); - tab_bar_ = bar; } diff --git a/src/widgets/fancytabwidget.h b/src/widgets/fancytabwidget.h index df2bd9939..1a5c360b0 100644 --- a/src/widgets/fancytabwidget.h +++ b/src/widgets/fancytabwidget.h @@ -1,249 +1,107 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://qt.nokia.com/contact. -** -**************************************************************************/ +/* + * Strawberry Music Player + * This file was part of Clementine. + * Copyright 2018, Vikram Ambrose + * Copyright 2018, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ #ifndef FANCYTABWIDGET_H #define FANCYTABWIDGET_H -#include "config.h" - #include -#include #include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include #include +#include +#include +#include #include -class QEvent; -class QMouseEvent; -class QPaintEvent; -class QContextMenuEvent; - namespace Core { namespace Internal { -class FancyTabProxyStyle : public QProxyStyle { +class FancyTabWidget : public QTabWidget { Q_OBJECT -public: - void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const; - void polish(QWidget *widget); - void polish(QApplication *app); - void polish(QPalette &palette); + public: + FancyTabWidget(QWidget* parent = 0); + int addTab(QWidget *widget, const QIcon &icon, const QString &label); + void delTab(const QString &label); + int insertTab(int index, QWidget *widget, const QIcon &icon, const QString &label); + void addBottomWidget(QWidget* widget); -protected: - bool eventFilter(QObject *o, QEvent *e); -}; + void setBackgroundPixmap(const QPixmap& pixmap); + void addSpacer(); -class FancyTab : public QWidget { - Q_OBJECT + void loadSettings(const char *); + void saveSettings(const char *); - Q_PROPERTY(float fader READ fader WRITE setFader) -public: - FancyTab(QWidget *tabbar); - float fader() { return m_fader; } - void setFader(float value); - - QSize sizeHint() const; - - void fadeIn(); - void fadeOut(); - - QIcon icon; - QString text; - -protected: - bool event(QEvent *); - void enterEvent(QEvent *); - void leaveEvent(QEvent *); - -private: - QPropertyAnimation animator; - QWidget *tabbar; - float m_fader; -}; - -class FancyTabBar : public QWidget { - Q_OBJECT - - public: - FancyTabBar(QWidget *parent = nullptr); - ~FancyTabBar(); - - void paintEvent(QPaintEvent *event); - void paintTab(QPainter *painter, int tabIndex) const; - void mousePressEvent(QMouseEvent *); - bool validIndex(int index) const { return index >= 0 && index < m_tabs.count(); } - - QSize sizeHint() const; - QSize minimumSizeHint() const; - - void addTab(const QIcon &icon, const QString &label); - void addSpacer(int size = 40); - void removeTab(int index) { - FancyTab *tab = m_tabs.takeAt(index); - delete tab; - } - void setCurrentIndex(int index); - int currentIndex() const { return m_currentIndex; } - - void setTabToolTip(int index, const QString &toolTip); - QString tabToolTip(int index) const; - - QIcon tabIcon(int index) const {return m_tabs.at(index)->icon; } - QString tabText(int index) const { return m_tabs.at(index)->text; } - int count() const { return m_tabs.count(); } - QRect tabRect(int index) const; - -signals: - void currentChanged(int); - -public slots: - void emitCurrentIndex(); - -private: - static const int m_rounding; - static const int m_textPadding; - int m_currentIndex; - QList m_tabs; - QTimer m_triggerTimer; - QSize tabSizeHint(bool minimum = false) const; - -}; - -class FancyTabWidget : public QWidget { - Q_OBJECT - - public: - FancyTabWidget(QWidget *parent = nullptr); - - // Values are persisted - only add to the end - enum Mode { - Mode_None = 0, - - Mode_LargeSidebar = 1, - Mode_SmallSidebar = 2, - Mode_Tabs = 3, - Mode_IconOnlyTabs = 4, - Mode_PlainSidebar = 5, - }; - - struct Item { - Item(const QIcon &icon, const QString &label) - : type_(Type_Tab), tab_label_(label), tab_icon_(icon), spacer_size_(0) {} - Item(int size) : type_(Type_Spacer), spacer_size_(size) {} - - enum Type { - Type_Tab, - Type_Spacer, + // Values are persisted - only add to the end + enum Mode { + Mode_None = 0, + Mode_LargeSidebar, + Mode_SmallSidebar, + Mode_Tabs, + Mode_IconOnlyTabs, + Mode_PlainSidebar, }; - Type type_; - QString tab_label_; - QIcon tab_icon_; - int spacer_size_; - }; + static const QSize TabSize_LargeSidebar; - void addTab(QWidget *tab, const QIcon &icon, const QString &label); - void AddSpacer(int size = 40); - void SetBackgroundPixmap(const QPixmap &pixmap); + static const QSize IconSize_LargeSidebar; + static const QSize IconSize_SmallSidebar; - void addBottomWidget(QWidget *widget); + Mode mode() { return mode_; } - int currentIndex() const; - Mode mode() const { return mode_; } + signals: + void ModeChanged(FancyTabWidget::Mode mode); + void CurrentChanged(int); -public slots: - void setCurrentIndex(int index); - void setCurrentWidget(QWidget *widget); - void SetMode(Mode mode); - void SetMode(int mode) { SetMode(Mode(mode)); } + public slots: + void setCurrentIndex(int index); + void SetMode(Mode mode); + // Mapper mapped signal needs this convenience function + void SetMode(int mode) { SetMode(Mode(mode)); } -signals: - void CurrentChanged(int index); - void ModeChanged(FancyTabWidget::Mode mode); + private slots: + void tabBarUpdateGeometry(); + void currentTabChanged(int); -protected: - void paintEvent(QPaintEvent *event); - void contextMenuEvent(QContextMenuEvent *e); + protected: + void paintEvent(QPaintEvent *); + void contextMenuEvent(QContextMenuEvent* e); + private: + void addMenuItem(QSignalMapper* mapper, QActionGroup* group, const QString& text, Mode mode); -private slots: - void ShowWidget(int index); + QPixmap background_pixmap_; + QMenu* menu_; + Mode mode_; + QWidget *bottom_widget_; -private: - void MakeTabBar(QTabBar::Shape shape, bool text, bool icons, bool fancy); - void AddMenuItem(QSignalMapper *mapper, QActionGroup *group, const QString &text, Mode mode); + QHash tabs_; - Mode mode_; - QList items_; - - QWidget *tab_bar_; - QStackedLayout *stack_; - QPixmap background_pixmap_; - QWidget *side_widget_; - QVBoxLayout *side_layout_; - QVBoxLayout *top_layout_; - - bool use_background_; - - QMenu *menu_; - - std::unique_ptr proxy_style_; }; } // namespace Internal } // namespace Core -Q_DECLARE_METATYPE(QPropertyAnimation*); - -using Core::Internal::FancyTab; -using Core::Internal::FancyTabBar; using Core::Internal::FancyTabWidget; #endif // FANCYTABWIDGET_H