From 62a9dab5b108c58be23786f9679f2552bdf05bc6 Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Sun, 24 Apr 2022 19:49:40 -0700 Subject: [PATCH 1/4] lib/widgets: add TTabWidget The current implementation requires that TTabWidget is given a "large" and "small" image, and that those images won't change for the lifetime of the object. It wouldn't be hard to relax either constraint, but this was all that we need for Tarsnap-GUI, so I refrained from spending more time on it. --- lib/widgets/TTabWidget.cpp | 108 +++++++++++++++++++++++++++++++++++++ lib/widgets/TTabWidget.h | 69 ++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 lib/widgets/TTabWidget.cpp create mode 100644 lib/widgets/TTabWidget.h diff --git a/lib/widgets/TTabWidget.cpp b/lib/widgets/TTabWidget.cpp new file mode 100644 index 00000000..54b647d5 --- /dev/null +++ b/lib/widgets/TTabWidget.cpp @@ -0,0 +1,108 @@ +#include "TTabWidget.h" + +WARNINGS_DISABLE +#include +#include +#include +#include +WARNINGS_ENABLE + +class QPaintEvent; +class QResizeEvent; + +#define RIGHT_PADDING 3 + +TTabWidget::TTabWidget(QWidget *parent) + : QTabWidget(parent), + _needRecalculate(true), + _image_x(0), + _largeLogo(nullptr), + _smallLogo(nullptr), + _image(nullptr) +{ +} + +TTabWidget::~TTabWidget() +{ + delete _largeLogo; + delete _smallLogo; +} + +void TTabWidget::setLargeLogoFilename(const QString &largeLogoFilename) +{ + // Check that we haven't used this before. + Q_ASSERT(_largeLogo == nullptr); + + // Save filename and load logo. + _largeLogoFilename = largeLogoFilename; + _largeLogo = new QPixmap(_largeLogoFilename); + _needRecalculate = true; +} + +void TTabWidget::setSmallLogoFilename(const QString &smallLogoFilename) +{ + // Check that we haven't used this before. + Q_ASSERT(_smallLogo == nullptr); + + // Save filename and load logo. + _smallLogoFilename = smallLogoFilename; + _smallLogo = new QPixmap(_smallLogoFilename); + _needRecalculate = true; +} + +void TTabWidget::resizeEvent(QResizeEvent *event) +{ + QTabWidget::resizeEvent(event); + + // We need to recalculate the widths. + // + // If this was a perfectly reusable class, we would also recalculate after + // every ::tabInserted() and ::tabRemoved(). However, this is sufficient + // for Tarsnap-GUI. + _needRecalculate = true; +} + +void TTabWidget::paintEvent(QPaintEvent *event) +{ + (void)event; /* UNUSED */ + + // Update width calculation if necessary. + if(_needRecalculate) + recalculateWidth(); + + // Bail if it's too narrow to draw either logo. + if(_image == nullptr) + return; + + // Draw the selected logo. + QPainter p(this); + p.drawPixmap(_image_x, 0, *_image); +} + +void TTabWidget::recalculateWidth() +{ + // We don't need to call this again (unless something else changes). + _needRecalculate = true; + + // Bail if we're missing either logo. + if((!_largeLogo) || (!_smallLogo)) + return; + + // How much width is available? + int remainingWidth = width() - tabBar()->width() - RIGHT_PADDING; + + // Pick which image (if any) to use. + if(remainingWidth > _largeLogo->width()) + _image = _largeLogo; + else if(remainingWidth > _smallLogo->width()) + _image = _smallLogo; + else + { + _image = nullptr; + // It doesn't matter what _image_x is in this case. + return; + } + + // How far along (width-wise) should we draw the logo? + _image_x = width() - RIGHT_PADDING - _image->width(); +} diff --git a/lib/widgets/TTabWidget.h b/lib/widgets/TTabWidget.h new file mode 100644 index 00000000..cf3dde5b --- /dev/null +++ b/lib/widgets/TTabWidget.h @@ -0,0 +1,69 @@ +#ifndef TTABWIDGET_H +#define TTABWIDGET_H + +#include "warnings-disable.h" + +WARNINGS_DISABLE +#include +#include +#include +WARNINGS_ENABLE + +/* Forward declaration(s). */ +class QPaintEvent; +class QPixmap; +class QResizeEvent; +class QWidget; + +/*! + * \ingroup lib-widgets + * \brief The TTabWidget widget is a QTabWidget which will display one of two + * images in the top-right corner. + * + * Both largeLogoFilename and smallLogoFilename must be set exactly once. + * They are essentially arguments to the constructor, but using an indirect + * route so that TTabWidget can be used in the Qt Designer. + */ +class TTabWidget : public QTabWidget +{ + Q_OBJECT + + //! Filename of the large icon. Can only be set once. + Q_PROPERTY(QString largeLogoFilename MEMBER _largeLogoFilename WRITE + setLargeLogoFilename DESIGNABLE true) + //! Filename of the small icon. Can only be set once. + Q_PROPERTY(QString smallLogoFilename MEMBER _smallLogoFilename WRITE + setSmallLogoFilename DESIGNABLE true) + +public: + //! Constructor. + explicit TTabWidget(QWidget *parent = nullptr); + ~TTabWidget() override; + + //! Set the filename of the large icon. + void setLargeLogoFilename(const QString &largeLogoFilename); + //! Set the filename of the small icon. + void setSmallLogoFilename(const QString &smallLogoFilename); + +protected: + //! We need to recalculate the available width. + void resizeEvent(QResizeEvent *event) override; + //! Draw one of the logos in the top-right corner. + void paintEvent(QPaintEvent *event) override; + +private: + bool _needRecalculate; + int _image_x; + + // These are only here so that we can set them in the designer + QString _largeLogoFilename; + QString _smallLogoFilename; + + QPixmap *_largeLogo; + QPixmap *_smallLogo; + QPixmap *_image; // Always a pointer to an existing object (or nullptr). + + void recalculateWidth(); +}; + +#endif // TTABWIDGET_H From 26a9af81000f537c1abbd51ad4b6a3b90823abbb Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Sun, 24 Apr 2022 19:49:41 -0700 Subject: [PATCH 2/4] lib/plugins: add TTabWidget --- lib/plugins/TTabWidgetPlugin.cpp | 47 ++++++++++++++++++++++++++++++++ lib/plugins/TTabWidgetPlugin.h | 32 ++++++++++++++++++++++ lib/plugins/plugins.cpp | 2 ++ lib/plugins/plugins.pro | 4 +++ 4 files changed, 85 insertions(+) create mode 100644 lib/plugins/TTabWidgetPlugin.cpp create mode 100644 lib/plugins/TTabWidgetPlugin.h diff --git a/lib/plugins/TTabWidgetPlugin.cpp b/lib/plugins/TTabWidgetPlugin.cpp new file mode 100644 index 00000000..94914b25 --- /dev/null +++ b/lib/plugins/TTabWidgetPlugin.cpp @@ -0,0 +1,47 @@ +#include "TTabWidgetPlugin.h" + +#include "TTabWidget.h" + +TTabWidgetPlugin::TTabWidgetPlugin(QObject *parent) : QObject(parent) +{ +} + +QIcon TTabWidgetPlugin::icon() const +{ + return QIcon(); +} + +QString TTabWidgetPlugin::group() const +{ + return QStringLiteral("Containers"); +} + +QString TTabWidgetPlugin::includeFile() const +{ + return QStringLiteral("TTabWidget.h"); +} + +QString TTabWidgetPlugin::name() const +{ + return QStringLiteral("TTabWidget"); +} + +QString TTabWidgetPlugin::toolTip() const +{ + return QString(); +} + +QString TTabWidgetPlugin::whatsThis() const +{ + return QString(); +} + +QWidget *TTabWidgetPlugin::createWidget(QWidget *parent) +{ + return new TTabWidget(parent); +} + +bool TTabWidgetPlugin::isContainer() const +{ + return false; +} diff --git a/lib/plugins/TTabWidgetPlugin.h b/lib/plugins/TTabWidgetPlugin.h new file mode 100644 index 00000000..1e05dbb0 --- /dev/null +++ b/lib/plugins/TTabWidgetPlugin.h @@ -0,0 +1,32 @@ +#ifndef TTABWIGETPLUGIN_H +#define TTABWIGETPLUGIN_H + +#include "warnings-disable.h" + +WARNINGS_DISABLE +#include +#include +WARNINGS_ENABLE + +class TTabWidgetPlugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + explicit TTabWidgetPlugin(QObject *parent = nullptr); + + QIcon icon() const override; + QString group() const override; + QString includeFile() const override; + QString name() const override; + QString toolTip() const override; + QString whatsThis() const override; + QWidget *createWidget(QWidget *parent) override; + bool isContainer() const override; + +private: + bool initialized = false; +}; + +#endif /* !TTABWIGETPLUGIN_H */ diff --git a/lib/plugins/plugins.cpp b/lib/plugins/plugins.cpp index dbb11ccf..aa6f4afb 100644 --- a/lib/plugins/plugins.cpp +++ b/lib/plugins/plugins.cpp @@ -6,6 +6,7 @@ #include "TPathComboBrowsePlugin.h" #include "TPathLineBrowsePlugin.h" #include "TPopupPushButtonPlugin.h" +#include "TTabWidgetPlugin.h" #include "TTextViewPlugin.h" #include "TWizardPagePlugin.h" @@ -17,6 +18,7 @@ TarsnapPlugins::TarsnapPlugins(QObject *parent) : QObject(parent) widgets.append(new TPathComboBrowsePlugin(this)); widgets.append(new TPathLineBrowsePlugin(this)); widgets.append(new TPopupPushButtonPlugin(this)); + widgets.append(new TTabWidgetPlugin(this)); widgets.append(new TTextViewPlugin(this)); widgets.append(new TWizardPagePlugin(this)); } diff --git a/lib/plugins/plugins.pro b/lib/plugins/plugins.pro index 071f9a0d..3162d8d9 100644 --- a/lib/plugins/plugins.pro +++ b/lib/plugins/plugins.pro @@ -11,6 +11,7 @@ HEADERS = plugins.h \ ../widgets/TPathComboBrowse.h \ ../widgets/TPathLineBrowse.h \ ../widgets/TPopupPushButton.h \ + ../widgets/TTabWidget.h \ ../widgets/TTextView.h \ ../widgets/TWizardPage.h \ TBusyLabelPlugin.h \ @@ -19,6 +20,7 @@ HEADERS = plugins.h \ TPathComboBrowsePlugin.h \ TPathLineBrowsePlugin.h \ TPopupPushButtonPlugin.h \ + TTabWidgetPlugin.h \ TTextViewPlugin.h \ TWizardPagePlugin.h @@ -29,6 +31,7 @@ SOURCES = plugins.cpp \ ../widgets/TPathComboBrowse.cpp \ ../widgets/TPathLineBrowse.cpp \ ../widgets/TPopupPushButton.cpp \ + ../widgets/TTabWidget.cpp \ ../widgets/TTextView.cpp \ ../widgets/TWizardPage.cpp \ TBusyLabelPlugin.cpp \ @@ -37,6 +40,7 @@ SOURCES = plugins.cpp \ TPathComboBrowsePlugin.cpp \ TPathLineBrowsePlugin.cpp \ TPopupPushButtonPlugin.cpp \ + TTabWidgetPlugin.cpp \ TTextViewPlugin.cpp \ TWizardPagePlugin.cpp From 6af5c3eb47309a408cc8f04b9a6adae439140040 Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Sun, 24 Apr 2022 19:49:42 -0700 Subject: [PATCH 3/4] tests/lib-widgets: add TTabWidget --- tests/lib-widgets/test-lib-widgets.cpp | 13 +++++++++++++ tests/lib-widgets/test-lib-widgets.pro | 5 ++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/lib-widgets/test-lib-widgets.cpp b/tests/lib-widgets/test-lib-widgets.cpp index 4793f90f..4463ef33 100644 --- a/tests/lib-widgets/test-lib-widgets.cpp +++ b/tests/lib-widgets/test-lib-widgets.cpp @@ -24,6 +24,7 @@ WARNINGS_ENABLE #include "TOkLabel.h" #include "TPathComboBrowse.h" #include "TPathLineBrowse.h" +#include "TTabWidget.h" #include "TTextView.h" #include "TWizard.h" #include "TWizardPage.h" @@ -43,6 +44,7 @@ private slots: void busylabel_on_off(); void pathlinebrowse(); void pathcombobrowse(); + void ttabwidget(); void twizard(); void textview(); }; @@ -291,6 +293,17 @@ void TestLibWidgets::pathcombobrowse() delete pcb; } +void TestLibWidgets::ttabwidget() +{ + TTabWidget *tabwidget = new TTabWidget(); + tabwidget->setLargeLogoFilename(":/logos/tarsnap-header-h29.png"); + tabwidget->setSmallLogoFilename(":/logos/tarsnap-icon-h29.png"); + + VISUAL_INIT(tabwidget); + + delete tabwidget; +} + void TestLibWidgets::twizard() { TWizard *wizard = new TWizard(); diff --git a/tests/lib-widgets/test-lib-widgets.pro b/tests/lib-widgets/test-lib-widgets.pro index a3bea499..f8a6dd61 100644 --- a/tests/lib-widgets/test-lib-widgets.pro +++ b/tests/lib-widgets/test-lib-widgets.pro @@ -8,7 +8,8 @@ FORMS += \ ../../lib/forms/TPathLineBrowse.ui \ ../../lib/forms/TWizard.ui -RESOURCES += ../../lib/resources/lib-resources.qrc +RESOURCES += ../../lib/resources/lib-resources.qrc \ + ../../resources/resources.qrc HEADERS += \ ../../lib/widgets/TBusyLabel.h \ @@ -16,6 +17,7 @@ HEADERS += \ ../../lib/widgets/TOkLabel.h \ ../../lib/widgets/TPathComboBrowse.h \ ../../lib/widgets/TPathLineBrowse.h \ + ../../lib/widgets/TTabWidget.h \ ../../lib/widgets/TTextView.h \ ../../lib/widgets/TWizard.h \ ../../lib/widgets/TWizardPage.h \ @@ -28,6 +30,7 @@ SOURCES += test-lib-widgets.cpp \ ../../lib/widgets/TOkLabel.cpp \ ../../lib/widgets/TPathComboBrowse.cpp \ ../../lib/widgets/TPathLineBrowse.cpp \ + ../../lib/widgets/TTabWidget.cpp \ ../../lib/widgets/TTextView.cpp \ ../../lib/widgets/TWizard.cpp \ ../../lib/widgets/TWizardPage.cpp From ba7f8f956b6a0d91a43556e5e8c09c4fa663c2e0 Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Sun, 24 Apr 2022 19:49:43 -0700 Subject: [PATCH 4/4] MainWindow: use TTabWidget --- Tarsnap.pro | 2 ++ forms/mainwindow.ui | 14 +++++++++- src/widgets/mainwindow.cpp | 40 ---------------------------- src/widgets/mainwindow.h | 3 --- tests/mainwindow/test-mainwindow.pro | 2 ++ 5 files changed, 17 insertions(+), 44 deletions(-) diff --git a/Tarsnap.pro b/Tarsnap.pro index d01320c9..b9b71bed 100644 --- a/Tarsnap.pro +++ b/Tarsnap.pro @@ -33,6 +33,7 @@ SOURCES += \ lib/widgets/TPathComboBrowse.cpp \ lib/widgets/TPathLineBrowse.cpp \ lib/widgets/TPopupPushButton.cpp \ + lib/widgets/TTabWidget.cpp \ lib/widgets/TTextView.cpp \ lib/widgets/TWizard.cpp \ lib/widgets/TWizardPage.cpp \ @@ -116,6 +117,7 @@ HEADERS += \ lib/widgets/TPathComboBrowse.h \ lib/widgets/TPathLineBrowse.h \ lib/widgets/TPopupPushButton.h \ + lib/widgets/TTabWidget.h \ lib/widgets/TTextView.h \ lib/widgets/TWizard.h \ lib/widgets/TWizardPage.h \ diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index 7fc48a10..1bff9e11 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -42,7 +42,7 @@ Qt::Vertical - + 0 @@ -103,6 +103,12 @@ border-radius: 2px; 0 + + :/logos/tarsnap-header-h29.png + + + :/logos/tarsnap-icon-h29.png + false @@ -692,6 +698,12 @@ font-size: 12px; + + TTabWidget + QTabWidget +
TTabWidget.h
+ 1 +
TTextView QPlainTextEdit diff --git a/src/widgets/mainwindow.cpp b/src/widgets/mainwindow.cpp index cce92725..767bf6f7 100644 --- a/src/widgets/mainwindow.cpp +++ b/src/widgets/mainwindow.cpp @@ -48,13 +48,9 @@ WARNINGS_ENABLE #include "widgets/settingswidget.h" #include "widgets/stoptasksdialog.h" -#define MAIN_LOGO_RIGHT_MARGIN 5 -#define MAIN_LOGO_FUDGE (-10) - MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), _ui(new Ui::MainWindow), - _minWidth(0), _menuBar(nullptr), _aboutToQuit(false), _backupTaskRunning(false), @@ -273,42 +269,6 @@ void MainWindow::backupTabValidStatus(bool valid) _ui->actionBackupMorphIntoJob->setEnabled(valid); } -void MainWindow::paintEvent(QPaintEvent *event) -{ - (void)event; /* UNUSED */ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); - if(_minWidth == 0) - _minWidth = _ui->mainTabWidget->tabBar()->width(); - // Find out how much room is left to display an icon, including a - // "fudge factor" to accommodate margins. - int remaining_width = frameGeometry().width() - _minWidth + MAIN_LOGO_FUDGE; - - // Compare with the width of the png files. - QPixmap logoPixmap(":/logos/tarsnap-header-h29.png"); - QPixmap iconPixmap(":/logos/tarsnap-icon-h29.png"); - - // Pick which image (if any) to use - QPixmap *pixmap; - if(remaining_width > logoPixmap.width()) - pixmap = &logoPixmap; - else if(remaining_width > iconPixmap.width()) - pixmap = &iconPixmap; - else - pixmap = nullptr; - - // Draw image - if(pixmap != nullptr) - { - QIcon icon(*pixmap); - int x = width() - MAIN_LOGO_RIGHT_MARGIN - pixmap->width(); - int y = _ui->mainContentSplitter->y() + _ui->centralWidget->y(); - icon.paint(&p, x, y, pixmap->width(), pixmap->height()); - } -} - void MainWindow::keyPressEvent(QKeyEvent *event) { switch(event->key()) diff --git a/src/widgets/mainwindow.h b/src/widgets/mainwindow.h index b05c1f14..185dec28 100644 --- a/src/widgets/mainwindow.h +++ b/src/widgets/mainwindow.h @@ -159,8 +159,6 @@ public slots: void cancelTaskRequested(BaseTask *task, const QUuid uuid); protected: - //! Draw the Tarsnap logo in the top-right corner. - void paintEvent(QPaintEvent *event) override; //! Handles the escape key; passes other events on. void keyPressEvent(QKeyEvent *event) override; //! Start checking whether there are running tasks. @@ -187,7 +185,6 @@ private slots: private: Ui::MainWindow *_ui; - int _minWidth; QMenuBar *_menuBar; bool _aboutToQuit; bool _backupTaskRunning; diff --git a/tests/mainwindow/test-mainwindow.pro b/tests/mainwindow/test-mainwindow.pro index 2c997ddd..4acca646 100644 --- a/tests/mainwindow/test-mainwindow.pro +++ b/tests/mainwindow/test-mainwindow.pro @@ -38,6 +38,7 @@ HEADERS += \ ../../lib/widgets/TBusyLabel.h \ ../../lib/widgets/TElidedLabel.h \ ../../lib/widgets/TPopupPushButton.h \ + ../../lib/widgets/TTabWidget.h \ ../../lib/widgets/TTextView.h \ ../../src/backuptask.h \ ../../src/basetask.h \ @@ -97,6 +98,7 @@ SOURCES += test-mainwindow.cpp \ ../../lib/widgets/TBusyLabel.cpp \ ../../lib/widgets/TElidedLabel.cpp \ ../../lib/widgets/TPopupPushButton.cpp \ + ../../lib/widgets/TTabWidget.cpp \ ../../lib/widgets/TTextView.cpp \ ../../src/backuptask.cpp \ ../../src/basetask.cpp \