diff --git a/src/branding/default/branding.desc b/src/branding/default/branding.desc index 3f6268cc5..4f099dd00 100644 --- a/src/branding/default/branding.desc +++ b/src/branding/default/branding.desc @@ -1,3 +1,9 @@ +# Product branding information. This influences some global +# user-visible aspects of Calamares, such as the product +# name, window behavior, and the slideshow during installation. +# +# Additional styling can be done using the stylesheet.qss +# file, also in the branding directory. --- componentName: default @@ -94,6 +100,9 @@ slideshow: "show.qml" # Optional, and defaults to the application palette. # - sidebarSelect is the text color of the selected step. # +# These colors can **also** be set through the stylesheet, if the +# branding component also ships a stylesheet.qss. Then they are +# the corresponding CSS attributes of #sidebarApp. style: sidebarBackground: "#292F34" sidebarText: "#FFFFFF" diff --git a/src/branding/default/stylesheet.qss b/src/branding/default/stylesheet.qss index 0ea8118bf..c5341ee0a 100644 --- a/src/branding/default/stylesheet.qss +++ b/src/branding/default/stylesheet.qss @@ -6,6 +6,14 @@ In principle, all parts can be styled through CSS. Missing parts should be filed as issues. The IDs are based on the object names in the C++ code. + +Documentation for styling Qt Widgets through a stylesheet +can be found at + https://doc.qt.io/qt-5/stylesheet-examples.html +In Calamares, styling widget classes is supported (e.g. +using `QComboBox` as a selector). You can also use specific +object names (ids), which you can find through debugging tools. + */ /* Main application window. diff --git a/src/calamares/CMakeLists.txt b/src/calamares/CMakeLists.txt index 659865792..5159916e8 100644 --- a/src/calamares/CMakeLists.txt +++ b/src/calamares/CMakeLists.txt @@ -1,9 +1,5 @@ add_definitions( -DUIDLLEXPORT_PRO ) -if( NOT CMAKE_BUILD_TYPE STREQUAL "Release" ) - message( "Building in debug mode, enabling all debug updates" ) -endif() - set( calamaresSources main.cpp CalamaresApplication.cpp diff --git a/src/calamares/CalamaresWindow.cpp b/src/calamares/CalamaresWindow.cpp index b570a9c86..25c8432e2 100644 --- a/src/calamares/CalamaresWindow.cpp +++ b/src/calamares/CalamaresWindow.cpp @@ -59,7 +59,7 @@ CalamaresWindow::CalamaresWindow( QWidget* parent ) // If we can never cancel, don't show the window-close button if ( Calamares::Settings::instance()->disableCancel() ) setWindowFlag( Qt::WindowCloseButtonHint, false ); - + CALAMARES_RETRANSLATE( setWindowTitle( Calamares::Settings::instance()->isSetupMode() ? tr( "%1 Setup Program" ).arg( *Calamares::Branding::ProductName ) @@ -74,6 +74,7 @@ CalamaresWindow::CalamaresWindow( QWidget* parent ) using CalamaresUtils::windowPreferredHeight; using CalamaresUtils::windowPreferredWidth; + // Needs to match what's checked in DebugWindow this->setObjectName("mainApp"); QSize availableSize = qApp->desktop()->availableGeometry( this ).size(); @@ -173,7 +174,7 @@ 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. - + mainLayout->addWidget( m_viewManager->centralWidget() ); setStyleSheet( Calamares::Branding::instance()->stylesheet() ); } diff --git a/src/libcalamaresui/Branding.cpp b/src/libcalamaresui/Branding.cpp index 2f9407bb7..673b3df42 100644 --- a/src/libcalamaresui/Branding.cpp +++ b/src/libcalamaresui/Branding.cpp @@ -153,7 +153,7 @@ Branding::Branding( const QString& brandingFilePath, #ifdef WITH_KOSRelease KOSRelease relInfo; - + QHash< QString, QString > relMap{ std::initializer_list< std::pair< QString, QString > > { { QStringLiteral( "NAME" ), relInfo.name() }, @@ -239,16 +239,6 @@ Branding::Branding( const QString& brandingFilePath, m_translationsPathPrefix.append( QString( "%1calamares-%2" ) .arg( QDir::separator() ) .arg( m_componentName ) ); - - QFileInfo importQSSPath( componentDir.filePath( "stylesheet.qss" ) ); - if ( importQSSPath.exists() && importQSSPath.isReadable() ) - { - QFile stylesheetFile( importQSSPath.filePath() ); - stylesheetFile.open( QFile::ReadOnly ); - m_stylesheet = stylesheetFile.readAll(); - } - else - cWarning() << "the branding component" << componentDir.absolutePath() << "does not ship stylesheet.qss."; } else { @@ -310,6 +300,21 @@ Branding::image( Branding::ImageEntry imageEntry, const QSize& size ) const return pixmap; } +QString +Branding::stylesheet() const +{ + QFileInfo fi( m_descriptorPath ); + QFileInfo importQSSPath( fi.absoluteDir().filePath( "stylesheet.qss" ) ); + if ( importQSSPath.exists() && importQSSPath.isReadable() ) + { + QFile stylesheetFile( importQSSPath.filePath() ); + stylesheetFile.open( QFile::ReadOnly ); + return stylesheetFile.readAll(); + } + else + cWarning() << "The branding component" << fi.absoluteDir().absolutePath() << "does not ship stylesheet.qss."; + return QString(); +} void Branding::setGlobals( GlobalStorage* globalStorage ) const diff --git a/src/libcalamaresui/Branding.h b/src/libcalamaresui/Branding.h index 29a39f103..00174f604 100644 --- a/src/libcalamaresui/Branding.h +++ b/src/libcalamaresui/Branding.h @@ -123,8 +123,13 @@ public: QString styleString( Branding::StyleEntry styleEntry ) const; QString imagePath( Branding::ImageEntry imageEntry ) const; QPixmap image( Branding::ImageEntry imageEntry, const QSize& size ) const; - /** @brief Stylesheet to apply for this branding. May be empty. */ - QString stylesheet() const { return m_stylesheet; } + /** @brief Stylesheet to apply for this branding. May be empty. + * + * The file is loaded every time this function is called, so + * it may be quite expensive -- although normally it will be + * called only once, on startup. (Or from the debug window) + */ + QString stylesheet() const; bool welcomeStyleCalamares() const { return m_welcomeStyleCalamares; } bool welcomeExpandingLogo() const { return m_welcomeExpandingLogo; } @@ -151,14 +156,13 @@ private: [[noreturn]] void bail( const QString& message ); - QString m_descriptorPath; - QString m_componentName; + QString m_descriptorPath; // Path to descriptor (e.g. "/etc/calamares/default/branding.desc") + QString m_componentName; // Matches last part of full path to containing directory QMap< QString, QString > m_strings; QMap< QString, QString > m_images; QMap< QString, QString > m_style; QString m_slideshowPath; QString m_translationsPathPrefix; - QString m_stylesheet; // Text from file /** @brief Initialize the simple settings below */ void initSimpleSettings( const YAML::Node& doc ); diff --git a/src/libcalamaresui/utils/DebugWindow.cpp b/src/libcalamaresui/utils/DebugWindow.cpp index 164da02d9..62ab504d3 100644 --- a/src/libcalamaresui/utils/DebugWindow.cpp +++ b/src/libcalamaresui/utils/DebugWindow.cpp @@ -20,13 +20,17 @@ #include "DebugWindow.h" #include "ui_DebugWindow.h" -#include "utils/Retranslator.h" +#include "Branding.h" +#include "modulesystem/Module.h" +#include "modulesystem/ModuleManager.h" #include "utils/qjsonmodel.h" -#include "JobQueue.h" -#include "Job.h" + #include "GlobalStorage.h" -#include "modulesystem/ModuleManager.h" -#include "modulesystem/Module.h" +#include "Job.h" +#include "JobQueue.h" +#include "utils/Logger.h" +#include "utils/Retranslator.h" + #ifdef WITH_PYTHONQT #include @@ -49,6 +53,20 @@ crash() *a = 1; } +/// @brief Print out the widget tree (names) in indented form. +static void dumpWidgetTree( QDebug& deb, const QWidget* widget, int depth ) +{ + if ( !widget ) + return; + + deb << Logger::Continuation; + for (int i = 0; i < depth; ++i ) + deb << ' '; + deb << widget->objectName(); + + for ( const auto* w : widget->findChildren( QString(), Qt::FindDirectChildrenOnly ) ) + dumpWidgetTree( deb, w, depth+1 ); +} namespace Calamares { @@ -186,7 +204,29 @@ DebugWindow::DebugWindow() } } ); + // Tools page connect( m_ui->crashButton, &QPushButton::clicked, this, [] { ::crash(); } ); + connect( m_ui->reloadStylesheetButton, &QPushButton::clicked, + []() + { + for ( auto* w : qApp->topLevelWidgets() ) + { + // Needs to match what's set in CalamaresWindow + if ( w->objectName() == QStringLiteral( "mainApp" ) ) + { + w->setStyleSheet( Calamares::Branding::instance()->stylesheet() ); + } + } + }); + connect( m_ui->widgetTreeButton, &QPushButton::clicked, + []() + { + for ( auto* w : qApp->topLevelWidgets() ) + { + auto deb = cDebug(); + dumpWidgetTree( deb, w, 0 ); + } + }); CALAMARES_RETRANSLATE( m_ui->retranslateUi( this ); diff --git a/src/libcalamaresui/utils/DebugWindow.ui b/src/libcalamaresui/utils/DebugWindow.ui index eb6d5c3e7..63a6a840a 100644 --- a/src/libcalamaresui/utils/DebugWindow.ui +++ b/src/libcalamaresui/utils/DebugWindow.ui @@ -100,6 +100,20 @@ + + + + Reload Stylesheet + + + + + + + Widget Tree + + + diff --git a/src/qml/calamares/CMakeLists.txt b/src/qml/calamares/CMakeLists.txt index ba2fb38b7..48f8ca96c 100644 --- a/src/qml/calamares/CMakeLists.txt +++ b/src/qml/calamares/CMakeLists.txt @@ -25,3 +25,5 @@ foreach( SUBDIRECTORY ${SUBDIRECTORIES} ) endif() endforeach() + +message( "" )