From 196a33ba4b81acfcd536a91c3edcf62aabd08ee9 Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Sat, 20 May 2023 15:22:02 +0200 Subject: [PATCH] profile: move axis animation code to ProfileView This feels quite a bit slower than the non-QtQuick version. This makes sense, as there is an additional level of indirection. Instead of painting directly, we paint into an QImage and turn that into a QSGTexture. Ultimately one would think that we should render directly using QtQuick. Alas, we can't, since that would mean no more printing/ exporting of profiles. How sad. Signed-off-by: Berthold Stoeger --- profile-widget/profilescene.cpp | 42 ++----------------------- profile-widget/profilescene.h | 7 ++--- profile-widget/profileview.cpp | 54 ++++++++++++++++++++++++++++++--- profile-widget/profileview.h | 4 +++ 4 files changed, 58 insertions(+), 49 deletions(-) diff --git a/profile-widget/profilescene.cpp b/profile-widget/profilescene.cpp index 174a98bfa..8c7f56652 100644 --- a/profile-widget/profilescene.cpp +++ b/profile-widget/profilescene.cpp @@ -19,37 +19,9 @@ #include "core/subsurface-string.h" #include "core/settings/qPrefDisplay.h" #include "qt-models/diveplannermodel.h" -#include static const double diveComputerTextBorder = 1.0; -// Class for animations (if any). Might want to do our own. -class ProfileAnimation : public QAbstractAnimation { - ProfileScene &scene; - // For historical reasons, speed is actually the duration - // (i.e. the reciprocal of speed). Ouch, that hurts. - int speed; - - int duration() const override - { - return speed; - } - void updateCurrentTime(int time) override - { - // Note: we explicitly pass 1.0 at the end, so that - // the callee can do a simple float comparison for "end". - scene.anim(time == speed ? 1.0 - : static_cast(time) / speed); - } -public: - ProfileAnimation(ProfileScene &scene, int animSpeed) : - scene(scene), - speed(animSpeed) - { - start(); - } -}; - template T *ProfileScene::createItem(const DiveCartesianAxis &vAxis, DataAccessor accessor, int z, Args&&... args) { @@ -404,8 +376,8 @@ static double max_gas(const plot_info &pi, double gas_pressures::*gas) return ret; } -void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsModel *plannerModel, - bool inPlanner, bool instant, bool keepPlotInfo, bool calcMax, double zoom, double zoomedPosition) +void ProfileScene::plotDive(const struct dive *dIn, int dcIn, int animSpeed, DivePlannerPointsModel *plannerModel, + bool inPlanner, bool keepPlotInfo, bool calcMax, double zoom, double zoomedPosition) { d = dIn; dc = dcIn; @@ -439,8 +411,6 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM keepPlotInfo = false; empty = false; - int animSpeed = instant || printMode ? 0 : qPrefDisplay::animation_speed(); - // A non-null planner_ds signals to create_plot_info_new that the dive is currently planned. struct deco_state *planner_ds = inPlanner && plannerModel ? &plannerModel->final_deco_state : nullptr; @@ -589,12 +559,6 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM if (nr > 1) dcText += tr(" (#%1 of %2)").arg(dc + 1).arg(nr); diveComputerText->set(dcText, getColor(TIME_TEXT, isGrayscale)); - - // Reset animation. - if (animSpeed <= 0) - animation.reset(); - else - animation = std::make_unique(*this, animSpeed); } void ProfileScene::anim(double fraction) @@ -609,7 +573,7 @@ void ProfileScene::draw(QPainter *painter, const QRect &pos, { QSize size = pos.size(); resize(QSizeF(size)); - plotDive(d, dc, plannerModel, inPlanner, true, false, true); + plotDive(d, dc, 0, plannerModel, inPlanner, false, true); QImage image(pos.size(), QImage::Format_ARGB32); image.fill(getColor(::BACKGROUND, isGrayscale)); diff --git a/profile-widget/profilescene.h b/profile-widget/profilescene.h index 5b1fbc93d..566a92cb1 100644 --- a/profile-widget/profilescene.h +++ b/profile-widget/profilescene.h @@ -27,7 +27,6 @@ class DiveReportedCeiling; class DiveTemperatureItem; class DiveTextItem; class PartialPressureGasItem; -class ProfileAnimation; class TankItem; class ProfileScene : public QGraphicsScene { @@ -42,8 +41,8 @@ public: // Can be compared with literal 1.0 to determine "end" state. // If a plannerModel is passed, the deco-information is taken from there. - void plotDive(const struct dive *d, int dc, DivePlannerPointsModel *plannerModel = nullptr, bool inPlanner = false, - bool instant = false, bool keepPlotInfo = false, bool calcMax = true, double zoom = 1.0, double zoomedPosition = 0.0); + void plotDive(const struct dive *d, int dc, int animSpeed, DivePlannerPointsModel *plannerModel = nullptr, bool inPlanner = false, + bool keepPlotInfo = false, bool calcMax = true, double zoom = 1.0, double zoomedPosition = 0.0); void draw(QPainter *painter, const QRect &pos, const struct dive *d, int dc, @@ -61,7 +60,6 @@ private: void updateVisibility(bool diveHasHeartBeat, bool simplified); // Update visibility of non-interactive chart features according to preferences void updateAxes(bool diveHasHeartBeat, bool simplified); // Update axes according to preferences - friend class ProfileWidget2; // For now, give the ProfileWidget full access to the objects on the scene double dpr; // Device Pixel Ratio. A DPR of one corresponds to a "standard" PC screen. bool printMode; bool isGrayscale; @@ -101,7 +99,6 @@ private: DivePercentageItem *percentageItem; TankItem *tankItem; std::shared_ptr pixmaps; - std::unique_ptr animation; std::vector animatedAxes; }; diff --git a/profile-widget/profileview.cpp b/profile-widget/profileview.cpp index 935125a71..8084808f6 100644 --- a/profile-widget/profileview.cpp +++ b/profile-widget/profileview.cpp @@ -6,11 +6,40 @@ #include "core/errorhelper.h" #include "core/pref.h" #include "core/settings/qPrefTechnicalDetails.h" +#include "core/settings/qPrefDisplay.h" #include "qt-quick/chartitem.h" +#include #include #include +// Class for animations (if any). Might want to do our own. +class ProfileAnimation : public QAbstractAnimation { + ProfileView &view; + // For historical reasons, speed is actually the duration + // (i.e. the reciprocal of speed). Ouch, that hurts. + int speed; + + int duration() const override + { + return speed; + } + void updateCurrentTime(int time) override + { + // Note: we explicitly pass 1.0 at the end, so that + // the callee can do a simple float comparison for "end". + view.anim(time == speed ? 1.0 + : static_cast(time) / speed); + } +public: + ProfileAnimation(ProfileView &view, int animSpeed) : + view(view), + speed(animSpeed) + { + start(); + } +}; + static double calcZoom(int zoomLevel) { // Base of exponential zoom function: one wheel-click will increase the zoom by 15%. @@ -97,16 +126,16 @@ void ProfileView::plotDive(const struct dive *dIn, int dcIn, int flags) DivePlannerPointsModel *model = nullptr; bool inPlanner = flags & RenderFlags::PlanMode; - QColor backgroundColor = inPlanner ? QColor("#D7E3EF") - : getColor(::BACKGROUND, false); - double zoom = calcZoom(zoomLevel); + int animSpeed = flags & RenderFlags::Instant ? 0 : qPrefDisplay::animation_speed(); + profileScene->resize(size()); - profileScene->plotDive(d, dc, model, inPlanner, true, //flags & RenderFlags::Instant, + profileScene->plotDive(d, dc, animSpeed, model, inPlanner, flags & RenderFlags::DontRecalculatePlotInfo, shouldCalculateMax, zoom, zoomedPosition); - profileItem->draw(size(), backgroundColor, *profileScene); + background = inPlanner ? QColor("#D7E3EF") : getColor(::BACKGROUND, false); + profileItem->draw(size(), background, *profileScene); //rulerItem->setVisible(prefs.rulergraph && currentState != PLAN && currentState != EDIT); //toolTipItem->setPlotInfo(profileScene->plotInfo); @@ -136,4 +165,19 @@ void ProfileView::plotDive(const struct dive *dIn, int dcIn, int flags) qPrefTechnicalDetails::set_calcndltts(false); report_error("%s", qPrintable(tr("Show NDL / TTS was disabled because of excessive processing time"))); } + + // Reset animation. + if (animSpeed <= 0) + animation.reset(); + else + animation = std::make_unique(*this, animSpeed); +} + +void ProfileView::anim(double fraction) +{ + if (!profileScene || !profileItem) + return; + profileScene->anim(fraction); + profileItem->draw(size(), background, *profileScene); + update(); } diff --git a/profile-widget/profileview.h b/profile-widget/profileview.h index 1d87d213d..b651b6a4b 100644 --- a/profile-widget/profileview.h +++ b/profile-widget/profileview.h @@ -6,6 +6,7 @@ #include class ChartGraphicsSceneItem; +class ProfileAnimation; class ProfileScene; class ProfileView : public ChartView { @@ -25,6 +26,7 @@ public: void plotDive(const struct dive *d, int dc, int flags = RenderFlags::None); void clear(); + void anim(double fraction); private: const struct dive *d; int dc; @@ -32,8 +34,10 @@ private: double zoomedPosition; // Position when zoomed: 0.0 = beginning, 1.0 = end. bool empty; // No dive shown. bool shouldCalculateMax; // Calculate maximum time and depth (default). False when dragging handles. + QColor background; std::unique_ptr profileScene; ChartItemPtr profileItem; + std::unique_ptr animation; void plotAreaChanged(const QSizeF &size) override; void resetPointers() override;