diff --git a/src/branding/default/branding.desc b/src/branding/default/branding.desc index e7b9d9898..365af30e9 100644 --- a/src/branding/default/branding.desc +++ b/src/branding/default/branding.desc @@ -44,9 +44,15 @@ windowPlacement: center # Kind of sidebar (panel on the left, showing progress). # - "widget" or unset, use traditional sidebar (logo, items) # - "none", hide it entirely -# - "qml", use sidebar.qml from branding folder +# - "qml", use calamares-sidebar.qml from branding folder sidebar: widget +# Kind of navigation (button panel on the bottom). +# - "widget" or unset, use traditional navigation +# - "none", hide it entirely +# - "qml", use calamares-navigation.qml from branding folder +navigation: widget + # These are strings shown to the user in the user interface. # There is no provision for translating them -- since they # are names, the string is included as-is. diff --git a/src/calamares/CalamaresWindow.cpp b/src/calamares/CalamaresWindow.cpp index f2ff42aa8..a97d2dccf 100644 --- a/src/calamares/CalamaresWindow.cpp +++ b/src/calamares/CalamaresWindow.cpp @@ -138,11 +138,118 @@ CalamaresWindow::getQmlSidebar( int desiredWidth ) QQuickWidget* w = new QQuickWidget( this ); w->setFixedWidth( desiredWidth ); w->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + w->setResizeMode( QQuickWidget::SizeRootObjectToView ); w->setSource( QUrl( CalamaresUtils::searchQmlFile( CalamaresUtils::QmlSearch::Both, QStringLiteral( "calamares-sidebar" ) ) ) ); return w; } +/** @brief Get a button-sized icon. */ +static inline QPixmap +getButtonIcon( const QString& name ) +{ + return Calamares::Branding::instance()->image( name, QSize( 22, 22 ) ); +} + +static inline void +setButtonIcon( QPushButton* button, const QString& name ) +{ + auto icon = getButtonIcon( name ); + if ( button && !icon.isNull() ) + { + button->setIcon( icon ); + } +} + +QWidget* +CalamaresWindow::getWidgetNavigation() +{ + QWidget* navigation = new QWidget( this ); + QBoxLayout* bottomLayout = new QHBoxLayout; + bottomLayout->addStretch(); + + // Create buttons and sets an initial icon; the icons may change + { + auto* back = new QPushButton( getButtonIcon( QStringLiteral( "go-previous" ) ), tr( "&Back" ), navigation ); + back->setObjectName( "view-button-back" ); + back->setEnabled( m_viewManager->backEnabled() ); + connect( back, &QPushButton::clicked, m_viewManager, &Calamares::ViewManager::back ); + connect( m_viewManager, &Calamares::ViewManager::backEnabledChanged, back, &QPushButton::setEnabled ); + connect( m_viewManager, &Calamares::ViewManager::backLabelChanged, back, &QPushButton::setText ); + connect( m_viewManager, &Calamares::ViewManager::backIconChanged, this, [=]( QString n ) { + setButtonIcon( back, n ); + } ); + bottomLayout->addWidget( back ); + } + { + auto* next = new QPushButton( getButtonIcon( QStringLiteral( "go-next" ) ), tr( "&Next" ), navigation ); + next->setObjectName( "view-button-next" ); + next->setEnabled( m_viewManager->nextEnabled() ); + connect( next, &QPushButton::clicked, m_viewManager, &Calamares::ViewManager::next ); + connect( m_viewManager, &Calamares::ViewManager::nextEnabledChanged, next, &QPushButton::setEnabled ); + connect( m_viewManager, &Calamares::ViewManager::nextLabelChanged, next, &QPushButton::setText ); + connect( m_viewManager, &Calamares::ViewManager::nextIconChanged, this, [=]( QString n ) { + setButtonIcon( next, n ); + } ); + bottomLayout->addWidget( next ); + } + bottomLayout->addSpacing( 12 ); + { + auto* quit = new QPushButton( getButtonIcon( QStringLiteral( "dialog-cancel" ) ), tr( "&Cancel" ), navigation ); + quit->setObjectName( "view-button-cancel" ); + connect( quit, &QPushButton::clicked, m_viewManager, &Calamares::ViewManager::quit ); + connect( m_viewManager, &Calamares::ViewManager::quitEnabledChanged, quit, &QPushButton::setEnabled ); + connect( m_viewManager, &Calamares::ViewManager::quitLabelChanged, quit, &QPushButton::setText ); + connect( m_viewManager, &Calamares::ViewManager::quitIconChanged, this, [=]( QString n ) { + setButtonIcon( quit, n ); + } ); + connect( m_viewManager, &Calamares::ViewManager::quitTooltipChanged, quit, &QPushButton::setToolTip ); + connect( m_viewManager, &Calamares::ViewManager::quitVisibleChanged, quit, &QPushButton::setVisible ); + bottomLayout->addWidget( quit ); + } + + navigation->setLayout( bottomLayout ); + return navigation; +} + +QWidget* +CalamaresWindow::getQmlNavigation() +{ + CalamaresUtils::registerCalamaresModels(); + QQuickWidget* w = new QQuickWidget( this ); + w->setFixedHeight( 64 ); + w->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + w->setResizeMode( QQuickWidget::SizeRootObjectToView ); + w->setSource( QUrl( + CalamaresUtils::searchQmlFile( CalamaresUtils::QmlSearch::Both, QStringLiteral( "calamares-navigation" ) ) ) ); + return w; +} + +/**@brief Picks one of two methods to call + * + * Calls method (member function) @p widget or @p qml with arguments @p a + * on the given window, based on the flavor. + */ +template < typename widgetMaker, typename... args > +QWidget* +flavoredWidget( Calamares::Branding::PanelFlavor flavor, + CalamaresWindow* w, + widgetMaker widget, + widgetMaker qml, + args... a ) +{ + // Member-function calling syntax is (object.*member)(args) + switch ( flavor ) + { + case Calamares::Branding::PanelFlavor::Widget: + return ( w->*widget )( a... ); + case Calamares::Branding::PanelFlavor::Qml: + return ( w->*qml )( a... ); + case Calamares::Branding::PanelFlavor::None: + return nullptr; + } +} + CalamaresWindow::CalamaresWindow( QWidget* parent ) : QWidget( parent ) , m_debugWindow( nullptr ) @@ -188,20 +295,12 @@ CalamaresWindow::CalamaresWindow( QWidget* parent ) QBoxLayout* mainLayout = new QHBoxLayout; setLayout( mainLayout ); - QWidget* sideBox = nullptr; - switch ( branding->sidebarFlavor() ) - { - case Calamares::Branding::SidebarFlavor::Widget: - sideBox = getWidgetSidebar( - qBound( 100, CalamaresUtils::defaultFontHeight() * 12, w < windowPreferredWidth ? 100 : 190 ) ); - break; - case Calamares::Branding::SidebarFlavor::Qml: - sideBox = getQmlSidebar( - qBound( 100, CalamaresUtils::defaultFontHeight() * 12, w < windowPreferredWidth ? 100 : 190 ) ); - break; - case Calamares::Branding::SidebarFlavor::None: - sideBox = nullptr; - } + QWidget* sideBox = flavoredWidget( + branding->sidebarFlavor(), + this, + &CalamaresWindow::getWidgetSidebar, + &CalamaresWindow::getQmlSidebar, + qBound( 100, CalamaresUtils::defaultFontHeight() * 12, w < windowPreferredWidth ? 100 : 190 ) ); if ( sideBox ) { mainLayout->addWidget( sideBox ); @@ -219,9 +318,19 @@ CalamaresWindow::CalamaresWindow( QWidget* parent ) // and requires an extra show() (at least with KWin/X11) which // is too annoying. Instead, leave it up to ignoring-the-quit- // event, which is also the ViewManager's responsibility. + QBoxLayout* contentsLayout = new QVBoxLayout; + contentsLayout->addWidget( m_viewManager->centralWidget() ); + QWidget* navigation = flavoredWidget( + branding->navigationFlavor(), this, &CalamaresWindow::getWidgetNavigation, &CalamaresWindow::getQmlNavigation ); + if ( navigation ) + { + contentsLayout->addWidget( navigation ); + } + + mainLayout->addLayout( contentsLayout ); - mainLayout->addWidget( m_viewManager->centralWidget() ); CalamaresUtils::unmarginLayout( mainLayout ); + CalamaresUtils::unmarginLayout( contentsLayout ); setStyleSheet( Calamares::Branding::instance()->stylesheet() ); } diff --git a/src/calamares/CalamaresWindow.h b/src/calamares/CalamaresWindow.h index 5cbbdfca6..d6592c99a 100644 --- a/src/calamares/CalamaresWindow.h +++ b/src/calamares/CalamaresWindow.h @@ -51,9 +51,14 @@ protected: virtual void closeEvent( QCloseEvent* e ) override; private: + // Two variations on sidebar (the progress view) QWidget* getWidgetSidebar( int desiredWidth ); QWidget* getQmlSidebar( int desiredWidth ); + // Two variations on navigation (buttons at bottom) + QWidget* getWidgetNavigation(); + QWidget* getQmlNavigation(); + QPointer< Calamares::DebugWindow > m_debugWindow; // Managed by self Calamares::ViewManager* m_viewManager; }; diff --git a/src/calamares/calamares-navigation.qml b/src/calamares/calamares-navigation.qml new file mode 100644 index 000000000..c7cd91835 --- /dev/null +++ b/src/calamares/calamares-navigation.qml @@ -0,0 +1,57 @@ +import io.calamares.ui 1.0 +import io.calamares.core 1.0 + +import QtQuick 2.3 +import QtQuick.Controls 2.10 +import QtQuick.Layouts 1.3 + +Rectangle { + id: navigationBar; + color: Branding.styleString( Branding.SidebarBackground ); + + RowLayout { + id: buttonBar + height: 64; + anchors.fill: parent; + + Item + { + Layout.fillWidth: true; + } + + Button + { + text: ViewManager.backLabel; + icon.name: ViewManager.backIcon; + + enabled: ViewManager.backEnabled; + visible: true; + onClicked: { ViewManager.back(); } + } + Button + { + text: ViewManager.nextLabel; + icon.name: ViewManager.nextIcon; + + enabled: ViewManager.nextEnabled; + visible: true; + onClicked: { ViewManager.next(); } + } + Button + { + Layout.leftMargin: 3 * buttonBar.spacing; // little gap from back/next + Layout.rightMargin: 2 * buttonBar.spacing + text: ViewManager.quitLabel; + icon.name: ViewManager.quitIcon; + + ToolTip.visible: hovered + ToolTip.timeout: 5000 + ToolTip.delay: 1000 + ToolTip.text: ViewManager.quitTooltip; + + enabled: ViewManager.quitEnabled; + visible: ViewManager.quitVisible; + onClicked: { ViewManager.quit(); } + } + } +} diff --git a/src/calamares/calamares-sidebar.qml b/src/calamares/calamares-sidebar.qml index aa794e94a..183a9acb2 100644 --- a/src/calamares/calamares-sidebar.qml +++ b/src/calamares/calamares-sidebar.qml @@ -1,36 +1,49 @@ -import QtQuick 2.3 import io.calamares.ui 1.0 import io.calamares.core 1.0 -Column { +import QtQuick 2.3 +import QtQuick.Layouts 1.3 Rectangle { - id: hello - width: 200 - height: 100 - color: "red" + id: sideBar; + color: Branding.styleString( Branding.SidebarBackground ); - Text { - anchors.centerIn: parent - text: Branding.string(Branding.VersionedName) - } -} + ColumnLayout { + anchors.fill: parent; + spacing: 0; -/* perhaps we could show a branding image here */ + Image { + Layout.topMargin: 12; + Layout.bottomMargin: 12; + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + id: logo; + width: 80; + height: width; // square + source: "file:/" + Branding.imagePath(Branding.ProductLogo); + sourceSize.width: width; + sourceSize.height: height; + } -Repeater { - model: ViewManager - Rectangle { - width: 200 - height: 75 - color: "black" + Repeater { + model: ViewManager + Rectangle { + Layout.leftMargin: 12; + width: parent.width - 24; + height: 35; + radius: 6; + color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarTextHighlight : Branding.SidebarBackground ); - Text { - anchors.centerIn: parent - color: index == ViewManager.currentStepIndex ? "green" : "yellow" - text: display + Text { + anchors.verticalCenter: parent.verticalCenter; + x: parent.x + 12; + color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarTextSelect : Branding.SidebarText ); + text: display; + } + } } - } -} + Item { + Layout.fillHeight: true; + } + } } diff --git a/src/calamares/calamares.qrc b/src/calamares/calamares.qrc index fdcd5e05d..17db2e08a 100644 --- a/src/calamares/calamares.qrc +++ b/src/calamares/calamares.qrc @@ -1,5 +1,6 @@ calamares-sidebar.qml + calamares-navigation.qml diff --git a/src/libcalamaresui/Branding.cpp b/src/libcalamaresui/Branding.cpp index 5c41f5ea2..25fab307e 100644 --- a/src/libcalamaresui/Branding.cpp +++ b/src/libcalamaresui/Branding.cpp @@ -419,10 +419,11 @@ Branding::initSimpleSettings( const YAML::Node& doc ) { QStringLiteral( "free" ), WindowPlacement::Free }, { QStringLiteral( "center" ), WindowPlacement::Center } }; - static const NamedEnumTable< SidebarFlavor > sidebarFlavorNames { - { QStringLiteral( "widget" ), SidebarFlavor::Widget }, - { QStringLiteral( "none" ), SidebarFlavor::None }, - { QStringLiteral( "qml" ), SidebarFlavor::Qml } + static const NamedEnumTable< PanelFlavor > sidebarFlavorNames { + { QStringLiteral( "widget" ), PanelFlavor::Widget }, + { QStringLiteral( "none" ), PanelFlavor::None }, + { QStringLiteral( "hidden" ), PanelFlavor::None }, + { QStringLiteral( "qml" ), PanelFlavor::Qml } }; // clang-format on // *INDENT-ON* @@ -448,6 +449,12 @@ Branding::initSimpleSettings( const YAML::Node& doc ) cWarning() << "Branding module-setting *sidebar* interpreted as" << sidebarFlavorNames.find( m_sidebarFlavor, ok ); } + m_navigationFlavor = sidebarFlavorNames.find( getString( doc, "navigation" ), ok); + if ( !ok ) + { + cWarning() << "Branding module-setting *navigation* interpreted as" + << sidebarFlavorNames.find( m_navigationFlavor, ok ); + } QString windowSize = getString( doc, "windowSize" ); if ( !windowSize.isEmpty() ) diff --git a/src/libcalamaresui/Branding.h b/src/libcalamaresui/Branding.h index 88f658473..b7ba637d6 100644 --- a/src/libcalamaresui/Branding.h +++ b/src/libcalamaresui/Branding.h @@ -124,13 +124,13 @@ public: }; Q_ENUM( WindowPlacement ) ///@brief What kind of sidebar to use in the main window - enum class SidebarFlavor + enum class PanelFlavor { None, Widget, Qml }; - Q_ENUM( SidebarFlavor ) + Q_ENUM( PanelFlavor ) static Branding* instance(); @@ -185,7 +185,9 @@ public: bool windowPlacementCentered() const { return m_windowPlacement == WindowPlacement::Center; } ///@brief Which sidebar flavor is configured - SidebarFlavor sidebarFlavor() const { return m_sidebarFlavor; } + PanelFlavor sidebarFlavor() const { return m_sidebarFlavor; } + ///@brief Which navigation flavor is configured + PanelFlavor navigationFlavor() const { return m_navigationFlavor; } /** * Creates a map called "branding" in the global storage, and inserts an @@ -227,7 +229,8 @@ private: WindowDimension m_windowHeight, m_windowWidth; WindowPlacement m_windowPlacement; - SidebarFlavor m_sidebarFlavor = SidebarFlavor::Widget; + PanelFlavor m_sidebarFlavor = PanelFlavor::Widget; + PanelFlavor m_navigationFlavor = PanelFlavor::Widget; }; template < typename U > diff --git a/src/libcalamaresui/ViewManager.cpp b/src/libcalamaresui/ViewManager.cpp index 93f23bd2f..e80d4afd8 100644 --- a/src/libcalamaresui/ViewManager.cpp +++ b/src/libcalamaresui/ViewManager.cpp @@ -38,6 +38,12 @@ #include #include +#define UPDATE_BUTTON_PROPERTY( name, value ) \ + { \ + m_##name = value; \ + emit name##Changed( m_##name ); \ + } + namespace Calamares { @@ -88,43 +94,12 @@ ViewManager::ViewManager( QObject* parent ) m_stack->setContentsMargins( 0, 0, 0, 0 ); mainLayout->addWidget( m_stack ); - // Create buttons and sets an initial icon; the icons may change - m_back = new QPushButton( getButtonIcon( QStringLiteral( "go-previous" ) ), tr( "&Back" ), m_widget ); - m_back->setObjectName( "view-button-back" ); - m_next = new QPushButton( getButtonIcon( QStringLiteral( "go-next" ) ), tr( "&Next" ), m_widget ); - m_next->setObjectName( "view-button-next" ); - m_quit = new QPushButton( getButtonIcon( QStringLiteral( "dialog-cancel" ) ), tr( "&Cancel" ), m_widget ); - m_quit->setObjectName( "view-button-cancel" ); - - CALAMARES_RETRANSLATE_SLOT( &ViewManager::updateButtonLabels ) - - QBoxLayout* bottomLayout = new QHBoxLayout; - mainLayout->addLayout( bottomLayout ); - bottomLayout->addStretch(); - bottomLayout->addWidget( m_back ); - bottomLayout->addWidget( m_next ); - bottomLayout->addSpacing( 12 ); - bottomLayout->addWidget( m_quit ); - - connect( m_next, &QPushButton::clicked, this, &ViewManager::next ); - connect( m_back, &QPushButton::clicked, this, &ViewManager::back ); - m_back->setEnabled( false ); + updateButtonLabels(); - connect( m_quit, &QPushButton::clicked, this, [this]() { - if ( this->confirmCancelInstallation() ) - { - qApp->quit(); - } - } ); connect( JobQueue::instance(), &JobQueue::failed, this, &ViewManager::onInstallationFailed ); connect( JobQueue::instance(), &JobQueue::finished, this, &ViewManager::next ); - if ( Calamares::Settings::instance()->disableCancel() ) - { - m_quit->setVisible( false ); - } - - // onInstallationFailed( "Title of Failure", "Body of Failure"); // for testing paste functionality + CALAMARES_RETRANSLATE_SLOT( &ViewManager::updateButtonLabels ) } @@ -149,7 +124,8 @@ ViewManager::addViewStep( ViewStep* step ) // If this is the first inserted view step, update status of "Next" button if ( m_steps.count() == 1 ) { - m_next->setEnabled( step->isNextEnabled() ); + m_nextEnabled = step->isNextEnabled(); + emit nextEnabledChanged( m_nextEnabled ); } } @@ -160,13 +136,15 @@ ViewManager::insertViewStep( int before, ViewStep* step ) emit beginInsertRows( QModelIndex(), before, before ); m_steps.insert( before, step ); connect( step, &ViewStep::enlarge, this, &ViewManager::enlarge ); + // TODO: this can be a regular slot connect( step, &ViewStep::nextStatusChanged, this, [this]( bool status ) { ViewStep* vs = qobject_cast< ViewStep* >( sender() ); if ( vs ) { if ( vs == m_steps.at( m_currentStep ) ) { - m_next->setEnabled( status ); + m_nextEnabled = status; + emit nextEnabledChanged( m_nextEnabled ); } } } ); @@ -371,8 +349,8 @@ ViewManager::next() { // Reached the end in a weird state (e.g. no finished step after an exec) executing = false; - m_next->setEnabled( false ); - m_back->setEnabled( false ); + UPDATE_BUTTON_PROPERTY( nextEnabled, false ) + UPDATE_BUTTON_PROPERTY( backEnabled, false ) } updateCancelEnabled( !settings->disableCancel() && !( executing && settings->disableCancelDuringExec() ) ); } @@ -383,8 +361,8 @@ ViewManager::next() if ( m_currentStep < m_steps.count() ) { - m_next->setEnabled( !executing && m_steps.at( m_currentStep )->isNextEnabled() ); - m_back->setEnabled( !executing && m_steps.at( m_currentStep )->isBackEnabled() ); + UPDATE_BUTTON_PROPERTY( nextEnabled, !executing && m_steps.at( m_currentStep )->isNextEnabled() ) + UPDATE_BUTTON_PROPERTY( backEnabled, !executing && m_steps.at( m_currentStep )->isBackEnabled() ) } updateButtonLabels(); @@ -406,43 +384,43 @@ ViewManager::updateButtonLabels() // If we're going into the execution step / install phase, other message if ( stepIsExecute( m_steps, m_currentStep + 1 ) ) { - m_next->setText( nextIsInstallationStep ); - setButtonIcon( m_next, "run-install" ); + UPDATE_BUTTON_PROPERTY( nextLabel, nextIsInstallationStep ) + UPDATE_BUTTON_PROPERTY( nextIcon, "run-install" ) } else { - m_next->setText( tr( "&Next" ) ); - setButtonIcon( m_next, "go-next" ); + UPDATE_BUTTON_PROPERTY( nextLabel, tr( "&Next" ) ) + UPDATE_BUTTON_PROPERTY( nextIcon, "go-next" ) } // Going back is always simple - m_back->setText( tr( "&Back" ) ); + UPDATE_BUTTON_PROPERTY( backLabel, tr( "&Back" ) ) // Cancel button changes label at the end if ( isAtVeryEnd( m_steps, m_currentStep ) ) { - m_quit->setText( tr( "&Done" ) ); - m_quit->setToolTip( quitOnCompleteTooltip ); - m_quit->setVisible( true ); // At end, always visible and enabled. - setButtonIcon( m_quit, "dialog-ok-apply" ); + UPDATE_BUTTON_PROPERTY( quitLabel, tr( "&Done" ) ) + UPDATE_BUTTON_PROPERTY( quitTooltip, quitOnCompleteTooltip ) + UPDATE_BUTTON_PROPERTY( quitVisible, true ) + UPDATE_BUTTON_PROPERTY( quitIcon, "dialog-ok-apply" ) updateCancelEnabled( true ); if ( settings->quitAtEnd() ) { - m_quit->click(); + quit(); } } else { if ( settings->disableCancel() ) { - m_quit->setVisible( false ); // In case we went back from final + UPDATE_BUTTON_PROPERTY( quitVisible, false ) } updateCancelEnabled( !settings->disableCancel() && !( stepIsExecute( m_steps, m_currentStep ) && settings->disableCancelDuringExec() ) ); - m_quit->setText( tr( "&Cancel" ) ); - m_quit->setToolTip( cancelBeforeInstallationTooltip ); - setButtonIcon( m_quit, "dialog-cancel" ); + UPDATE_BUTTON_PROPERTY( quitLabel, tr( "&Cancel" ) ) + UPDATE_BUTTON_PROPERTY( quitTooltip, cancelBeforeInstallationTooltip ) + UPDATE_BUTTON_PROPERTY( quitIcon, "dialog-cancel" ) } } @@ -467,15 +445,23 @@ ViewManager::back() return; } - m_next->setEnabled( m_steps.at( m_currentStep )->isNextEnabled() ); - m_back->setEnabled( m_steps.at( m_currentStep )->isBackEnabled() ); + UPDATE_BUTTON_PROPERTY( nextEnabled, m_steps.at( m_currentStep )->isNextEnabled() ) + UPDATE_BUTTON_PROPERTY( backEnabled, + ( m_currentStep == 0 && m_steps.first()->isAtBeginning() ) + ? false + : m_steps.at( m_currentStep )->isBackEnabled() ) + + updateButtonLabels(); +} - if ( m_currentStep == 0 && m_steps.first()->isAtBeginning() ) + +void +ViewManager::quit() +{ + if ( confirmCancelInstallation() ) { - m_back->setEnabled( false ); + qApp->quit(); } - - updateButtonLabels(); } bool @@ -516,7 +502,7 @@ ViewManager::confirmCancelInstallation() void ViewManager::updateCancelEnabled( bool enabled ) { - m_quit->setEnabled( enabled ); + UPDATE_BUTTON_PROPERTY( quitEnabled, enabled ) emit cancelEnabled( enabled ); } diff --git a/src/libcalamaresui/ViewManager.h b/src/libcalamaresui/ViewManager.h index f16419dcd..ad9376f1a 100644 --- a/src/libcalamaresui/ViewManager.h +++ b/src/libcalamaresui/ViewManager.h @@ -39,6 +39,21 @@ class UIDLLEXPORT ViewManager : public QAbstractListModel Q_OBJECT Q_PROPERTY( int currentStepIndex READ currentStepIndex NOTIFY currentStepChanged FINAL ) + Q_PROPERTY( bool nextEnabled READ nextEnabled NOTIFY nextEnabledChanged FINAL ) + Q_PROPERTY( QString nextLabel READ nextLabel NOTIFY nextLabelChanged FINAL ) + Q_PROPERTY( QString nextIcon READ nextIcon NOTIFY nextIconChanged FINAL ) + + Q_PROPERTY( bool backEnabled READ backEnabled NOTIFY backEnabledChanged FINAL ) + Q_PROPERTY( QString backLabel READ backLabel NOTIFY backLabelChanged FINAL ) + Q_PROPERTY( QString backIcon READ backIcon NOTIFY backIconChanged FINAL ) + + Q_PROPERTY( bool quitEnabled READ quitEnabled NOTIFY quitEnabledChanged FINAL ) + Q_PROPERTY( QString quitLabel READ quitLabel NOTIFY quitLabelChanged FINAL ) + Q_PROPERTY( QString quitIcon READ quitIcon NOTIFY quitIconChanged FINAL ) + Q_PROPERTY( QString quitTooltip READ quitTooltip NOTIFY quitTooltipChanged FINAL ) + + Q_PROPERTY( bool quitVisible READ quitVisible NOTIFY quitVisibleChanged FINAL ) + public: /** * @brief instance access to the ViewManager singleton. @@ -92,13 +107,25 @@ public: */ bool confirmCancelInstallation(); -public slots: +public Q_SLOTS: /** * @brief next moves forward to the next page of the current ViewStep (if any), * or to the first page of the next ViewStep if the current ViewStep doesn't * have any more pages. */ void next(); + bool nextEnabled() const + { + return m_nextEnabled; ///< Is the next-button to be enabled + } + QString nextLabel() const + { + return m_nextLabel; ///< What should be displayed on the next-button + } + QString nextIcon() const + { + return m_nextIcon; ///< Name of the icon to show + } /** * @brief back moves backward to the previous page of the current ViewStep (if any), @@ -106,6 +133,42 @@ public slots: * have any pages before the current one. */ void back(); + bool backEnabled() const + { + return m_backEnabled; ///< Is the back-button to be enabled + } + QString backLabel() const + { + return m_backLabel; ///< What should be displayed on the back-button + } + QString backIcon() const + { + return m_backIcon; ///< Name of the icon to show + } + + /** + * @brief Probably quit + * + * Asks for confirmation if necessary. Terminates the application. + */ + void quit(); + bool quitEnabled() const + { + return m_quitEnabled; ///< Is the quit-button to be enabled + } + QString quitLabel() const + { + return m_quitLabel; ///< What should be displayed on the quit-button + } + QString quitIcon() const + { + return m_quitIcon; ///< Name of the icon to show + } + bool quitVisible() const + { + return m_quitVisible; ///< Should the quit-button be visible + } + QString quitTooltip() const { return m_quitTooltip; } /** * @brief onInstallationFailed displays an error message when a fatal failure @@ -126,6 +189,20 @@ signals: void enlarge( QSize enlarge ) const; // See ViewStep::enlarge() void cancelEnabled( bool enabled ) const; + void nextEnabledChanged( bool ) const; + void nextLabelChanged( QString ) const; + void nextIconChanged( QString ) const; + + void backEnabledChanged( bool ) const; + void backLabelChanged( QString ) const; + void backIconChanged( QString ) const; + + void quitEnabledChanged( bool ) const; + void quitLabelChanged( QString ) const; + void quitIconChanged( QString ) const; + void quitVisibleChanged( bool ) const; + void quitTooltipChanged( QString ) const; + private: explicit ViewManager( QObject* parent = nullptr ); virtual ~ViewManager() override; @@ -141,9 +218,20 @@ private: QWidget* m_widget; QStackedWidget* m_stack; - QPushButton* m_back; - QPushButton* m_next; - QPushButton* m_quit; + + bool m_nextEnabled = false; + QString m_nextLabel; + QString m_nextIcon; ///< Name of icon to show on button + + bool m_backEnabled = false; + QString m_backLabel; + QString m_backIcon; + + bool m_quitEnabled = false; + QString m_quitLabel; + QString m_quitIcon; + QString m_quitTooltip; + bool m_quitVisible = true; public: /** @section Model