calamares/src/libcalamaresui/Branding.h
Hector Martin 15027f40b2 Make HiDPI SVG rendering work on Wayland
Branding SVGs were rendering at 1x on Wayland and then scaling up to the
display DPI, which looks ugly. To get this to work properly we need to
explicitly multiply the devicePixelRatio into the dimensions that
QPixmaps render at, since QPixmap is DPI-unaware.

This probably only takes care of a subset of the problem codepaths, but
at least it makes the sidebar logo and welcome screen work properly.

Signed-off-by: Hector Martin <marcan@marcan.st>
2023-09-04 14:35:14 +09:00

327 lines
10 KiB
C++

/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot <groot@kde.org>
* SPDX-FileCopyrightText: 2018 Raul Rodrigo Segura (raurodse)
* SPDX-FileCopyrightText: 2019 Camilo Higuita <milo.h@aol.com>
* SPDX-FileCopyrightText: 2021 Anubhav Choudhary <ac.10edu@gmail.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef BRANDING_H
#define BRANDING_H
#include "CalamaresConfig.h"
#include "DllMacro.h"
#include "utils/NamedSuffix.h"
#include <QMap>
#include <QObject>
#include <QPixmap>
#include <QSize>
#include <QStringList>
#include <QUrl>
namespace YAML
{
class Node;
} // namespace YAML
namespace Calamares
{
class GlobalStorage;
class UIDLLEXPORT Branding : public QObject
{
Q_OBJECT
public:
/**
* Descriptive strings in the configuration file. use
* e.g. *Branding::ProductName to get the string value for
* the product name.
*/
enum StringEntry
{
ProductName,
Version,
ShortVersion,
VersionedName,
ShortVersionedName,
ShortProductName,
BootloaderEntryName,
ProductUrl,
SupportUrl,
KnownIssuesUrl,
ReleaseNotesUrl,
DonateUrl
};
Q_ENUM( StringEntry )
enum ImageEntry : short
{
ProductBanner,
ProductIcon,
ProductLogo,
ProductWallpaper,
ProductWelcome
};
Q_ENUM( ImageEntry )
/** @brief Names of style entries, for use in code
*
* These names are mapped to names in the branding.desc file through
* an internal table s_styleEntryStrings, which defines which names
* in `branding.desc` key *style* are used for which entry.
*/
enum StyleEntry : short
{
SidebarBackground,
SidebarText,
SidebarTextCurrent,
SidebarBackgroundCurrent,
};
Q_ENUM( StyleEntry )
/** @brief Supported log-upload servers.
*
* 'None' is here as a fallback.
*/
enum UploadServerType : short
{
None,
Fiche
};
Q_ENUM( UploadServerType )
/** @brief Setting for how much the main window may expand. */
enum class WindowExpansion
{
Normal,
Fullscreen,
Fixed
};
Q_ENUM( WindowExpansion )
/** @brief Setting for the main window size.
*
* The units are pixels (Pixies) or something-based-on-fontsize (Fonties), which
* we suffix as "em", e.g. "600px" or "32em".
*/
enum class WindowDimensionUnit
{
None,
Pixies,
Fonties
};
Q_ENUM( WindowDimensionUnit )
class WindowDimension : public NamedSuffix< WindowDimensionUnit, WindowDimensionUnit::None >
{
public:
static const NamedEnumTable< WindowDimensionUnit >& suffixes();
bool isValid() const;
using NamedSuffix::NamedSuffix;
WindowDimension( const QString& s )
: NamedSuffix( suffixes(), s )
{
}
};
/** @brief Placement of main window.
*/
enum class WindowPlacement
{
Center,
Free
};
Q_ENUM( WindowPlacement )
///@brief What kind of panel (sidebar, navigation) to use in the main window
enum class PanelFlavor
{
None,
Widget
#ifdef WITH_QML
,
Qml
#endif
};
Q_ENUM( PanelFlavor )
///@brief Where to place a panel (sidebar, navigation)
enum class PanelSide
{
None,
Left,
Right,
Top,
Bottom
};
Q_ENUM( PanelSide )
static Branding* instance();
explicit Branding( const QString& brandingFilePath, QObject* parent = nullptr, qreal devicePixelRatio = 1.0 );
/** @brief Complete path of the branding descriptor file. */
QString descriptorPath() const { return m_descriptorPath; }
/** @brief The component name found in the descriptor file.
*
* The component name always matches the last directory name in the path.
*/
QString componentName() const { return m_componentName; }
/** @brief The directory holding all of the branding assets. */
QString componentDirectory() const;
/** @brief The directory where branding translations live.
*
* This is componentDir + "/lang".
*/
QString translationsDirectory() const { return m_translationsPathPrefix; }
/** @brief Path to the slideshow QML file, if any. (API == 1 or 2)*/
QString slideshowPath() const { return m_slideshowPath; }
/// @brief List of pathnames of slideshow images, if any. (API == -1)
QStringList slideshowImages() const { return m_slideshowFilenames; }
/** @brief Which slideshow API to use for the slideshow?
*
* - 2 For QML-based slideshows loaded asynchronously (current)
* - 1 For QML-based slideshows, loaded when shown (legacy)
* - -1 For oldschool image-slideshows.
*/
int slideshowAPI() const { return m_slideshowAPI; }
QPixmap image( Branding::ImageEntry imageEntry, const QSize& size ) const;
/** @brief Look up an image in the branding directory or as an icon
*
* The @p name is checked in the branding directory: if it is an image
* file, return the pixmap from that file, at the requested size.
* If it isn't a file, look it up as an icon name in the current theme.
* May return a null pixmap if nothing is found.
*/
QPixmap image( const QString& name, const QSize& size ) const;
/** @brief Look up image with alternate names
*
* Calls image() for each name in the @p list and returns the first
* one that is non-null. May return a null pixmap if nothing is found.
*/
QPixmap image( const QStringList& list, const QSize& size ) const;
/** @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; }
bool windowMaximize() const { return m_windowExpansion == WindowExpansion::Fullscreen; }
bool windowExpands() const { return m_windowExpansion != WindowExpansion::Fixed; }
QPair< WindowDimension, WindowDimension > windowSize() const
{
return QPair< WindowDimension, WindowDimension >( m_windowWidth, m_windowHeight );
}
bool windowPlacementCentered() const { return m_windowPlacement == WindowPlacement::Center; }
///@brief Which sidebar flavor is configured
PanelFlavor sidebarFlavor() const { return m_sidebarFlavor; }
///@brief Which navigation flavor is configured
PanelFlavor navigationFlavor() const { return m_navigationFlavor; }
/** @brief Upload server configuration
*
* This object has 3 items : the type (which may be none, in which case the URL
* is irrelevant and usually empty), the URL for the upload and the size limit of upload
* in bytes (for configuration value < 0, it serves -1, which stands for having no limit).
*/
struct UploadServerInfo
{
UploadServerType type;
QUrl url;
qint64 size;
operator bool() const { return type != Calamares::Branding::UploadServerType::None && size != 0; }
};
UploadServerInfo uploadServer() const { return m_uploadServer; }
/**
* Creates a map called "branding" in the global storage, and inserts an
* entry for each of the branding strings. This makes the branding
* information accessible to the Python modules.
*/
void setGlobals( GlobalStorage* globalStorage ) const;
public slots:
QString string( StringEntry stringEntry ) const;
QString versionedName() const { return string( VersionedName ); }
QString productName() const { return string( ProductName ); }
QString shortProductName() const { return string( ShortProductName ); }
QString shortVersionedName() const { return string( ShortVersionedName ); }
/** @brief Map an enum-value to the entry from the *style* key.
*
* e.g. StyleEntry::SidebarTextCurrent maps to the corresponding
* *style* entry, which is (confusingly) named "sidebarTextSelect"
* in the branding file.
*/
QString styleString( StyleEntry styleEntry ) const;
QString imagePath( ImageEntry imageEntry ) const;
PanelSide sidebarSide() const { return m_sidebarSide; }
PanelSide navigationSide() const { return m_navigationSide; }
private:
static Branding* s_instance;
static const QStringList s_stringEntryStrings;
static const QStringList s_imageEntryStrings;
static const QStringList s_uploadServerStrings;
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;
UploadServerInfo m_uploadServer;
/* The slideshow can be done in one of two ways:
* - as a sequence of images
* - as a QML file
* The slideshow: setting selects which one is used. If it is
* a list (of filenames) then it is a sequence of images, and otherwise
* it is a QML file which is run. (For QML, the slideshow API is
* important).
*/
QStringList m_slideshowFilenames;
QString m_slideshowPath;
int m_slideshowAPI;
QString m_translationsPathPrefix;
/** @brief Initialize the simple settings below */
void initSimpleSettings( const YAML::Node& doc );
///@brief Initialize the slideshow settings, above
void initSlideshowSettings( const YAML::Node& doc );
bool m_welcomeStyleCalamares;
bool m_welcomeExpandingLogo;
WindowExpansion m_windowExpansion;
WindowDimension m_windowHeight, m_windowWidth;
WindowPlacement m_windowPlacement;
PanelFlavor m_sidebarFlavor = PanelFlavor::Widget;
PanelFlavor m_navigationFlavor = PanelFlavor::Widget;
PanelSide m_sidebarSide = PanelSide::Left;
PanelSide m_navigationSide = PanelSide::Bottom;
qreal m_devicePixelRatio;
};
} // namespace Calamares
#endif // BRANDING_H