diff --git a/CMakeLists.txt b/CMakeLists.txt index a5c1e5b56..80d8ecf15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -395,9 +395,9 @@ if (NOT SUBSURFACE_TARGET_EXECUTABLE MATCHES "DownloaderExecutable") qt_add_resources(SUBSURFACE_RESOURCES map-widget/qml/map-widget.qrc) set(SUBSURFACE_MAPWIDGET subsurface_mapwidget) endif() - qt_add_resources(SUBSURFACE_RESOURCES subsurface.qrc profile.qrc stats/statsicons.qrc desktop-widgets/qml/statsview2.qrc) + qt_add_resources(SUBSURFACE_RESOURCES subsurface.qrc profile.qrc stats/statsicons.qrc desktop-widgets/qml/statsview2.qrc desktop-widgets/qml/profileview.qrc) else() - qt5_add_resources(SUBSURFACE_RESOURCES subsurface.qrc profile.qrc stats/statsicons.qrc map-widget/qml/map-widget.qrc desktop-widgets/qml/statsview2.qrc) + qt5_add_resources(SUBSURFACE_RESOURCES subsurface.qrc profile.qrc stats/statsicons.qrc map-widget/qml/map-widget.qrc desktop-widgets/qml/statsview2.qrc desktop-widgets/qml/profileview.qrc) set(SUBSURFACE_MAPWIDGET subsurface_mapwidget) endif() endif() diff --git a/Subsurface-mobile.pro b/Subsurface-mobile.pro index efd8b56a9..a817a84d4 100644 --- a/Subsurface-mobile.pro +++ b/Subsurface-mobile.pro @@ -184,7 +184,8 @@ SOURCES += subsurface-mobile-main.cpp \ profile-widget/tankitem.cpp \ profile-widget/divelineitem.cpp \ profile-widget/diverectitem.cpp \ - profile-widget/divetextitem.cpp + profile-widget/divetextitem.cpp \ + profile-widget/profileview.cpp HEADERS += \ commands/command_base.h \ @@ -349,7 +350,8 @@ HEADERS += \ profile-widget/divepixmapcache.h \ profile-widget/divepixmapitem.h \ profile-widget/diverectitem.h \ - profile-widget/divetextitem.h + profile-widget/divetextitem.h \ + profile-widget/profileview.h RESOURCES += mobile-widgets/qml/mobile-resources.qrc \ mobile-widgets/3rdparty/icons.qrc \ diff --git a/desktop-widgets/divelogexportdialog.cpp b/desktop-widgets/divelogexportdialog.cpp index a7cc4b4fb..89073c3aa 100644 --- a/desktop-widgets/divelogexportdialog.cpp +++ b/desktop-widgets/divelogexportdialog.cpp @@ -22,7 +22,6 @@ #include "desktop-widgets/divelogexportdialog.h" #include "desktop-widgets/diveshareexportdialog.h" #include "desktop-widgets/subsurfacewebservices.h" -#include "profile-widget/profilewidget2.h" // Retrieves the current unit settings defined in the Subsurface preferences. #define GET_UNIT(name, field, f, t) \ diff --git a/desktop-widgets/mainwindow.cpp b/desktop-widgets/mainwindow.cpp index 806b0d428..00b31e1a3 100644 --- a/desktop-widgets/mainwindow.cpp +++ b/desktop-widgets/mainwindow.cpp @@ -57,7 +57,6 @@ #include "commands/command.h" #include "profilewidget.h" -#include "profile-widget/profilewidget2.h" #ifndef NO_PRINTING #include "desktop-widgets/printdialog.h" diff --git a/desktop-widgets/modeldelegates.cpp b/desktop-widgets/modeldelegates.cpp index 68036a45a..b07281752 100644 --- a/desktop-widgets/modeldelegates.cpp +++ b/desktop-widgets/modeldelegates.cpp @@ -8,7 +8,6 @@ #include "qt-models/cylindermodel.h" #include "qt-models/models.h" #include "desktop-widgets/starwidget.h" -#include "profile-widget/profilewidget2.h" #include "qt-models/tankinfomodel.h" #include "qt-models/weightsysteminfomodel.h" #include "qt-models/weightmodel.h" diff --git a/desktop-widgets/profilewidget.cpp b/desktop-widgets/profilewidget.cpp index ab28832a7..c232af1e9 100644 --- a/desktop-widgets/profilewidget.cpp +++ b/desktop-widgets/profilewidget.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "profilewidget.h" -#include "profile-widget/profilewidget2.h" +#include "profile-widget/profileview.h" #include "commands/command.h" #include "core/color.h" #include "core/event.h" @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include @@ -54,6 +56,7 @@ void EmptyView::resizeEvent(QResizeEvent *) update(); } +static const QUrl urlProfileView = QUrl(QStringLiteral("qrc:/qml/profileview.qml")); ProfileWidget::ProfileWidget() : d(nullptr), dc(0), placingCommand(false) { ui.setupUi(this); @@ -74,7 +77,10 @@ ProfileWidget::ProfileWidget() : d(nullptr), dc(0), placingCommand(false) emptyView.reset(new EmptyView); - view.reset(new ProfileWidget2(DivePlannerPointsModel::instance(), 1.0, this)); + viewWidget.reset(new QQuickWidget); + viewWidget->setSource(urlProfileView); + viewWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + QToolBar *toolBar = new QToolBar(this); for (QAction *a: toolbarActions) toolBar->addAction(a); @@ -83,7 +89,7 @@ ProfileWidget::ProfileWidget() : d(nullptr), dc(0), placingCommand(false) stack = new QStackedWidget(this); stack->addWidget(emptyView.get()); - stack->addWidget(view.get()); + stack->addWidget(viewWidget.get()); QHBoxLayout *layout = new QHBoxLayout(this); layout->setSpacing(0); @@ -123,14 +129,6 @@ ProfileWidget::ProfileWidget() : d(nullptr), dc(0), placingCommand(false) connect(ui.profPO2, &QAction::triggered, pp_gas, &qPrefPartialPressureGas::set_po2); connect(&diveListNotifier, &DiveListNotifier::divesChanged, this, &ProfileWidget::divesChanged); - connect(&diveListNotifier, &DiveListNotifier::settingsChanged, view.get(), &ProfileWidget2::settingsChanged); - connect(&diveListNotifier, &DiveListNotifier::cylinderAdded, this, &ProfileWidget::cylindersChanged); - connect(&diveListNotifier, &DiveListNotifier::cylinderRemoved, this, &ProfileWidget::cylindersChanged); - connect(&diveListNotifier, &DiveListNotifier::cylinderEdited, this, &ProfileWidget::cylindersChanged); - connect(view.get(), &ProfileWidget2::stopAdded, this, &ProfileWidget::stopAdded); - connect(view.get(), &ProfileWidget2::stopRemoved, this, &ProfileWidget::stopRemoved); - connect(view.get(), &ProfileWidget2::stopMoved, this, &ProfileWidget::stopMoved); - connect(view.get(), &ProfileWidget2::stopEdited, this, &ProfileWidget::stopEdited); ui.profCalcAllTissues->setChecked(qPrefTechnicalDetails::calcalltissues()); ui.profCalcCeiling->setChecked(qPrefTechnicalDetails::calcceiling()); @@ -151,12 +149,38 @@ ProfileWidget::ProfileWidget() : d(nullptr), dc(0), placingCommand(false) ui.profTissues->setChecked(qPrefTechnicalDetails::percentagegraph()); ui.profScaled->setChecked(qPrefTechnicalDetails::zoomed_plot()); ui.profInfobox->setChecked(qPrefTechnicalDetails::infobox()); + + //connect(&diveListNotifier, &DiveListNotifier::settingsChanged, view.get(), &ProfileWidget2::settingsChanged); + //connect(&diveListNotifier, &DiveListNotifier::cylinderAdded, this, &ProfileWidget::cylindersChanged); + //connect(&diveListNotifier, &DiveListNotifier::cylinderRemoved, this, &ProfileWidget::cylindersChanged); + //connect(&diveListNotifier, &DiveListNotifier::cylinderEdited, this, &ProfileWidget::cylindersChanged); + //connect(view.get(), &ProfileWidget2::stopAdded, this, &ProfileWidget::stopAdded); + //connect(view.get(), &ProfileWidget2::stopRemoved, this, &ProfileWidget::stopRemoved); + //connect(view.get(), &ProfileWidget2::stopMoved, this, &ProfileWidget::stopMoved); + //connect(view.get(), &ProfileWidget2::stopEdited, this, &ProfileWidget::stopEdited); } ProfileWidget::~ProfileWidget() { } +// hack around the Qt6 bug where the QML object gets destroyed and recreated +ProfileView *ProfileWidget::getView() +{ + ProfileView *view = qobject_cast(viewWidget->rootObject()); + if (!view) + qWarning("Oops. The root of the StatsView is not a StatsView."); + if (view) { + // try to prevent the JS garbage collection from freeing the object + // this appears to fail with Qt6 which is why we still look up the + // object from the rootObject + viewWidget->engine()->setObjectOwnership(view, QQmlEngine::CppOwnership); + view->setParent(this); + view->setVisible(isVisible()); // Synchronize visibility of widget and QtQuick-view. + } + return view; +} + void ProfileWidget::setEnabledToolbar(bool enabled) { for (QAction *b: toolbarActions) @@ -224,13 +248,14 @@ void ProfileWidget::plotDive(dive *dIn, int dcIn) editDive(); } + auto view = getView(); setEnabledToolbar(d != nullptr); if (editedDive) { view->plotDive(editedDive.get(), dc); setDive(editedDive.get(), dc); } else if (d) { - view->setProfileState(d, dc); - view->resetZoom(); // when switching dive, reset the zoomLevel + //view->setProfileState(d, dc); + //view->resetZoom(); // when switching dive, reset the zoomLevel view->plotDive(d, dc); setDive(d, dc); } else { @@ -273,7 +298,7 @@ void ProfileWidget::divesChanged(const QVector &dives, DiveField field) return; // If we're editing the current dive and not currently - // placing command, we have to update the edited dive. + // placing a command, we have to update the edited dive. if (editedDive) { copy_dive(d, editedDive.get()); // TODO: Holy moly that function sends too many signals. Fix it! @@ -307,7 +332,7 @@ void ProfileWidget::cylindersChanged(struct dive *changed, int pos) void ProfileWidget::setPlanState(const struct dive *d, int dcNr) { dc = dcNr; - view->setPlanState(d, dcNr); + //view->setPlanState(d, dcNr); setDive(d, dcNr); } @@ -329,7 +354,7 @@ void ProfileWidget::editDive() copy_dive(d, editedDive.get()); // Work on a copy of the dive DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::EDIT); DivePlannerPointsModel::instance()->loadFromDive(editedDive.get(), dc); - view->setEditState(editedDive.get(), dc); + //view->setEditState(editedDive.get(), dc); } void ProfileWidget::exitEditMode() @@ -338,7 +363,7 @@ void ProfileWidget::exitEditMode() return; DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::NOTHING); - view->setProfileState(d, dc); // switch back to original dive before erasing the copy. + //view->setProfileState(d, dc); // switch back to original dive before erasing the copy. editedDive.reset(); } diff --git a/desktop-widgets/profilewidget.h b/desktop-widgets/profilewidget.h index 4eb1c20c5..c36cf8f76 100644 --- a/desktop-widgets/profilewidget.h +++ b/desktop-widgets/profilewidget.h @@ -10,8 +10,9 @@ #include struct dive; -class ProfileWidget2; +class ProfileView; class EmptyView; +class QQuickWidget; class QStackedWidget; class ProfileWidget : public QWidget { @@ -19,7 +20,6 @@ class ProfileWidget : public QWidget { public: ProfileWidget(); ~ProfileWidget(); - std::unique_ptr view; void plotDive(struct dive *d, int dc); // Attempt to keep DC number id dc < 0 void plotCurrentDive(); void setPlanState(const struct dive *d, int dc); @@ -40,6 +40,8 @@ slots: void stopMoved(int count); void stopEdited(); private: + ProfileView *getView(); + std::unique_ptr viewWidget; std::unique_ptr emptyView; std::vector toolbarActions; Ui::ProfileWidget ui; diff --git a/desktop-widgets/qml/profileview.qml b/desktop-widgets/qml/profileview.qml new file mode 100644 index 000000000..a9055aeb7 --- /dev/null +++ b/desktop-widgets/qml/profileview.qml @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +import org.subsurfacedivelog.mobile 1.0 + +ProfileView { + property real dpr: 1.0 +} diff --git a/desktop-widgets/qml/profileview.qrc b/desktop-widgets/qml/profileview.qrc new file mode 100644 index 000000000..9a38d0bf1 --- /dev/null +++ b/desktop-widgets/qml/profileview.qrc @@ -0,0 +1,5 @@ + + + profileview.qml + + diff --git a/desktop-widgets/simplewidgets.cpp b/desktop-widgets/simplewidgets.cpp index 396c6a4aa..3802cff5c 100644 --- a/desktop-widgets/simplewidgets.cpp +++ b/desktop-widgets/simplewidgets.cpp @@ -19,7 +19,6 @@ #include "libdivecomputer/parser.h" #include "desktop-widgets/divelistview.h" #include "core/selection.h" -#include "profile-widget/profilewidget2.h" #include "commands/command.h" #include "core/metadata.h" #include "core/range.h" diff --git a/desktop-widgets/tab-widgets/TabDiveInformation.cpp b/desktop-widgets/tab-widgets/TabDiveInformation.cpp index 1662dbfa7..286734d16 100644 --- a/desktop-widgets/tab-widgets/TabDiveInformation.cpp +++ b/desktop-widgets/tab-widgets/TabDiveInformation.cpp @@ -2,7 +2,6 @@ #include "TabDiveInformation.h" #include "maintab.h" #include "ui_TabDiveInformation.h" -#include "profile-widget/profilewidget2.h" #include "../tagwidget.h" #include "commands/command.h" #include "core/subsurface-string.h" diff --git a/profile-widget/CMakeLists.txt b/profile-widget/CMakeLists.txt index ba8548088..d60185b57 100644 --- a/profile-widget/CMakeLists.txt +++ b/profile-widget/CMakeLists.txt @@ -24,6 +24,8 @@ set(SUBSURFACE_PROFILE_LIB_SRCS divetooltipitem.h profilescene.cpp profilescene.h + profileview.cpp + profileview.h tankitem.cpp tankitem.h ) @@ -38,8 +40,6 @@ set(SUBSURFACE_PROFILE_LIB_SRCS ${SUBSURFACE_PROFILE_LIB_SRCS} divehandler.cpp divehandler.h - profilewidget2.cpp - profilewidget2.h ruleritem.cpp ruleritem.h ) diff --git a/profile-widget/divehandler.cpp b/profile-widget/divehandler.cpp index 90c138014..ed5fb0346 100644 --- a/profile-widget/divehandler.cpp +++ b/profile-widget/divehandler.cpp @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 #include "divehandler.h" -#include "profilewidget2.h" #include "profilescene.h" #include "core/dive.h" #include "core/gettextfromc.h" @@ -22,8 +21,9 @@ DiveHandler::DiveHandler(const struct dive *d, int currentDcNr) : dive(d), dcNr( int DiveHandler::parentIndex() { - ProfileWidget2 *view = qobject_cast(scene()->views().first()); - return view->handleIndex(this); + //ProfileWidget2 *view = qobject_cast(scene()->views().first()); + //return view->handleIndex(this); + return 0; // FIXME } void DiveHandler::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) @@ -54,19 +54,17 @@ void DiveHandler::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) void DiveHandler::selfRemove() { -#ifndef SUBSURFACE_MOBILE setSelected(true); - ProfileWidget2 *view = qobject_cast(scene()->views().first()); - view->keyDeleteAction(); -#endif + //ProfileWidget2 *view = qobject_cast(scene()->views().first()); + //view->keyDeleteAction(); } void DiveHandler::changeGas() { - ProfileWidget2 *view = qobject_cast(scene()->views().first()); - QAction *action = qobject_cast(sender()); + //ProfileWidget2 *view = qobject_cast(scene()->views().first()); + //QAction *action = qobject_cast(sender()); - view->changeGas(parentIndex(), action->data().toInt()); + //view->changeGas(parentIndex(), action->data().toInt()); } void DiveHandler::mouseMoveEvent(QGraphicsSceneMouseEvent *event) @@ -75,9 +73,9 @@ void DiveHandler::mouseMoveEvent(QGraphicsSceneMouseEvent *event) return; t.start(); - ProfileWidget2 *view = qobject_cast(scene()->views().first()); - if(!view->profileScene->pointOnProfile(event->scenePos())) - return; + //ProfileWidget2 *view = qobject_cast(scene()->views().first()); + //if(!view->profileScene->pointOnProfile(event->scenePos())) + //return; QGraphicsEllipseItem::mouseMoveEvent(event); emit moved(); diff --git a/profile-widget/diveprofileitem.cpp b/profile-widget/diveprofileitem.cpp index 92f9f1bab..0af31f6bd 100644 --- a/profile-widget/diveprofileitem.cpp +++ b/profile-widget/diveprofileitem.cpp @@ -3,13 +3,15 @@ #include "profile-widget/divecartesianaxis.h" #include "profile-widget/divetextitem.h" #include "profile-widget/animationfunctions.h" +#include "core/dive.h" #include "core/profile.h" -#include "qt-models/diveplannermodel.h" #include "core/qthelper.h" #include "core/settings/qPrefTechnicalDetails.h" #include "core/settings/qPrefLog.h" #include "libdivecomputer/parser.h" -#include "profile-widget/profilewidget2.h" +#include "qt-models/diveplannermodel.h" + +#include AbstractProfilePolygonItem::AbstractProfilePolygonItem(const plot_info &pInfo, const DiveCartesianAxis &horizontal, const DiveCartesianAxis &vertical, DataAccessor accessor, diff --git a/profile-widget/divetextitem.cpp b/profile-widget/divetextitem.cpp index b4cbfacf5..b032591e1 100644 --- a/profile-widget/divetextitem.cpp +++ b/profile-widget/divetextitem.cpp @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 #include "divetextitem.h" -#include "profilewidget2.h" #include "core/color.h" #include "core/errorhelper.h" -#include +#include #include +#include +#include static const double outlineSize = 3.0; diff --git a/profile-widget/profilescene.cpp b/profile-widget/profilescene.cpp index 7d77f28ad..174a98bfa 100644 --- a/profile-widget/profilescene.cpp +++ b/profile-widget/profilescene.cpp @@ -465,6 +465,10 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM updateVisibility(hasHeartBeat, simplified); updateAxes(hasHeartBeat, simplified); + // When we found that we don't have enough place to draw, the state was set to empty. + if (empty) + return; + int newMaxtime = get_maxtime(plotInfo); if (calcMax || newMaxtime > maxtime) maxtime = newMaxtime; diff --git a/profile-widget/profileview.cpp b/profile-widget/profileview.cpp new file mode 100644 index 000000000..4a9e4735b --- /dev/null +++ b/profile-widget/profileview.cpp @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "profileview.h" +#include "profilescene.h" +#include "zvalues.h" +#include "core/dive.h" +#include "core/errorhelper.h" +#include "core/pref.h" +#include "core/settings/qPrefTechnicalDetails.h" +#include "qt-quick/chartitem.h" + +#include +#include + +static double calcZoom(int zoomLevel) +{ + // Base of exponential zoom function: one wheel-click will increase the zoom by 15%. + constexpr double zoomFactor = 1.15; + return zoomLevel == 0 ? 1.0 : pow(zoomFactor, zoomLevel); +} + +ProfileView::ProfileView(QQuickItem *parent) : ChartView(parent, ProfileZValue::Count), + d(nullptr), + dc(0), + zoomLevel(0), + zoomedPosition(0.0), + empty(true), + shouldCalculateMax(true), + profileScene(std::make_unique(1.0, false, false)) +{ + setBackgroundColor(Qt::black); + setFlag(ItemHasContents, true); + + setAcceptHoverEvents(true); + setAcceptedMouseButtons(Qt::LeftButton); +} + +ProfileView::ProfileView() : ProfileView(nullptr) +{ +} + +ProfileView::~ProfileView() +{ +} + +void ProfileView::resetPointers() +{ + profileItem.reset(); +} + +void ProfileView::plotAreaChanged(const QSizeF &s) +{ + if (!empty) + plotDive(d, dc, RenderFlags::Instant); +} + +void ProfileView::clear() +{ + //clearPictures(); + //disconnectPlannerConnections(); + profileScene->clear(); + //handles.clear(); + //gases.clear(); + empty = true; + d = nullptr; + dc = 0; +} + +void ProfileView::plotDive(const struct dive *dIn, int dcIn, int flags) +{ + d = dIn; + dc = dcIn; + if (!d) { + clear(); + return; + } + + // If there was no previously displayed dive, turn off animations + if (empty) + flags |= RenderFlags::Instant; + empty = false; + + // If Qt decided to destroy our canvas, recreate it + if (!profileItem) + profileItem = createChartItem(ProfileZValue::Profile); + + profileItem->setPos(QPointF(0.0, 0.0)); + + QElapsedTimer measureDuration; // let's measure how long this takes us (maybe we'll turn of TTL calculation later + measureDuration.start(); + + //DivePlannerPointsModel *model = currentState == EDIT || currentState == PLAN ? plannerModel : nullptr; + DivePlannerPointsModel *model = nullptr; + bool inPlanner = flags & RenderFlags::PlanMode; + + QColor backgroundColor = inPlanner ? QColor("#D7E3EF") + : getColor(::BACKGROUND, false); + + double zoom = calcZoom(zoomLevel); + + profileScene->resize(size()); + profileScene->plotDive(d, dc, model, inPlanner, true, //flags & RenderFlags::Instant, + flags & RenderFlags::DontRecalculatePlotInfo, + shouldCalculateMax, zoom, zoomedPosition); + profileItem->draw(size(), backgroundColor, *profileScene); + + //rulerItem->setVisible(prefs.rulergraph && currentState != PLAN && currentState != EDIT); + //toolTipItem->setPlotInfo(profileScene->plotInfo); + //rulerItem->setPlotInfo(d, profileScene->plotInfo); + + //if ((currentState == EDIT || currentState == PLAN) && plannerModel) { + //repositionDiveHandlers(); + //plannerModel->deleteTemporaryPlan(); + //} + + // On zoom / pan don't recreate the picture thumbnails, only change their position. + //if (flags & RenderFlags::DontRecalculatePlotInfo) + //updateThumbnails(); + //else + //plotPicturesInternal(d, flags & RenderFlags::Instant); + + //toolTipItem->refresh(d, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN); + + update(); + + // OK, how long did this take us? Anything above the second is way too long, + // so if we are calculation TTS / NDL then let's force that off. + qint64 elapsedTime = measureDuration.elapsed(); + if (verbose) + qDebug() << "Profile calculation for dive " << d->number << "took" << elapsedTime << "ms" << " -- calculated ceiling preference is" << prefs.calcceiling; + if (elapsedTime > 1000 && prefs.calcndltts) { + qPrefTechnicalDetails::set_calcndltts(false); + report_error("%s", qPrintable(tr("Show NDL / TTS was disabled because of excessive processing time"))); + } +} diff --git a/profile-widget/profileview.h b/profile-widget/profileview.h new file mode 100644 index 000000000..1d87d213d --- /dev/null +++ b/profile-widget/profileview.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef PROFILE_VIEW_H +#define PROFILE_VIEW_H + +#include "qt-quick/chartview.h" +#include + +class ChartGraphicsSceneItem; +class ProfileScene; + +class ProfileView : public ChartView { + Q_OBJECT +public: + ProfileView(); + ProfileView(QQuickItem *parent); + ~ProfileView(); + + struct RenderFlags { + static constexpr int None = 0; + static constexpr int Instant = 1 << 0; + static constexpr int DontRecalculatePlotInfo = 1 << 1; + static constexpr int EditMode = 1 << 2; + static constexpr int PlanMode = 1 << 3; + }; + + void plotDive(const struct dive *d, int dc, int flags = RenderFlags::None); + void clear(); +private: + const struct dive *d; + int dc; + int zoomLevel; + 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. + std::unique_ptr profileScene; + ChartItemPtr profileItem; + + void plotAreaChanged(const QSizeF &size) override; + void resetPointers() override; +}; + +#endif diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp index 255883535..cc4ae7b5c 100644 --- a/profile-widget/profilewidget2.cpp +++ b/profile-widget/profilewidget2.cpp @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include "profile-widget/profilewidget2.h" #include "profile-widget/profilescene.h" #include "core/device.h" #include "core/event.h" @@ -398,21 +397,6 @@ static void hideAll(const T &container) item->setVisible(false); } -void ProfileWidget2::clear() -{ - currentState = INIT; -#ifndef SUBSURFACE_MOBILE - clearPictures(); -#endif - disconnectPlannerModel(); - profileScene->clear(); - handles.clear(); - gases.clear(); - empty = true; - d = nullptr; - dc = 0; -} - void ProfileWidget2::setProfileState(const dive *dIn, int dcIn) { d = dIn; diff --git a/profile-widget/profilewidget2.h b/profile-widget/profilewidget2.h index 092a93caa..e6d372852 100644 --- a/profile-widget/profilewidget2.h +++ b/profile-widget/profilewidget2.h @@ -60,7 +60,6 @@ public: #ifndef SUBSURFACE_MOBILE bool eventFilter(QObject *, QEvent *) override; #endif - std::unique_ptr profileScene; State currentState; signals: diff --git a/profile-widget/ruleritem.cpp b/profile-widget/ruleritem.cpp index 755d24b12..97b98267d 100644 --- a/profile-widget/ruleritem.cpp +++ b/profile-widget/ruleritem.cpp @@ -1,12 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 #include "profile-widget/ruleritem.h" -#include "profile-widget/profilewidget2.h" #include "core/settings/qPrefTechnicalDetails.h" -#include - #include "core/profile.h" +#include +#include +#include +#include +#include + RulerNodeItem2::RulerNodeItem2() : pInfo(NULL), idx(-1), @@ -77,18 +80,16 @@ RulerItem2::RulerItem2() : pInfo(NULL), textItemBack->setPen(QColor(Qt::white)); textItemBack->setFlag(QGraphicsItem::ItemIgnoresTransformations); setPen(QPen(QColor(Qt::black), 0.0)); -#ifndef SUBSURFACE_MOBILE connect(qPrefTechnicalDetails::instance(), &qPrefTechnicalDetails::rulergraphChanged, this, &RulerItem2::settingsChanged); -#endif } void RulerItem2::settingsChanged(bool value) { - ProfileWidget2 *profWidget = NULL; - if (scene() && scene()->views().count()) - profWidget = qobject_cast(scene()->views().first()); + //ProfileWidget2 *profWidget = NULL; + //if (scene() && scene()->views().count()) + //profWidget = qobject_cast(scene()->views().first()); - setVisible( (profWidget && profWidget->currentState == ProfileWidget2::PROFILE) ? value : false); + //setVisible( (profWidget && profWidget->currentState == ProfileWidget2::PROFILE) ? value : false); } void RulerItem2::recalculate() diff --git a/profile-widget/zvalues.h b/profile-widget/zvalues.h new file mode 100644 index 000000000..2d3d2989e --- /dev/null +++ b/profile-widget/zvalues.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 +// Defines the z-values of features in the profile view. +// Objects with higher z-values are painted on top of objects +// with smaller z-values. For the same z-value objects are +// drawn in order of addition to the scene. +#ifndef PROFILE_ZVALUES_H +#define PROFILE_ZVALUES_H + +// Encapsulating an enum in a struct is stupid, but allows us +// to not poison the namespace and yet autoconvert to int +// (in constrast to enum class). enum is so broken! +struct ProfileZValue { + enum ZValues { + Profile = 0, + Count + }; +}; + +#endif diff --git a/qt-quick/chartitem.cpp b/qt-quick/chartitem.cpp index 90f83c545..56278ee28 100644 --- a/qt-quick/chartitem.cpp +++ b/qt-quick/chartitem.cpp @@ -4,6 +4,7 @@ #include "chartview.h" #include +#include #include #include #include @@ -83,10 +84,15 @@ void ChartPixmapItem::render() void ChartPixmapItem::resize(QSizeF size) { + QSize s_int(round_up(size.width()), round_up(size.height())); + if (img && s_int == img->size()) + return; painter.reset(); - img.reset(new QImage(round_up(size.width()), round_up(size.height()), QImage::Format_ARGB32)); - painter.reset(new QPainter(img.get())); - painter->setRenderHint(QPainter::Antialiasing); + img.reset(new QImage(s_int, QImage::Format_ARGB32)); + if (!img->isNull()) { + painter.reset(new QPainter(img.get())); + painter->setRenderHint(QPainter::Antialiasing); + } rect.setSize(size); setTextureDirty(); } @@ -102,6 +108,16 @@ QRectF ChartPixmapItem::getRect() const return rect; } +void ChartGraphicsSceneItem::draw(QSizeF s, QColor background, QGraphicsScene &scene) +{ + resize(s); // Noop if size doesn't change + if (!painter) + return; // Happens if we resize to (0,0) + img->fill(background); + scene.render(painter.get(), QRect(QPoint(), img->size()), scene.sceneRect(), Qt::IgnoreAspectRatio); + setTextureDirty(); +} + ChartRectItem::ChartRectItem(ChartView &v, size_t z, const QPen &pen, const QBrush &brush, double radius) : ChartPixmapItem(v, z), pen(pen), brush(brush), radius(radius) diff --git a/qt-quick/chartitem.h b/qt-quick/chartitem.h index 8313c1609..2b4e89cd1 100644 --- a/qt-quick/chartitem.h +++ b/qt-quick/chartitem.h @@ -11,6 +11,7 @@ #include class ChartView; +class QGraphicsScene; class QSGGeometry; class QSGGeometryNode; class QSGFlatColorMaterial; @@ -74,6 +75,14 @@ private: std::unique_ptr texture; }; +// Renders a QGraphicsScene +class ChartGraphicsSceneItem : public ChartPixmapItem +{ +public: + using ChartPixmapItem::ChartPixmapItem; + void draw(QSizeF s, QColor background, QGraphicsScene &scene); +}; + // Draw a rectangular background after resize. Children are responsible for calling update(). class ChartRectItem : public ChartPixmapItem { public: diff --git a/subsurface-helper.cpp b/subsurface-helper.cpp index df40cb433..5da07f798 100644 --- a/subsurface-helper.cpp +++ b/subsurface-helper.cpp @@ -7,6 +7,7 @@ #include "qt-models/maplocationmodel.h" #endif +#include "profile-widget/profileview.h" #include "stats/statsview.h" #include "core/devicedetails.h" #include "core/errorhelper.h" @@ -229,5 +230,6 @@ static void register_qml_types(QQmlEngine *engine) register_qml_type("MapWidgetHelper"); register_qml_type("MapLocationModel"); #endif + register_qml_type("ProfileView"); register_qml_type("StatsView"); }