From b39e88b8c6bb25bf952e28e0ee1149e753eb5198 Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Thu, 6 May 2021 14:45:09 +0200 Subject: [PATCH] profile: remove need for MainWindow when rendering the profile Very annoyingly, to render the profile for printing / export, the profile still had to be show()n, thus requiring a parent window. Analysis of qmlprofile.c showed that this was due to the transformation matrix not being properly set up on non-show()n scenes. Instead, we can simply render via the QGraphicsScene (circumventing the QGraphicsView). The code was factored out into the ProfileWidget2::draw() function. This will hopefully make it easier to change the size-code of the profile. Signed-off-by: Berthold Stoeger --- backend-shared/exportfuncs.cpp | 21 +++++++----------- desktop-widgets/diveplanner.cpp | 8 ++----- desktop-widgets/printer.cpp | 32 +++------------------------ profile-widget/profilewidget2.cpp | 36 +++++++++++++++++++++++++++++++ profile-widget/profilewidget2.h | 2 ++ 5 files changed, 51 insertions(+), 48 deletions(-) diff --git a/backend-shared/exportfuncs.cpp b/backend-shared/exportfuncs.cpp index 86645ebd7..2b33acf51 100644 --- a/backend-shared/exportfuncs.cpp +++ b/backend-shared/exportfuncs.cpp @@ -34,32 +34,27 @@ bool ExportCallback::canceled() const #if !defined(SUBSURFACE_MOBILE) -#include "desktop-widgets/mainwindow.h" // Currently needed for profile printing. TODO: remove. +// Let's say that 800x600 is a "reasonable" profile size. Use four times that for printing. +static constexpr int profileScale = 4; +static constexpr int profileWidth = 800 * profileScale; +static constexpr int profileHeight = 600 * profileScale; static void exportProfile(ProfileWidget2 *profile, const struct dive *dive, const QString &filename) { profile->setProfileState(dive, 0); profile->plotDive(dive, 0, false, true); - QImage image = QImage(profile->size(), QImage::Format_RGB32); + QImage image = QImage(QSize(profileWidth, profileHeight), QImage::Format_RGB32); QPainter paint; paint.begin(&image); - profile->render(&paint); + profile->draw(&paint, QRect(0, 0, profileWidth, profileHeight)); image.save(filename); } static std::unique_ptr getPrintProfile() { - // Let's say that 800x600 is a "reasonable" profile size. Use four times that for printing. - const int scale = 4; - QSize size(800 * scale, 600 * scale); - - // TODO: Annoyingly, this still needs a parent window? Otherwise, - // the profile is shown as its own window, when calling show() below. - auto profile = std::make_unique(nullptr, MainWindow::instance()); - profile->resize(size); - profile->show(); // Ominous: if the scene isn't shown, parts of the plot are missing. Needs investigation. + auto profile = std::make_unique(nullptr, nullptr); profile->setPrintMode(true); - profile->setFontPrintScale((double)scale); + profile->setFontPrintScale((double)profileScale); return profile; } diff --git a/desktop-widgets/diveplanner.cpp b/desktop-widgets/diveplanner.cpp index f744aebfe..ad1b9a276 100644 --- a/desktop-widgets/diveplanner.cpp +++ b/desktop-widgets/diveplanner.cpp @@ -609,15 +609,11 @@ void PlannerWidgets::printDecoPlan() painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); - // TODO: Annoyingly, this still needs a parent window? Otherwise, - // the profile is shown as its own window, when calling show() below. - auto profile = std::make_unique(DivePlannerPointsModel::instance(), MainWindow::instance()); - profile->show(); // Ominous: if the scene isn't shown, parts of the plot are missing. Needs investigation. - profile->resize(renderSize.toSize()); + auto profile = std::make_unique(DivePlannerPointsModel::instance(), nullptr); profile->setPlanState(&displayed_dive, 0); profile->plotDive(&displayed_dive, 0, true, true); profile->setPrintMode(true); - profile->render(&painter); + profile->draw(&painter, QRect(0, 0, pixmap.width(), pixmap.height())); QByteArray byteArray; QBuffer buffer(&byteArray); diff --git a/desktop-widgets/printer.cpp b/desktop-widgets/printer.cpp index e3dcd84a1..7b083bb21 100644 --- a/desktop-widgets/printer.cpp +++ b/desktop-widgets/printer.cpp @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 #include "printer.h" -#include "mainwindow.h" #include "templatelayout.h" #include "core/statistics.h" #include "core/qthelper.h" @@ -36,31 +35,10 @@ void Printer::putProfileImage(const QRect &profilePlaceholder, const QRect &view int y = profilePlaceholder.y() - viewPort.y(); // use the placeHolder and the viewPort position to calculate the relative position of the dive profile. QRect pos(x, y, profilePlaceholder.width(), profilePlaceholder.height()); + profile->setProfileState(dive, 0); profile->plotDive(dive, 0, true); - - if (!printOptions.color_selected) { - QImage image(pos.width(), pos.height(), QImage::Format_ARGB32); - QPainter imgPainter(&image); - imgPainter.setRenderHint(QPainter::Antialiasing); - imgPainter.setRenderHint(QPainter::SmoothPixmapTransform); - profile->render(&imgPainter, QRect(0, 0, pos.width(), pos.height())); - imgPainter.end(); - - // convert QImage to grayscale before rendering - for (int i = 0; i < image.height(); i++) { - QRgb *pixel = reinterpret_cast(image.scanLine(i)); - QRgb *end = pixel + image.width(); - for (; pixel != end; pixel++) { - int gray_val = qGray(*pixel); - *pixel = QColor(gray_val, gray_val, gray_val).rgb(); - } - } - - painter->drawImage(pos, image); - } else { - profile->render(painter, pos); - } + profile->draw(painter, pos); } void Printer::flowRender() @@ -124,9 +102,7 @@ void Printer::flowRender() void Printer::render(int pages) { - // TODO: Annoyingly, this still needs a parent window? Otherwise, - // the profile is shown as its own window, when calling show() below. - auto profile = std::make_unique(nullptr, MainWindow::instance()); + auto profile = std::make_unique(nullptr, nullptr); double printFontScale = 1.0; // apply printing settings to profile @@ -149,8 +125,6 @@ void Printer::render(int pages) // This is arbitrary, but it seems to work reasonably. QSize size = collection[0].geometry().size(); printFontScale = size.height() / 600.0; - profile->show(); // Ominous: if the scene isn't shown, parts of the plot are missing. Needs investigation. - profile->resize(size); } profile->setFontPrintScale(printFontScale); diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp index c0f835bb5..206c45af1 100644 --- a/profile-widget/profilewidget2.cpp +++ b/profile-widget/profilewidget2.cpp @@ -2161,3 +2161,39 @@ struct dive *ProfileWidget2::mutable_dive() const { return const_cast(d); } + +QImage ProfileWidget2::toImage(QSize size) +{ + // The size of chart with respect to the scene is fixed - by convention - to 100.0. + // We add 2% to the height so that the dive computer name is not cut off. + QRectF sceneRect(0.0, 0.0, 100.0, 102.0); + + QImage image(size, QImage::Format_ARGB32); + image.fill(getColor(::BACKGROUND, isGrayscale)); + + QPainter imgPainter(&image); + imgPainter.setRenderHint(QPainter::Antialiasing); + imgPainter.setRenderHint(QPainter::SmoothPixmapTransform); + scene()->render(&imgPainter, QRect(QPoint(), size), sceneRect, Qt::IgnoreAspectRatio); + imgPainter.end(); + + if (isGrayscale) { + // convert QImage to grayscale before rendering + for (int i = 0; i < image.height(); i++) { + QRgb *pixel = reinterpret_cast(image.scanLine(i)); + QRgb *end = pixel + image.width(); + for (; pixel != end; pixel++) { + int gray_val = qGray(*pixel); + *pixel = QColor(gray_val, gray_val, gray_val).rgb(); + } + } + } + + return image; +} + +void ProfileWidget2::draw(QPainter *painter, const QRect &pos) +{ + QImage img = toImage(pos.size()); + painter->drawImage(pos, img); +} diff --git a/profile-widget/profilewidget2.h b/profile-widget/profilewidget2.h index dc24aaa39..2a1491596 100644 --- a/profile-widget/profilewidget2.h +++ b/profile-widget/profilewidget2.h @@ -79,6 +79,8 @@ public: bool isPlanner() const; double getFontPrintScale() const; void setFontPrintScale(double scale); + void draw(QPainter *painter, const QRect &pos); + QImage toImage(QSize size); #ifndef SUBSURFACE_MOBILE bool eventFilter(QObject *, QEvent *) override; #endif