Gui: refactor Splashscreen

Move About dialog class to the separate source file.
This commit is contained in:
Ladislav Michl
2024-09-11 10:40:10 +02:00
parent 3f870deb51
commit 37e04a8775
8 changed files with 1308 additions and 1172 deletions

View File

@@ -100,7 +100,7 @@
#include "PythonConsole.h"
#include "ReportView.h"
#include "SelectionView.h"
#include "Splashscreen.h"
#include "SplashScreen.h"
#include "ToolBarManager.h"
#include "ToolBoxManager.h"
#include "Tree.h"
@@ -115,7 +115,6 @@
#include "View3DInventor.h"
#include "View3DInventorViewer.h"
#include "DlgObjectSelection.h"
#include "Tools.h"
#include <App/Color.h>
FC_LOG_LEVEL_INIT("MainWindow",false,true,true)
@@ -1936,7 +1935,7 @@ void MainWindow::startSplasher()
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("General");
// first search for an external image file
if (hGrp->GetBool("ShowSplasher", true)) {
d->splashscreen = new SplashScreen(this->splashImage());
d->splashscreen = new SplashScreen(SplashScreen::splashImage());
if (!hGrp->GetBool("ShowSplasherMessages", false)) {
d->splashscreen->setShowMessages(false);
@@ -1959,220 +1958,6 @@ void MainWindow::stopSplasher()
}
}
QPixmap MainWindow::aboutImage() const
{
// See if we have a custom About screen image set
QPixmap about_image;
QFileInfo fi(QString::fromLatin1("images:about_image.png"));
if (fi.isFile() && fi.exists())
about_image.load(fi.filePath(), "PNG");
std::string about_path = App::Application::Config()["AboutImage"];
if (!about_path.empty() && about_image.isNull()) {
QString path = QString::fromUtf8(about_path.c_str());
if (QDir(path).isRelative()) {
QString home = QString::fromStdString(App::Application::getHomePath());
path = QFileInfo(QDir(home), path).absoluteFilePath();
}
about_image.load(path);
// Now try the icon paths
if (about_image.isNull()) {
about_image = Gui::BitmapFactory().pixmap(about_path.c_str());
}
}
return about_image;
}
/**
* Displays a warning about this being a developer build. Designed for display in the Splashscreen.
* \param painter The painter to draw the warning into
* \param startPosition The painter-space coordinates to start the warning box at.
* \param maxSize The maximum extents for the box that is drawn. If the text exceeds this size it
* will be scaled down to fit.
* \note The text string is translatable, so its length is somewhat unpredictable. It is always
* displayed as two lines, regardless of the length of the text (e.g. no wrapping is done). Only the
* width is considered, the height simply follows from the font size.
*/
void MainWindow::renderDevBuildWarning(
QPainter &painter,
const QPoint startPosition,
const QSize maxSize,
QColor color)
{
// Create a background box that fades out the artwork for better legibility
QColor fader (Qt::white);
constexpr float halfDensity (0.65F);
fader.setAlphaF(halfDensity);
QBrush fillBrush(fader, Qt::BrushStyle::SolidPattern);
painter.setBrush(fillBrush);
// Construct the lines of text and figure out how much space they need
const auto devWarningLine1 = tr("WARNING: This is a development version.");
const auto devWarningLine2 = tr("Please do not use it in a production environment.");
QFontMetrics fontMetrics(painter.font()); // Try to use the existing font
int padding = QtTools::horizontalAdvance(fontMetrics, QLatin1String("M")); // Arbitrary
int line1Width = QtTools::horizontalAdvance(fontMetrics, devWarningLine1);
int line2Width = QtTools::horizontalAdvance(fontMetrics, devWarningLine2);
int boxWidth = std::max(line1Width,line2Width) + 2 * padding;
int lineHeight = fontMetrics.lineSpacing();
if (boxWidth > maxSize.width()) {
// Especially if the text was translated, there is a chance that using the existing font
// will exceed the width of the Splashscreen graphic. Resize down so that it fits, no matter
// how long the text strings are.
float reductionFactor = static_cast<float>(maxSize.width()) / static_cast<float>(boxWidth);
int newFontSize = static_cast<int>(painter.font().pointSize() * reductionFactor);
padding *= reductionFactor;
QFont newFont = painter.font();
newFont.setPointSize(newFontSize);
painter.setFont(newFont);
lineHeight = painter.fontMetrics().lineSpacing();
boxWidth = maxSize.width();
}
constexpr float lineExpansionFactor(2.3F);
int boxHeight = static_cast<int>(lineHeight*lineExpansionFactor);
// Draw the background rectangle and the text
painter.setPen(color);
painter.drawRect(startPosition.x(), startPosition.y(), boxWidth, boxHeight);
painter.drawText(startPosition.x()+padding, startPosition.y()+lineHeight, devWarningLine1);
painter.drawText(startPosition.x()+padding, startPosition.y()+2*lineHeight, devWarningLine2);
}
QPixmap MainWindow::splashImage() const
{
// search in the UserAppData dir as very first
QPixmap splash_image;
QFileInfo fi(QString::fromLatin1("images:splash_image.png"));
if (fi.isFile() && fi.exists())
splash_image.load(fi.filePath(), "PNG");
// if no image was found try the config
std::string splash_path = App::Application::Config()["SplashScreen"];
if (splash_image.isNull()) {
QString path = QString::fromUtf8(splash_path.c_str());
if (QDir(path).isRelative()) {
QString home = QString::fromStdString(App::Application::getHomePath());
path = QFileInfo(QDir(home), path).absoluteFilePath();
}
splash_image.load(path);
}
// now try the icon paths
float pixelRatio (1.0);
if (splash_image.isNull()) {
// determine the count of splashes
QStringList pixmaps = Gui::BitmapFactory().findIconFiles().filter(QString::fromStdString(splash_path));
// divide by 2 since there's two sets (normal and 2x)
// minus 1 to ignore the default splash that isn't numbered
int splash_count = pixmaps.count()/2 - 1;
// set a random splash path
if (splash_count > 0) {
int random = rand() % splash_count;
splash_path += std::to_string(random);
}
if (qApp->devicePixelRatio() > 1.0) {
// For HiDPI screens, we have a double-resolution version of the splash image
splash_path += "_2x";
splash_image = Gui::BitmapFactory().pixmap(splash_path.c_str());
splash_image.setDevicePixelRatio(2.0);
pixelRatio = 2.0;
}
else {
splash_image = Gui::BitmapFactory().pixmap(splash_path.c_str());
}
}
// include application name and version number
std::map<std::string,std::string>::const_iterator tc = App::Application::Config().find("SplashInfoColor");
std::map<std::string,std::string>::const_iterator wc = App::Application::Config().find("SplashWarningColor");
if (tc != App::Application::Config().end() && wc != App::Application::Config().end()) {
QString title = qApp->applicationName();
QString major = QString::fromLatin1(App::Application::Config()["BuildVersionMajor"].c_str());
QString minor = QString::fromLatin1(App::Application::Config()["BuildVersionMinor"].c_str());
QString point = QString::fromLatin1(App::Application::Config()["BuildVersionPoint"].c_str());
QString suffix = QString::fromLatin1(App::Application::Config()["BuildVersionSuffix"].c_str());
QString version = QString::fromLatin1("%1.%2.%3%4").arg(major, minor, point, suffix);
QString position, fontFamily;
std::map<std::string,std::string>::const_iterator te = App::Application::Config().find("SplashInfoExeName");
std::map<std::string,std::string>::const_iterator tv = App::Application::Config().find("SplashInfoVersion");
std::map<std::string,std::string>::const_iterator tp = App::Application::Config().find("SplashInfoPosition");
std::map<std::string,std::string>::const_iterator tf = App::Application::Config().find("SplashInfoFont");
if (te != App::Application::Config().end())
title = QString::fromUtf8(te->second.c_str());
if (tv != App::Application::Config().end())
version = QString::fromUtf8(tv->second.c_str());
if (tp != App::Application::Config().end())
position = QString::fromUtf8(tp->second.c_str());
if (tf != App::Application::Config().end())
fontFamily = QString::fromUtf8(tf->second.c_str());
QPainter painter;
painter.begin(&splash_image);
if (!fontFamily.isEmpty()) {
QFont font = painter.font();
if (font.fromString(fontFamily))
painter.setFont(font);
}
QFont fontExe = painter.font();
fontExe.setPointSizeF(20.0);
QFontMetrics metricExe(fontExe);
int l = QtTools::horizontalAdvance(metricExe, title);
if (title == QLatin1String("FreeCAD")) {
l = 0.0; // "FreeCAD" text is already part of the splashscreen, version goes below it
}
int w = splash_image.width();
int h = splash_image.height();
QFont fontVer = painter.font();
fontVer.setPointSizeF(11.0);
QFontMetrics metricVer(fontVer);
int v = QtTools::horizontalAdvance(metricVer, version);
int x = -1, y = -1;
QRegularExpression rx(QLatin1String("(\\d+).(\\d+)"));
auto match = rx.match(position);
if (match.hasMatch()) {
x = match.captured(1).toInt();
y = match.captured(2).toInt();
}
else {
x = w - (l + v + 10);
y = h - 20;
}
QColor color(QString::fromLatin1(tc->second.c_str()));
if (color.isValid()) {
painter.setPen(color);
painter.setFont(fontExe);
if (title != QLatin1String("FreeCAD")) {
// FreeCAD's Splashscreen already contains the EXE name, no need to draw it
painter.drawText(x, y, title);
}
painter.setFont(fontVer);
painter.drawText(x + (l + 235), y - 7, version);
QColor warningColor(QString::fromLatin1(wc->second.c_str()));
if (suffix == QLatin1String("dev") && warningColor.isValid()) {
fontVer.setPointSizeF(14.0);
painter.setFont(fontVer);
const int lineHeight = metricVer.lineSpacing();
const int padding {45}; // Distance from the edge of the graphic's bounding box
QPoint startPosition(padding, y + lineHeight*2);
QSize maxSize(w/pixelRatio - 2*padding, lineHeight * 3);
MainWindow::renderDevBuildWarning(painter, startPosition, maxSize, warningColor);
}
painter.end();
}
}
return splash_image;
}
/**
* Drops the event \a e and tries to open the files.
*/