mirror of
https://github.com/clementine-player/Clementine
synced 2024-12-22 07:54:18 +01:00
Replace Nokia based FancyTabWidget with standard QTabWidget (#5956)
* Replace Nokia sidebar widget with QTabWidget The old sidebar widget was written by Nokia 10 years ago and was a hand made hardcoded mess of widgets trying to emulate a QTabWidget. This commit completely replaces it with a widget of the same name (FancyTabWidget) but is a much simpler subclass of the standard QTabWidget allowing for a 50% code reduction. There is still some manual draw code copied over to get the exact same look of the previous widget but this is not strictly necessary and can be later refactored with simpler drawControl code based on styling preferences. Benefits: - 50% code reduction - Easier to understand standard QTabWidget mechanics - Built-in support for re-arranging and closing tabs * Save and restore sidebar tab order Allow the user to rearrange the tab order by dragging tabs to a new location. Tab order is saved on exit and restored on start * Fix some code formatting issues
This commit is contained in:
parent
2e4a67b8da
commit
790fc2ff28
@ -255,37 +255,40 @@ MainWindow::MainWindow(Application* app, SystemTrayIcon* tray_icon, OSD* osd,
|
|||||||
SLOT(AddToPlaylist(QMimeData*)));
|
SLOT(AddToPlaylist(QMimeData*)));
|
||||||
|
|
||||||
// Add tabs to the fancy tab widget
|
// Add tabs to the fancy tab widget
|
||||||
ui_->tabs->AddTab(global_search_view_,
|
ui_->tabs->addTab(global_search_view_,
|
||||||
IconLoader::Load("search", IconLoader::Base),
|
IconLoader::Load("search", IconLoader::Base),
|
||||||
tr("Search", "Global search settings dialog title."));
|
tr("Search", "Global search settings dialog title."));
|
||||||
ui_->tabs->AddTab(library_view_,
|
ui_->tabs->addTab(library_view_,
|
||||||
IconLoader::Load("folder-sound", IconLoader::Base),
|
IconLoader::Load("folder-sound", IconLoader::Base),
|
||||||
tr("Library"));
|
tr("Library"));
|
||||||
ui_->tabs->AddTab(file_view_,
|
ui_->tabs->addTab(file_view_,
|
||||||
IconLoader::Load("document-open", IconLoader::Base),
|
IconLoader::Load("document-open", IconLoader::Base),
|
||||||
tr("Files"));
|
tr("Files"));
|
||||||
ui_->tabs->AddTab(playlist_list_,
|
ui_->tabs->addTab(playlist_list_,
|
||||||
IconLoader::Load("view-media-playlist", IconLoader::Base),
|
IconLoader::Load("view-media-playlist", IconLoader::Base),
|
||||||
tr("Playlists"));
|
tr("Playlists"));
|
||||||
ui_->tabs->AddTab(internet_view_,
|
ui_->tabs->addTab(internet_view_,
|
||||||
IconLoader::Load("applications-internet", IconLoader::Base),
|
IconLoader::Load("applications-internet", IconLoader::Base),
|
||||||
tr("Internet"));
|
tr("Internet"));
|
||||||
ui_->tabs->AddTab(
|
ui_->tabs->addTab(
|
||||||
device_view_container_,
|
device_view_container_,
|
||||||
IconLoader::Load("multimedia-player-ipod-mini-blue", IconLoader::Base),
|
IconLoader::Load("multimedia-player-ipod-mini-blue", IconLoader::Base),
|
||||||
tr("Devices"));
|
tr("Devices"));
|
||||||
ui_->tabs->AddSpacer();
|
ui_->tabs->addSpacer();
|
||||||
ui_->tabs->AddTab(song_info_view_,
|
ui_->tabs->addTab(song_info_view_,
|
||||||
IconLoader::Load("view-media-lyrics", IconLoader::Base),
|
IconLoader::Load("view-media-lyrics", IconLoader::Base),
|
||||||
tr("Song info"));
|
tr("Song info"));
|
||||||
ui_->tabs->AddTab(artist_info_view_,
|
ui_->tabs->addTab(artist_info_view_,
|
||||||
IconLoader::Load("x-clementine-artist", IconLoader::Base),
|
IconLoader::Load("x-clementine-artist", IconLoader::Base),
|
||||||
tr("Artist info"));
|
tr("Artist info"));
|
||||||
|
|
||||||
// Add the now playing widget to the fancy tab widget
|
// Add the now playing widget to the fancy tab widget
|
||||||
ui_->tabs->AddBottomWidget(ui_->now_playing);
|
ui_->tabs->addBottomWidget(ui_->now_playing);
|
||||||
|
|
||||||
ui_->tabs->SetBackgroundPixmap(QPixmap(":/sidebar_background.png"));
|
ui_->tabs->setBackgroundPixmap(QPixmap(":/sidebar_background.png"));
|
||||||
|
|
||||||
|
// Do this only after all default tabs have been added
|
||||||
|
ui_->tabs->loadSettings(kSettingsGroup);
|
||||||
|
|
||||||
track_position_timer_->setInterval(kTrackPositionUpdateTimeMs);
|
track_position_timer_->setInterval(kTrackPositionUpdateTimeMs);
|
||||||
connect(track_position_timer_, SIGNAL(timeout()),
|
connect(track_position_timer_, SIGNAL(timeout()),
|
||||||
@ -979,7 +982,7 @@ MainWindow::MainWindow(Application* app, SystemTrayIcon* tray_icon, OSD* osd,
|
|||||||
settings_.value("splitter_state").toByteArray())) {
|
settings_.value("splitter_state").toByteArray())) {
|
||||||
ui_->splitter->setSizes(QList<int>() << 300 << width() - 300);
|
ui_->splitter->setSizes(QList<int>() << 300 << width() - 300);
|
||||||
}
|
}
|
||||||
ui_->tabs->SetCurrentIndex(
|
ui_->tabs->setCurrentIndex(
|
||||||
settings_.value("current_tab", 1 /* Library tab */).toInt());
|
settings_.value("current_tab", 1 /* Library tab */).toInt());
|
||||||
FancyTabWidget::Mode default_mode = FancyTabWidget::Mode_LargeSidebar;
|
FancyTabWidget::Mode default_mode = FancyTabWidget::Mode_LargeSidebar;
|
||||||
ui_->tabs->SetMode(
|
ui_->tabs->SetMode(
|
||||||
@ -1265,8 +1268,10 @@ void MainWindow::SaveGeometry() {
|
|||||||
settings_.setValue("geometry", saveGeometry());
|
settings_.setValue("geometry", saveGeometry());
|
||||||
}
|
}
|
||||||
settings_.setValue("splitter_state", ui_->splitter->saveState());
|
settings_.setValue("splitter_state", ui_->splitter->saveState());
|
||||||
settings_.setValue("current_tab", ui_->tabs->current_index());
|
settings_.setValue("current_tab", ui_->tabs->currentIndex());
|
||||||
settings_.setValue("tab_mode", ui_->tabs->mode());
|
settings_.setValue("tab_mode", ui_->tabs->mode());
|
||||||
|
|
||||||
|
ui_->tabs->saveSettings(kSettingsGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::SavePlaybackStatus() {
|
void MainWindow::SavePlaybackStatus() {
|
||||||
@ -2911,7 +2916,7 @@ void MainWindow::HandleNotificationPreview(OSD::Behaviour type, QString line1,
|
|||||||
|
|
||||||
void MainWindow::ScrollToInternetIndex(const QModelIndex& index) {
|
void MainWindow::ScrollToInternetIndex(const QModelIndex& index) {
|
||||||
internet_view_->ScrollToIndex(index);
|
internet_view_->ScrollToIndex(index);
|
||||||
ui_->tabs->SetCurrentWidget(internet_view_);
|
ui_->tabs->setCurrentWidget(internet_view_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::AddPodcast() {
|
void MainWindow::AddPodcast() {
|
||||||
@ -2919,11 +2924,11 @@ void MainWindow::AddPodcast() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::FocusLibraryTab() {
|
void MainWindow::FocusLibraryTab() {
|
||||||
ui_->tabs->SetCurrentWidget(library_view_);
|
ui_->tabs->setCurrentWidget(library_view_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::FocusGlobalSearchField() {
|
void MainWindow::FocusGlobalSearchField() {
|
||||||
ui_->tabs->SetCurrentWidget(global_search_view_);
|
ui_->tabs->setCurrentWidget(global_search_view_);
|
||||||
global_search_view_->FocusSearchField();
|
global_search_view_->FocusSearchField();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,233 +1,97 @@
|
|||||||
/**************************************************************************
|
/* This file is part of Clementine.
|
||||||
**
|
Copyright 2018, Vikram Ambrose <ambroseworks@gmail.com>
|
||||||
** This file is part of Qt Creator
|
|
||||||
**
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
it under the terms of the GNU General Public License as published by
|
||||||
**
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
(at your option) any later version.
|
||||||
**
|
|
||||||
** Commercial Usage
|
Clementine is distributed in the hope that it will be useful,
|
||||||
**
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
** accordance with the Qt Commercial License Agreement provided with the
|
GNU General Public License for more details.
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and Nokia.
|
You should have received a copy of the GNU General Public License
|
||||||
**
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||||
** 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.
|
|
||||||
**
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FANCYTABWIDGET_H
|
#ifndef FANCYTABWIDGET_H
|
||||||
#define FANCYTABWIDGET_H
|
#define FANCYTABWIDGET_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <QIcon>
|
#include <QTabWidget>
|
||||||
#include <QPropertyAnimation>
|
|
||||||
#include <QProxyStyle>
|
|
||||||
#include <QTabBar>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
class QActionGroup;
|
class QActionGroup;
|
||||||
class QMenu;
|
class QMenu;
|
||||||
class QPainter;
|
|
||||||
class QSignalMapper;
|
class QSignalMapper;
|
||||||
class QStackedLayout;
|
|
||||||
class QStatusBar;
|
|
||||||
class QVBoxLayout;
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class FancyTabProxyStyle : public QProxyStyle {
|
|
||||||
|
class FancyTabWidget : public QTabWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void drawControl(ControlElement element, const QStyleOption* option,
|
FancyTabWidget(QWidget* parent = 0);
|
||||||
QPainter* painter, const QWidget* widget) const;
|
int addTab(QWidget * page, const QIcon & icon, const QString & label);
|
||||||
void polish(QWidget* widget);
|
int insertTab(int index, QWidget * page, const QIcon & icon, const QString & label);
|
||||||
void polish(QApplication* app);
|
void addBottomWidget(QWidget* widget);
|
||||||
void polish(QPalette& palette);
|
|
||||||
|
|
||||||
protected:
|
void setBackgroundPixmap(const QPixmap& pixmap);
|
||||||
bool eventFilter(QObject* o, QEvent* e);
|
void addSpacer();
|
||||||
};
|
|
||||||
|
|
||||||
class FancyTab : public QWidget {
|
void loadSettings(const char *);
|
||||||
Q_OBJECT
|
void saveSettings(const char *);
|
||||||
|
// Values are persisted - only add to the end
|
||||||
|
enum Mode {
|
||||||
|
Mode_None = 0,
|
||||||
|
Mode_LargeSidebar,
|
||||||
|
Mode_SmallSidebar,
|
||||||
|
Mode_Tabs,
|
||||||
|
Mode_IconOnlyTabs,
|
||||||
|
Mode_PlainSidebar,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const QSize TabSize_LargeSidebar;
|
||||||
|
|
||||||
Q_PROPERTY(float fader READ fader WRITE setFader)
|
static const QSize IconSize_LargeSidebar;
|
||||||
public:
|
static const QSize IconSize_SmallSidebar;
|
||||||
FancyTab(QWidget* tabbar);
|
|
||||||
float fader() { return m_fader; }
|
Mode mode() { return mode_; }
|
||||||
void setFader(float value);
|
|
||||||
|
|
||||||
QSize sizeHint() const;
|
signals:
|
||||||
|
void ModeChanged(FancyTabWidget::Mode mode);
|
||||||
|
|
||||||
void fadeIn();
|
public slots:
|
||||||
void fadeOut();
|
void setCurrentIndex(int index);
|
||||||
|
void SetMode(Mode mode);
|
||||||
|
// Mapper mapped signal needs this convenience function
|
||||||
|
void SetMode(int mode) { SetMode(Mode(mode)); }
|
||||||
|
|
||||||
QIcon icon;
|
private slots:
|
||||||
QString text;
|
void tabBarUpdateGeometry();
|
||||||
|
void currentTabChanged(int);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool event(QEvent*);
|
void paintEvent(QPaintEvent *);
|
||||||
void enterEvent(QEvent*);
|
void contextMenuEvent(QContextMenuEvent* e);
|
||||||
void leaveEvent(QEvent*);
|
private:
|
||||||
|
void addMenuItem(QSignalMapper* mapper, QActionGroup* group,
|
||||||
|
const QString& text, Mode mode);
|
||||||
|
|
||||||
private:
|
QPixmap background_pixmap_;
|
||||||
QPropertyAnimation animator;
|
QMenu* menu_;
|
||||||
QWidget* tabbar;
|
Mode mode_;
|
||||||
float m_fader;
|
QWidget *bottom_widget_;
|
||||||
};
|
|
||||||
|
|
||||||
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<FancyTab*> 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, };
|
|
||||||
|
|
||||||
Type type_;
|
|
||||||
QString tab_label_;
|
|
||||||
QIcon tab_icon_;
|
|
||||||
int spacer_size_;
|
|
||||||
};
|
|
||||||
|
|
||||||
void AddTab(QWidget* tab, const QIcon& icon, const QString& label);
|
|
||||||
void AddSpacer(int size = 40);
|
|
||||||
void SetBackgroundPixmap(const QPixmap& pixmap);
|
|
||||||
|
|
||||||
void AddBottomWidget(QWidget* widget);
|
|
||||||
|
|
||||||
int current_index() const;
|
|
||||||
Mode mode() const { return mode_; }
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void SetCurrentIndex(int index);
|
|
||||||
void SetCurrentWidget(QWidget* widget);
|
|
||||||
void SetMode(Mode mode);
|
|
||||||
void SetMode(int mode) { SetMode(Mode(mode)); }
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void CurrentChanged(int index);
|
|
||||||
void ModeChanged(FancyTabWidget::Mode mode);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void paintEvent(QPaintEvent* event);
|
|
||||||
void contextMenuEvent(QContextMenuEvent* e);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void ShowWidget(int index);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void MakeTabBar(QTabBar::Shape shape, bool text, bool icons, bool fancy);
|
|
||||||
void AddMenuItem(QSignalMapper* mapper, QActionGroup* group,
|
|
||||||
const QString& text, Mode mode);
|
|
||||||
|
|
||||||
Mode mode_;
|
|
||||||
QList<Item> 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<FancyTabProxyStyle> proxy_style_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QPropertyAnimation*);
|
|
||||||
|
|
||||||
using Core::Internal::FancyTab;
|
|
||||||
using Core::Internal::FancyTabBar;
|
|
||||||
using Core::Internal::FancyTabWidget;
|
using Core::Internal::FancyTabWidget;
|
||||||
|
|
||||||
#endif // FANCYTABWIDGET_H
|
#endif // FANCYTABWIDGET_H
|
||||||
|
Loading…
Reference in New Issue
Block a user