2017-04-27 20:26:36 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2021-06-05 18:42:56 +02:00
|
|
|
#include "profile-widget/profilescene.h"
|
2021-08-03 09:51:37 +02:00
|
|
|
#include "core/device.h"
|
2020-10-25 09:14:16 +01:00
|
|
|
#include "core/event.h"
|
2024-02-14 10:59:13 +01:00
|
|
|
#include "core/eventtype.h"
|
2018-05-11 08:25:41 -07:00
|
|
|
#include "core/subsurface-string.h"
|
2018-06-03 22:15:19 +02:00
|
|
|
#include "core/qthelper.h"
|
2022-09-24 14:06:56 +02:00
|
|
|
#include "core/range.h"
|
2018-08-15 11:52:50 +02:00
|
|
|
#include "core/settings/qPrefTechnicalDetails.h"
|
|
|
|
#include "core/settings/qPrefPartialPressureGas.h"
|
2016-04-04 22:02:03 -07:00
|
|
|
#include "profile-widget/diveeventitem.h"
|
|
|
|
#include "profile-widget/divetextitem.h"
|
|
|
|
#include "profile-widget/divetooltipitem.h"
|
2020-11-25 18:30:49 +01:00
|
|
|
#include "profile-widget/divehandler.h"
|
2016-04-04 22:02:03 -07:00
|
|
|
#include "core/planner.h"
|
|
|
|
#include "profile-widget/ruleritem.h"
|
|
|
|
#include "core/pref.h"
|
2016-03-06 06:52:55 -08:00
|
|
|
#include "qt-models/diveplannermodel.h"
|
|
|
|
#include "qt-models/models.h"
|
2019-08-05 19:41:15 +02:00
|
|
|
#include "core/errorhelper.h"
|
2015-11-05 16:05:44 -08:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
2016-04-04 22:02:03 -07:00
|
|
|
#include "desktop-widgets/simplewidgets.h"
|
2019-11-13 15:08:40 +01:00
|
|
|
#include "commands/command.h"
|
2018-06-17 08:48:54 +02:00
|
|
|
#include "core/gettextfromc.h"
|
2018-06-30 11:36:37 +02:00
|
|
|
#include "core/imagedownloader.h"
|
2015-11-05 16:05:44 -08:00
|
|
|
#endif
|
2015-02-09 18:27:59 -02:00
|
|
|
|
2014-03-15 21:12:34 -07:00
|
|
|
#include <QMessageBox>
|
2014-04-03 21:16:15 +02:00
|
|
|
#include <QInputDialog>
|
2015-02-09 18:58:40 -02:00
|
|
|
#include <QWheelEvent>
|
2015-11-05 12:50:51 -08:00
|
|
|
#include <QMenu>
|
2021-04-25 21:31:44 +02:00
|
|
|
#include <QMimeData>
|
2018-05-29 12:49:47 +02:00
|
|
|
#include <QElapsedTimer>
|
2014-01-16 15:02:32 -02:00
|
|
|
|
2014-01-15 13:20:05 -02:00
|
|
|
#ifndef QT_NO_DEBUG
|
|
|
|
#include <QTableView>
|
|
|
|
#endif
|
|
|
|
|
2018-07-15 17:56:18 +02:00
|
|
|
// Constant describing at which z-level the thumbnails are located.
|
|
|
|
// We might add more constants here for easier customability.
|
|
|
|
static const double thumbnailBaseZValue = 100.0;
|
2021-10-04 21:41:17 +02:00
|
|
|
|
2022-08-28 22:42:54 +02:00
|
|
|
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);
|
|
|
|
}
|
2018-07-15 17:56:18 +02:00
|
|
|
|
2021-08-09 16:48:08 +02:00
|
|
|
ProfileWidget2::ProfileWidget2(DivePlannerPointsModel *plannerModelIn, double dpr, QWidget *parent) : QGraphicsView(parent),
|
|
|
|
profileScene(new ProfileScene(dpr, false, false)),
|
2021-07-01 18:56:50 +02:00
|
|
|
currentState(INIT),
|
2021-01-25 15:06:53 +01:00
|
|
|
plannerModel(plannerModelIn),
|
2014-02-04 21:47:50 -02:00
|
|
|
zoomLevel(0),
|
2022-03-12 14:06:12 +01:00
|
|
|
zoomedPosition(0.0),
|
2016-02-06 13:25:58 -08:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
2014-02-05 14:34:45 -02:00
|
|
|
toolTipItem(new ToolTipItem()),
|
2016-02-06 13:25:58 -08:00
|
|
|
#endif
|
2021-07-01 18:56:50 +02:00
|
|
|
d(nullptr),
|
|
|
|
dc(0),
|
2021-12-03 08:50:52 +01:00
|
|
|
empty(true),
|
2022-08-28 22:42:54 +02:00
|
|
|
panning(false),
|
2021-01-04 17:55:42 -08:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
2014-08-05 18:27:00 -03:00
|
|
|
mouseFollowerVertical(new DiveLineItem()),
|
2014-08-06 10:54:37 -07:00
|
|
|
mouseFollowerHorizontal(new DiveLineItem()),
|
2014-03-25 23:34:09 +02:00
|
|
|
rulerItem(new RulerItem2()),
|
2016-02-06 13:25:58 -08:00
|
|
|
#endif
|
2021-07-29 06:50:59 +02:00
|
|
|
shouldCalculateMax(true)
|
2014-01-14 14:30:13 -02:00
|
|
|
{
|
2014-02-07 14:59:58 -02:00
|
|
|
setupSceneAndFlags();
|
|
|
|
setupItemOnScene();
|
|
|
|
addItemsToScene();
|
|
|
|
scene()->installEventFilter(this);
|
2015-11-12 01:37:18 +01:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
2015-11-03 21:17:50 +01:00
|
|
|
setAcceptDrops(true);
|
|
|
|
|
2018-06-30 11:36:37 +02:00
|
|
|
connect(Thumbnailer::instance(), &Thumbnailer::thumbnailChanged, this, &ProfileWidget2::updateThumbnail, Qt::QueuedConnection);
|
2020-03-03 22:42:51 +01:00
|
|
|
connect(&diveListNotifier, &DiveListNotifier::cylinderEdited, this, &ProfileWidget2::profileChanged);
|
|
|
|
connect(&diveListNotifier, &DiveListNotifier::eventsChanged, this, &ProfileWidget2::profileChanged);
|
2021-01-27 23:41:51 +01:00
|
|
|
connect(&diveListNotifier, &DiveListNotifier::divesChanged, this, &ProfileWidget2::divesChanged);
|
2021-08-17 11:19:41 -07:00
|
|
|
connect(&diveListNotifier, &DiveListNotifier::deviceEdited, this, &ProfileWidget2::replot);
|
2022-02-19 18:47:25 +01:00
|
|
|
connect(&diveListNotifier, &DiveListNotifier::diveComputerEdited, this, &ProfileWidget2::replot);
|
2015-11-12 01:37:18 +01:00
|
|
|
#endif // SUBSURFACE_MOBILE
|
2014-05-24 12:39:40 -03:00
|
|
|
|
2015-02-02 13:12:11 -08:00
|
|
|
#if !defined(QT_NO_DEBUG) && defined(SHOW_PLOT_INFO_TABLE)
|
2014-02-07 14:59:58 -02:00
|
|
|
QTableView *diveDepthTableView = new QTableView();
|
2021-06-28 20:29:46 +02:00
|
|
|
diveDepthTableView->setModel(profileScene->dataModel);
|
2014-03-07 12:42:13 -03:00
|
|
|
diveDepthTableView->show();
|
2014-02-07 14:59:58 -02:00
|
|
|
#endif
|
2020-11-25 20:03:49 +01:00
|
|
|
|
2021-07-01 18:56:50 +02:00
|
|
|
setProfileState();
|
2014-02-07 14:59:58 -02:00
|
|
|
}
|
2014-01-15 12:23:40 -02:00
|
|
|
|
2019-07-15 20:41:42 +02:00
|
|
|
ProfileWidget2::~ProfileWidget2()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-01-10 16:50:57 +01:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
2022-02-19 14:06:58 +01:00
|
|
|
void ProfileWidget2::keyPressEvent(QKeyEvent *e)
|
|
|
|
{
|
|
|
|
switch (e->key()) {
|
|
|
|
case Qt::Key_Delete: return keyDeleteAction();
|
|
|
|
case Qt::Key_Up: return keyUpAction();
|
|
|
|
case Qt::Key_Down: return keyDownAction();
|
|
|
|
case Qt::Key_Left: return keyLeftAction();
|
|
|
|
case Qt::Key_Right: return keyRightAction();
|
|
|
|
}
|
|
|
|
QGraphicsView::keyPressEvent(e);
|
2018-01-10 16:50:57 +01:00
|
|
|
}
|
|
|
|
#endif // SUBSURFACE_MOBILE
|
|
|
|
|
2014-02-07 14:59:58 -02:00
|
|
|
void ProfileWidget2::addItemsToScene()
|
|
|
|
{
|
2017-03-25 13:03:37 +01:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
|
|
|
scene()->addItem(toolTipItem);
|
2014-02-27 15:20:03 -03:00
|
|
|
scene()->addItem(rulerItem);
|
|
|
|
scene()->addItem(rulerItem->sourceNode());
|
|
|
|
scene()->addItem(rulerItem->destNode());
|
2014-08-05 18:27:00 -03:00
|
|
|
scene()->addItem(mouseFollowerHorizontal);
|
|
|
|
scene()->addItem(mouseFollowerVertical);
|
2014-08-05 15:47:02 -07:00
|
|
|
QPen pen(QColor(Qt::red).lighter());
|
|
|
|
pen.setWidth(0);
|
|
|
|
mouseFollowerHorizontal->setPen(pen);
|
|
|
|
mouseFollowerVertical->setPen(pen);
|
2016-02-06 13:25:58 -08:00
|
|
|
#endif
|
2014-02-07 14:59:58 -02:00
|
|
|
}
|
2014-01-15 12:23:40 -02:00
|
|
|
|
2014-02-07 14:59:58 -02:00
|
|
|
void ProfileWidget2::setupItemOnScene()
|
|
|
|
{
|
2016-02-06 13:25:58 -08:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
2014-03-12 00:09:54 +02:00
|
|
|
toolTipItem->setZValue(9998);
|
2021-06-28 20:29:46 +02:00
|
|
|
toolTipItem->setTimeAxis(profileScene->timeAxis);
|
2014-03-12 00:09:54 +02:00
|
|
|
rulerItem->setZValue(9997);
|
2021-06-28 20:29:46 +02:00
|
|
|
rulerItem->setAxis(profileScene->timeAxis, profileScene->profileYAxis);
|
2021-12-10 12:15:44 +01:00
|
|
|
mouseFollowerHorizontal->setZValue(9996);
|
|
|
|
mouseFollowerVertical->setZValue(9995);
|
2016-02-06 13:25:58 -08:00
|
|
|
#endif
|
2014-02-07 14:59:58 -02:00
|
|
|
}
|
2014-01-15 13:01:29 -02:00
|
|
|
|
2020-04-12 12:20:25 +02:00
|
|
|
void ProfileWidget2::replot()
|
2014-03-09 10:59:31 -03:00
|
|
|
{
|
2021-10-20 11:50:44 +02:00
|
|
|
plotDive(d, dc);
|
2014-03-09 10:59:31 -03:00
|
|
|
}
|
|
|
|
|
2014-02-07 14:59:58 -02:00
|
|
|
void ProfileWidget2::setupSceneAndFlags()
|
|
|
|
{
|
2021-06-05 18:42:56 +02:00
|
|
|
setScene(profileScene.get());
|
2014-02-07 14:59:58 -02:00
|
|
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
|
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
|
|
setOptimizationFlags(QGraphicsView::DontSavePainterState);
|
|
|
|
setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
|
|
|
|
setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
|
|
|
setMouseTracking(true);
|
|
|
|
}
|
2014-01-14 14:30:13 -02:00
|
|
|
|
|
|
|
// Currently just one dive, but the plan is to enable All of the selected dives.
|
2021-10-22 14:30:56 +02:00
|
|
|
void ProfileWidget2::plotDive(const struct dive *dIn, int dcIn, int flags)
|
2014-01-14 14:30:13 -02:00
|
|
|
{
|
2021-01-28 14:24:38 +01:00
|
|
|
d = dIn;
|
|
|
|
dc = dcIn;
|
|
|
|
if (!d) {
|
2021-07-01 18:56:50 +02:00
|
|
|
clear();
|
2021-01-28 14:24:38 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-12-03 08:50:52 +01:00
|
|
|
// If there was no previously displayed dive, turn off animations
|
|
|
|
if (empty)
|
|
|
|
flags |= RenderFlags::Instant;
|
|
|
|
empty = false;
|
|
|
|
|
2018-05-29 12:49:47 +02:00
|
|
|
QElapsedTimer measureDuration; // let's measure how long this takes us (maybe we'll turn of TTL calculation later
|
2014-06-04 13:41:50 -07:00
|
|
|
measureDuration.start();
|
2014-03-11 18:54:28 -03:00
|
|
|
|
2021-08-03 09:51:37 +02:00
|
|
|
DivePlannerPointsModel *model = currentState == EDIT || currentState == PLAN ? plannerModel : nullptr;
|
|
|
|
bool inPlanner = currentState == PLAN;
|
|
|
|
|
2022-08-28 22:42:54 +02:00
|
|
|
double zoom = calcZoom(zoomLevel);
|
2021-10-22 18:23:15 +02:00
|
|
|
profileScene->plotDive(d, dc, model, inPlanner, flags & RenderFlags::Instant,
|
|
|
|
flags & RenderFlags::DontRecalculatePlotInfo,
|
|
|
|
shouldCalculateMax, zoom, zoomedPosition);
|
2021-08-03 09:51:37 +02:00
|
|
|
|
2015-12-01 15:36:20 -08:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
2023-06-18 15:28:51 +12:00
|
|
|
toolTipItem->setVisible(prefs.infobox);
|
2021-08-03 09:51:37 +02:00
|
|
|
toolTipItem->setPlotInfo(profileScene->plotInfo);
|
2023-06-18 15:28:51 +12:00
|
|
|
rulerItem->setVisible(prefs.rulergraph && currentState != PLAN && currentState != EDIT);
|
2021-08-03 09:51:37 +02:00
|
|
|
rulerItem->setPlotInfo(d, profileScene->plotInfo);
|
2014-02-07 17:59:21 -02:00
|
|
|
|
2021-06-30 07:49:56 +02:00
|
|
|
if ((currentState == EDIT || currentState == PLAN) && plannerModel) {
|
2014-05-21 23:31:26 -03:00
|
|
|
repositionDiveHandlers();
|
2021-01-25 15:06:53 +01:00
|
|
|
plannerModel->deleteTemporaryPlan();
|
2014-05-21 23:31:26 -03:00
|
|
|
}
|
2021-10-26 07:42:13 +02:00
|
|
|
|
|
|
|
// On zoom / pan don't recreate the picture thumbnails, only change their position.
|
|
|
|
if (flags & RenderFlags::DontRecalculatePlotInfo)
|
|
|
|
updateThumbnails();
|
|
|
|
else
|
|
|
|
plotPicturesInternal(d, flags & RenderFlags::Instant);
|
2018-10-17 11:28:33 +02:00
|
|
|
|
2021-01-28 14:24:38 +01:00
|
|
|
toolTipItem->refresh(d, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN);
|
2018-01-10 13:55:29 +01:00
|
|
|
#endif
|
2014-07-21 18:54:28 -03:00
|
|
|
|
2014-06-04 13:41:50 -07:00
|
|
|
// 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.
|
2021-01-04 17:55:42 -08:00
|
|
|
qint64 elapsedTime = measureDuration.elapsed();
|
|
|
|
if (verbose)
|
2024-03-26 18:33:22 +01:00
|
|
|
report_info("Profile calculation for dive %d took %lld ms -- calculated ceiling preference is %d", d->number, elapsedTime, prefs.calcceiling);
|
2021-01-04 17:55:42 -08:00
|
|
|
if (elapsedTime > 1000 && prefs.calcndltts) {
|
2018-08-15 11:52:50 +02:00
|
|
|
qPrefTechnicalDetails::set_calcndltts(false);
|
2024-03-12 09:17:50 +01:00
|
|
|
report_error("%s", qPrintable(tr("Show NDL / TTS was disabled because of excessive processing time")));
|
2014-06-04 13:41:50 -07:00
|
|
|
}
|
2014-01-14 14:30:13 -02:00
|
|
|
}
|
|
|
|
|
2021-01-27 23:41:51 +01:00
|
|
|
void ProfileWidget2::divesChanged(const QVector<dive *> &dives, DiveField field)
|
|
|
|
{
|
|
|
|
// If the mode of the currently displayed dive changed, replot
|
|
|
|
if (field.mode &&
|
2022-09-17 19:51:53 +02:00
|
|
|
std::find(dives.begin(), dives.end(), d) != dives.end())
|
2021-01-27 23:41:51 +01:00
|
|
|
replot();
|
|
|
|
}
|
|
|
|
|
2018-05-21 18:20:29 +02:00
|
|
|
void ProfileWidget2::actionRequestedReplot(bool)
|
2016-01-25 15:54:23 -02:00
|
|
|
{
|
|
|
|
settingsChanged();
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:16:44 +02:00
|
|
|
void ProfileWidget2::settingsChanged()
|
|
|
|
{
|
2020-12-29 23:03:38 +01:00
|
|
|
replot();
|
2014-01-14 14:30:13 -02:00
|
|
|
}
|
|
|
|
|
2014-02-27 20:09:57 -08:00
|
|
|
void ProfileWidget2::resizeEvent(QResizeEvent *event)
|
2014-01-14 14:30:13 -02:00
|
|
|
{
|
2014-02-10 20:45:08 -08:00
|
|
|
QGraphicsView::resizeEvent(event);
|
2021-08-28 23:36:09 +02:00
|
|
|
profileScene->resize(viewport()->size());
|
2021-10-22 18:23:15 +02:00
|
|
|
plotDive(d, dc, RenderFlags::Instant | RenderFlags::DontRecalculatePlotInfo); // disable animation on resize events
|
2014-01-15 12:55:33 -02:00
|
|
|
}
|
|
|
|
|
2016-02-06 13:25:58 -08:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
2014-02-05 16:15:59 -02:00
|
|
|
bool ProfileWidget2::eventFilter(QObject *object, QEvent *event)
|
|
|
|
{
|
2014-02-27 20:09:57 -08:00
|
|
|
QGraphicsScene *s = qobject_cast<QGraphicsScene *>(object);
|
|
|
|
if (s && event->type() == QEvent::GraphicsSceneHelp) {
|
2014-02-05 16:15:59 -02:00
|
|
|
event->ignore();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return QGraphicsView::eventFilter(object, event);
|
|
|
|
}
|
2016-02-06 13:25:58 -08:00
|
|
|
#endif
|
2014-02-07 16:34:42 -02:00
|
|
|
|
2018-01-10 16:36:45 +01:00
|
|
|
template <typename T>
|
2019-04-01 22:15:19 +02:00
|
|
|
static void hideAll(const T &container)
|
2018-01-10 16:36:45 +01:00
|
|
|
{
|
2021-01-24 09:13:56 +01:00
|
|
|
for (auto &item: container)
|
2018-01-10 16:36:45 +01:00
|
|
|
item->setVisible(false);
|
|
|
|
}
|
|
|
|
|
2021-01-28 14:24:38 +01:00
|
|
|
void ProfileWidget2::setProfileState(const dive *dIn, int dcIn)
|
|
|
|
{
|
|
|
|
d = dIn;
|
|
|
|
dc = dcIn;
|
|
|
|
|
|
|
|
setProfileState();
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:42 -02:00
|
|
|
void ProfileWidget2::setProfileState()
|
|
|
|
{
|
2014-02-07 16:54:12 -02:00
|
|
|
if (currentState == PROFILE)
|
|
|
|
return;
|
2014-02-07 16:34:42 -02:00
|
|
|
|
2014-02-07 16:54:12 -02:00
|
|
|
currentState = PROFILE;
|
2021-07-29 06:50:59 +02:00
|
|
|
setBackgroundBrush(getColor(::BACKGROUND, profileScene->isGrayscale));
|
2014-02-07 17:38:00 -02:00
|
|
|
|
2016-02-06 13:25:58 -08:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
|
|
|
toolTipItem->readPos();
|
2023-06-18 15:28:51 +12:00
|
|
|
toolTipItem->setVisible(prefs.infobox);
|
2014-05-21 12:57:48 -03:00
|
|
|
rulerItem->setVisible(prefs.rulergraph);
|
2016-02-06 13:25:58 -08:00
|
|
|
mouseFollowerHorizontal->setVisible(false);
|
|
|
|
mouseFollowerVertical->setVisible(false);
|
2015-11-05 16:05:44 -08:00
|
|
|
#endif
|
2021-07-01 18:56:50 +02:00
|
|
|
|
|
|
|
handles.clear();
|
|
|
|
gases.clear();
|
2014-02-07 16:34:42 -02:00
|
|
|
}
|
2014-02-17 19:15:40 -03:00
|
|
|
|
2015-11-05 16:05:44 -08:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
2021-06-30 07:49:56 +02:00
|
|
|
void ProfileWidget2::setEditState(const dive *d, int dc)
|
2014-05-21 15:52:24 -03:00
|
|
|
{
|
2021-06-30 07:49:56 +02:00
|
|
|
if (currentState == EDIT)
|
2014-05-21 15:52:24 -03:00
|
|
|
return;
|
|
|
|
|
2021-01-28 14:24:38 +01:00
|
|
|
setProfileState(d, dc);
|
2014-08-06 12:33:36 -07:00
|
|
|
mouseFollowerHorizontal->setVisible(true);
|
|
|
|
mouseFollowerVertical->setVisible(true);
|
2014-05-24 12:39:40 -03:00
|
|
|
|
2022-03-12 13:10:29 +01:00
|
|
|
currentState = EDIT;
|
2021-02-27 16:01:28 +01:00
|
|
|
|
|
|
|
repositionDiveHandlers();
|
2014-05-21 15:52:24 -03:00
|
|
|
}
|
|
|
|
|
2021-01-28 14:24:38 +01:00
|
|
|
void ProfileWidget2::setPlanState(const dive *d, int dc)
|
2014-05-21 15:52:24 -03:00
|
|
|
{
|
|
|
|
if (currentState == PLAN)
|
|
|
|
return;
|
2014-05-25 15:12:00 -03:00
|
|
|
|
2021-01-28 14:24:38 +01:00
|
|
|
setProfileState(d, dc);
|
2014-08-06 12:33:36 -07:00
|
|
|
mouseFollowerHorizontal->setVisible(true);
|
|
|
|
mouseFollowerVertical->setVisible(true);
|
2014-05-25 14:16:43 -03:00
|
|
|
|
2022-03-12 13:10:29 +01:00
|
|
|
currentState = PLAN;
|
2014-06-30 18:46:51 -03:00
|
|
|
setBackgroundBrush(QColor("#D7E3EF"));
|
2021-02-27 16:01:28 +01:00
|
|
|
|
|
|
|
repositionDiveHandlers();
|
2014-05-21 15:52:24 -03:00
|
|
|
}
|
2016-02-06 13:25:58 -08:00
|
|
|
#endif
|
2014-05-21 15:52:24 -03:00
|
|
|
|
2021-01-10 14:04:43 +01:00
|
|
|
bool ProfileWidget2::isPlanner() const
|
2014-05-26 15:17:34 -07:00
|
|
|
{
|
|
|
|
return currentState == PLAN;
|
|
|
|
}
|
|
|
|
|
2019-07-06 12:09:15 +02:00
|
|
|
#if 0 // TODO::: FINISH OR DISABLE
|
2019-07-06 12:35:33 +02:00
|
|
|
struct int ProfileWidget2::getEntryFromPos(QPointF pos)
|
2014-11-19 22:31:28 +00:00
|
|
|
{
|
|
|
|
// find the time stamp corresponding to the mouse position
|
2017-03-23 08:13:49 +07:00
|
|
|
int seconds = lrint(timeAxis->valueAt(pos));
|
2014-11-19 22:31:28 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < plotInfo.nr; i++) {
|
2019-07-06 12:35:33 +02:00
|
|
|
if (plotInfo.entry[i].sec >= seconds)
|
|
|
|
return i;
|
2014-11-19 22:31:28 +00:00
|
|
|
}
|
2019-07-06 12:35:33 +02:00
|
|
|
return plotInfo.nr - 1;
|
2014-11-19 22:31:28 +00:00
|
|
|
}
|
2019-07-06 12:09:15 +02:00
|
|
|
#endif
|
2014-11-19 22:31:28 +00:00
|
|
|
|
2015-11-05 16:05:44 -08:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
2021-04-25 22:35:41 +02:00
|
|
|
static bool isDiveTextItem(const QGraphicsItem *item, const DiveTextItem *textItem)
|
|
|
|
{
|
|
|
|
while (item) {
|
|
|
|
if (item == textItem)
|
|
|
|
return true;
|
|
|
|
item = item->parentItem();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-05-15 17:23:39 +12:00
|
|
|
void ProfileWidget2::addGasChangeMenu(QMenu &m, QString menuTitle, const struct dive &d, int dcNr, int changeTime)
|
|
|
|
{
|
|
|
|
QMenu *gasChange = m.addMenu(menuTitle);
|
|
|
|
std::vector<std::pair<int, QString>> gases = get_dive_gas_list(&d, dcNr, true);
|
|
|
|
for (unsigned i = 0; i < gases.size(); i++) {
|
|
|
|
int cylinderIndex = gases[i].first;
|
|
|
|
gasChange->addAction(gases[i].second, [this, cylinderIndex, changeTime] { addGasSwitch(cylinderIndex, changeTime); });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-27 20:09:57 -08:00
|
|
|
void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
2014-02-17 19:15:40 -03:00
|
|
|
{
|
2021-06-30 07:49:56 +02:00
|
|
|
if (currentState == EDIT || currentState == PLAN) {
|
2014-05-25 00:33:39 -03:00
|
|
|
QGraphicsView::contextMenuEvent(event);
|
|
|
|
return;
|
|
|
|
}
|
2014-05-19 14:39:34 +09:00
|
|
|
QMenu m;
|
2021-01-28 14:24:38 +01:00
|
|
|
if (!d)
|
2014-02-17 19:15:40 -03:00
|
|
|
return;
|
2021-04-25 22:35:41 +02:00
|
|
|
|
2014-05-19 14:39:34 +09:00
|
|
|
// create the profile context menu
|
2020-01-30 15:03:48 +01:00
|
|
|
QPointF scenePos = mapToScene(mapFromGlobal(event->globalPos()));
|
2021-06-28 20:29:46 +02:00
|
|
|
qreal sec_val = profileScene->timeAxis->valueAt(scenePos);
|
2020-01-30 15:03:48 +01:00
|
|
|
int seconds = (sec_val < 0.0) ? 0 : (int)sec_val;
|
2020-08-25 05:37:08 +09:00
|
|
|
DiveEventItem *item = dynamic_cast<DiveEventItem *>(sceneItem);
|
|
|
|
|
|
|
|
// Add or edit Gas Change
|
2024-05-25 20:12:10 +02:00
|
|
|
if (d && item && item->ev.is_gaschange()) {
|
2024-09-09 23:53:06 +12:00
|
|
|
addGasChangeMenu(m, tr("Edit gas change"), *d, dc, item->ev.time.seconds);
|
2024-05-28 21:31:11 +02:00
|
|
|
} else if (d && d->cylinders.size() > 1) {
|
2014-11-19 21:03:58 +00:00
|
|
|
// if we have more than one gas, offer to switch to another one
|
2024-09-09 23:53:06 +12:00
|
|
|
const struct divecomputer *currentdc = d->get_dc(dc);
|
|
|
|
if (seconds == 0 || (!currentdc->samples.empty() && seconds <= currentdc->samples[0].time.seconds))
|
|
|
|
addGasChangeMenu(m, tr("Set initial gas"), *d, dc, 0);
|
|
|
|
else
|
|
|
|
addGasChangeMenu(m, tr("Add gas change"), *d, dc, seconds);
|
2014-02-17 19:15:40 -03:00
|
|
|
}
|
2020-03-02 22:02:33 +01:00
|
|
|
m.addAction(tr("Add setpoint change"), [this, seconds]() { ProfileWidget2::addSetpointChange(seconds); });
|
|
|
|
m.addAction(tr("Add bookmark"), [this, seconds]() { addBookmark(seconds); });
|
|
|
|
m.addAction(tr("Split dive into two"), [this, seconds]() { splitDive(seconds); });
|
2018-04-08 22:09:26 +02:00
|
|
|
|
2024-06-30 20:38:12 +02:00
|
|
|
divemode_loop loop(*d->get_dc(dc));
|
2024-09-03 19:48:49 +12:00
|
|
|
divemode_t divemode = loop.at(seconds);
|
2018-04-08 22:09:26 +02:00
|
|
|
QMenu *changeMode = m.addMenu(tr("Change divemode"));
|
2020-03-02 22:34:39 +01:00
|
|
|
if (divemode != OC)
|
|
|
|
changeMode->addAction(gettextFromC::tr(divemode_text_ui[OC]),
|
|
|
|
[this, seconds](){ addDivemodeSwitch(seconds, OC); });
|
|
|
|
if (divemode != CCR)
|
|
|
|
changeMode->addAction(gettextFromC::tr(divemode_text_ui[CCR]),
|
|
|
|
[this, seconds](){ addDivemodeSwitch(seconds, CCR); });
|
|
|
|
if (divemode != PSCR)
|
|
|
|
changeMode->addAction(gettextFromC::tr(divemode_text_ui[PSCR]),
|
|
|
|
[this, seconds](){ addDivemodeSwitch(seconds, PSCR); });
|
2015-04-23 13:56:24 -07:00
|
|
|
|
2014-03-15 21:12:34 -07:00
|
|
|
if (DiveEventItem *item = dynamic_cast<DiveEventItem *>(sceneItem)) {
|
2020-03-02 22:34:39 +01:00
|
|
|
m.addAction(tr("Remove event"), [this,item] { removeEvent(item); });
|
2023-07-28 01:21:25 +12:00
|
|
|
m.addAction(tr("Hide event"), [this, item] { hideEvent(item); });
|
2024-05-25 08:16:57 +02:00
|
|
|
m.addAction(tr("Hide events of type '%1'").arg(event_type_name(item->ev)),
|
2024-02-19 09:04:14 +01:00
|
|
|
[this, item] { hideEventType(item); });
|
2024-05-25 08:16:57 +02:00
|
|
|
if (item->ev.type == SAMPLE_EVENT_BOOKMARK)
|
2020-03-02 22:34:39 +01:00
|
|
|
m.addAction(tr("Edit name"), [this, item] { editName(item); });
|
2019-07-06 12:09:15 +02:00
|
|
|
#if 0 // TODO::: FINISH OR DISABLE
|
2017-08-26 12:11:44 -07:00
|
|
|
QPointF scenePos = mapToScene(event->pos());
|
2019-07-06 12:35:33 +02:00
|
|
|
int idx = getEntryFromPos(scenePos);
|
2014-11-19 16:15:10 -08:00
|
|
|
// this shows how to figure out if we should ask the user if they want adjust interpolated pressures
|
|
|
|
// at either side of a gas change
|
2024-05-25 08:16:57 +02:00
|
|
|
if (item->ev->type == SAMPLE_EVENT_GASCHANGE || item->ev->type == SAMPLE_EVENT_GASCHANGE2) {
|
2019-07-06 12:35:33 +02:00
|
|
|
int gasChangeIdx = idx;
|
|
|
|
while (gasChangeIdx > 0) {
|
|
|
|
--gasChangeIdx;
|
2024-05-25 08:16:57 +02:00
|
|
|
if (plotInfo.entry[gasChangeIdx].sec <= item->ev->time.seconds)
|
2014-11-19 16:15:10 -08:00
|
|
|
break;
|
|
|
|
}
|
2019-07-06 12:35:33 +02:00
|
|
|
const struct plot_data &gasChangeEntry = plotInfo.entry[newGasIdx];
|
2014-11-19 16:15:10 -08:00
|
|
|
// now gasChangeEntry points at the gas change, that entry has the final pressure of
|
|
|
|
// the old tank, the next entry has the starting pressure of the next tank
|
2019-07-06 12:35:33 +02:00
|
|
|
if (gasChangeIdx < plotInfo.nr - 1) {
|
|
|
|
int newGasIdx = gasChangeIdx + 1;
|
|
|
|
const struct plot_data &newGasEntry = plotInfo.entry[newGasIdx];
|
2024-06-25 07:43:32 +02:00
|
|
|
if (get_plot_sensor_pressure(&plotInfo, gasChangeIdx) == 0 || d->get_cylinder(gasChangeEntry->sensor[0])->sample_start.mbar == 0) {
|
2014-11-19 16:15:10 -08:00
|
|
|
// if we have no sensorpressure or if we have no pressure from samples we can assume that
|
|
|
|
// we only have interpolated pressure (the pressure in the entry may be stored in the sensor
|
|
|
|
// pressure field if this is the first or last entry for this tank... see details in gaspressures.c
|
|
|
|
pressure_t pressure;
|
2019-07-06 12:35:33 +02:00
|
|
|
pressure.mbar = get_plot_interpolated_pressure(&plotInfo, gasChangeIdx) ? : get_plot_sensor_pressure(&plotInfo, gasChangeIdx);
|
2017-11-18 09:35:06 +01:00
|
|
|
QAction *adjustOldPressure = m.addAction(tr("Adjust pressure of cyl. %1 (currently interpolated as %2)")
|
Start cleaning up sensor indexing for multiple sensors
This is a very timid start at making us actually use multiple sensors
without the magical special case for just CCR oxygen tracking.
It mainly does:
- turn the "sample->sensor" index into an array of two indexes, to
match the pressures themselves.
- get rid of dive->{oxygen_cylinder_index,diluent_cylinder_index},
since a CCR dive should now simply set the sample->sensor[] indices
correctly instead.
- in a couple of places, start actually looping over the sensors rather
than special-case the O2 case (although often the small "loops" are
just unrolled, since it's just two cases.
but in many cases we still end up only covering the zero sensor case,
because the CCR O2 sensor code coverage was fairly limited.
It's entirely possible (even likely) that this migth break some existing
case: it tries to be a fairly direct ("stupid") translation of the old
code, but unlike the preparatory patch this does actually does change
some semantics.
For example, right now the git loader code assumes that if the git save
data contains a o2pressure entry, it just hardcodes the O2 sensor index
to 1.
In fact, one issue is going to simply be that our file formats do not
have that multiple sensor format, but instead had very clearly encoded
things as being the CCR O2 pressure sensor.
But this is hopefully close to usable, and I will need feedback (and
maybe test cases) from people who have existing CCR dives with pressure
data.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2017-07-20 19:49:45 -07:00
|
|
|
.arg(gasChangeEntry->sensor[0] + 1).arg(get_pressure_string(pressure)));
|
2014-11-19 16:15:10 -08:00
|
|
|
}
|
2024-06-25 07:43:32 +02:00
|
|
|
if (get_plot_sensor_pressure(&plotInfo, newGasIdx) == 0 || d->get_cylinder(newGasEntry->sensor[0])->sample_start.mbar == 0) {
|
2014-11-19 16:15:10 -08:00
|
|
|
// we only have interpolated press -- see commend above
|
|
|
|
pressure_t pressure;
|
2019-07-06 12:35:33 +02:00
|
|
|
pressure.mbar = get_plot_interpolated_pressure(&plotInfo, newGasIdx) ? : get_plot_sensor_pressure(&plotInfo, newGasIdx);
|
2017-11-18 09:35:06 +01:00
|
|
|
QAction *adjustOldPressure = m.addAction(tr("Adjust pressure of cyl. %1 (currently interpolated as %2)")
|
Start cleaning up sensor indexing for multiple sensors
This is a very timid start at making us actually use multiple sensors
without the magical special case for just CCR oxygen tracking.
It mainly does:
- turn the "sample->sensor" index into an array of two indexes, to
match the pressures themselves.
- get rid of dive->{oxygen_cylinder_index,diluent_cylinder_index},
since a CCR dive should now simply set the sample->sensor[] indices
correctly instead.
- in a couple of places, start actually looping over the sensors rather
than special-case the O2 case (although often the small "loops" are
just unrolled, since it's just two cases.
but in many cases we still end up only covering the zero sensor case,
because the CCR O2 sensor code coverage was fairly limited.
It's entirely possible (even likely) that this migth break some existing
case: it tries to be a fairly direct ("stupid") translation of the old
code, but unlike the preparatory patch this does actually does change
some semantics.
For example, right now the git loader code assumes that if the git save
data contains a o2pressure entry, it just hardcodes the O2 sensor index
to 1.
In fact, one issue is going to simply be that our file formats do not
have that multiple sensor format, but instead had very clearly encoded
things as being the CCR O2 pressure sensor.
But this is hopefully close to usable, and I will need feedback (and
maybe test cases) from people who have existing CCR dives with pressure
data.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2017-07-20 19:49:45 -07:00
|
|
|
.arg(newGasEntry->sensor[0] + 1).arg(get_pressure_string(pressure)));
|
2014-11-19 16:15:10 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2014-02-17 19:15:40 -03:00
|
|
|
}
|
2024-02-19 09:04:14 +01:00
|
|
|
if (any_event_types_hidden()) {
|
|
|
|
QMenu *m2 = m.addMenu(tr("Unhide event type"));
|
|
|
|
for (int i: hidden_event_types()) {
|
|
|
|
m2->addAction(event_type_name(i), [this, i]() {
|
|
|
|
show_event_type(i);
|
|
|
|
replot();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
m2->addAction(tr("All event types"), this, &ProfileWidget2::unhideEventTypes);
|
|
|
|
}
|
2024-06-30 20:38:12 +02:00
|
|
|
const struct divecomputer *currentdc = d->get_dc(dc);
|
2024-05-25 08:16:57 +02:00
|
|
|
if (currentdc && std::any_of(currentdc->events.begin(), currentdc->events.end(),
|
|
|
|
[] (auto &ev) { return ev.hidden; }))
|
2024-02-19 09:04:14 +01:00
|
|
|
m.addAction(tr("Unhide individually hidden events of this dive"), this, &ProfileWidget2::unhideEvents);
|
2014-02-17 19:15:40 -03:00
|
|
|
m.exec(event->globalPos());
|
|
|
|
}
|
|
|
|
|
2023-07-28 01:21:25 +12:00
|
|
|
void ProfileWidget2::hideEvent(DiveEventItem *item)
|
|
|
|
{
|
2024-06-30 20:38:12 +02:00
|
|
|
if (!d)
|
|
|
|
return;
|
|
|
|
struct divecomputer *currentdc = mutable_dive()->get_dc(dc);
|
2024-05-25 08:16:57 +02:00
|
|
|
int idx = item->idx;
|
|
|
|
if (!currentdc || idx < 0 || static_cast<size_t>(idx) >= currentdc->events.size())
|
|
|
|
return;
|
|
|
|
currentdc->events[idx].hidden = true;
|
2023-07-28 01:21:25 +12:00
|
|
|
item->hide();
|
|
|
|
}
|
|
|
|
|
2024-02-19 09:04:14 +01:00
|
|
|
void ProfileWidget2::hideEventType(DiveEventItem *item)
|
2014-03-15 21:12:34 -07:00
|
|
|
{
|
2024-05-25 08:16:57 +02:00
|
|
|
if (!item->ev.name.empty()) {
|
|
|
|
hide_event_type(&item->ev);
|
2024-02-12 23:04:36 +13:00
|
|
|
|
|
|
|
replot();
|
2014-03-15 21:12:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ProfileWidget2::unhideEvents()
|
|
|
|
{
|
2024-06-30 20:38:12 +02:00
|
|
|
if (!d)
|
|
|
|
return;
|
|
|
|
struct divecomputer *currentdc = mutable_dive()->get_dc(dc);
|
2024-05-25 08:16:57 +02:00
|
|
|
if (!currentdc)
|
|
|
|
return;
|
|
|
|
for (auto &ev: currentdc->events)
|
|
|
|
ev.hidden = false;
|
|
|
|
for (DiveEventItem *item: profileScene->eventItems)
|
2014-05-14 21:51:45 -03:00
|
|
|
item->show();
|
2024-02-19 09:04:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ProfileWidget2::unhideEventTypes()
|
|
|
|
{
|
|
|
|
show_all_event_types();
|
|
|
|
|
|
|
|
replot();
|
2014-03-15 21:12:34 -07:00
|
|
|
}
|
|
|
|
|
2020-03-02 22:23:40 +01:00
|
|
|
void ProfileWidget2::removeEvent(DiveEventItem *item)
|
2014-03-15 21:12:34 -07:00
|
|
|
{
|
2024-05-25 08:16:57 +02:00
|
|
|
const struct event &ev = item->ev;
|
2015-11-05 12:58:24 -08:00
|
|
|
if (QMessageBox::question(this, TITLE_OR_TEXT(
|
|
|
|
tr("Remove the selected event?"),
|
2024-05-25 08:16:57 +02:00
|
|
|
tr("%1 @ %2:%3").arg(QString::fromStdString(ev.name)).arg(ev.time.seconds / 60).arg(ev.time.seconds % 60, 2, 10, QChar('0'))),
|
2020-03-04 18:25:47 +01:00
|
|
|
QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok)
|
2024-05-25 08:16:57 +02:00
|
|
|
Command::removeEvent(mutable_dive(), dc, item->idx);
|
2014-03-15 21:12:34 -07:00
|
|
|
}
|
|
|
|
|
2020-03-02 22:02:33 +01:00
|
|
|
void ProfileWidget2::addBookmark(int seconds)
|
2014-03-15 21:12:34 -07:00
|
|
|
{
|
2021-01-28 14:24:38 +01:00
|
|
|
if (d)
|
|
|
|
Command::addEventBookmark(mutable_dive(), dc, seconds);
|
2014-03-15 21:12:34 -07:00
|
|
|
}
|
|
|
|
|
2020-03-02 21:48:53 +01:00
|
|
|
void ProfileWidget2::addDivemodeSwitch(int seconds, int divemode)
|
2018-04-07 20:39:41 +02:00
|
|
|
{
|
2021-01-28 14:24:38 +01:00
|
|
|
if (d)
|
|
|
|
Command::addEventDivemodeSwitch(mutable_dive(), dc, seconds, divemode);
|
2018-04-07 20:39:41 +02:00
|
|
|
}
|
|
|
|
|
2020-03-02 22:02:33 +01:00
|
|
|
void ProfileWidget2::addSetpointChange(int seconds)
|
2014-11-26 14:22:41 +01:00
|
|
|
{
|
2021-01-28 14:24:38 +01:00
|
|
|
if (!d)
|
|
|
|
return;
|
|
|
|
SetpointDialog dialog(mutable_dive(), dc, seconds);
|
2020-03-03 23:09:25 +01:00
|
|
|
dialog.exec();
|
2014-11-26 14:22:41 +01:00
|
|
|
}
|
|
|
|
|
2020-03-02 22:02:33 +01:00
|
|
|
void ProfileWidget2::splitDive(int seconds)
|
2018-07-02 21:13:44 +02:00
|
|
|
{
|
2018-07-20 20:26:06 +02:00
|
|
|
if (!d)
|
|
|
|
return;
|
2024-09-01 21:48:31 +02:00
|
|
|
Command::splitDives(mutable_dive(), duration_t{ .seconds = seconds });
|
2018-07-02 21:13:44 +02:00
|
|
|
}
|
|
|
|
|
2024-05-25 19:03:39 +12:00
|
|
|
void ProfileWidget2::addGasSwitch(int tank, int seconds)
|
2014-02-17 19:15:40 -03:00
|
|
|
{
|
2024-05-28 21:31:11 +02:00
|
|
|
if (!d || tank < 0 || static_cast<size_t>(tank) >= d->cylinders.size())
|
2020-01-30 15:03:48 +01:00
|
|
|
return;
|
2015-03-11 11:23:50 -07:00
|
|
|
|
2021-01-28 14:24:38 +01:00
|
|
|
Command::addGasSwitch(mutable_dive(), dc, seconds, tank);
|
2014-02-19 17:18:26 -08:00
|
|
|
}
|
2014-03-25 23:34:09 +02:00
|
|
|
|
2024-05-25 19:03:39 +12:00
|
|
|
void ProfileWidget2::changeGas(int index, int newCylinderId)
|
|
|
|
{
|
|
|
|
if ((currentState == PLAN || currentState == EDIT) && plannerModel) {
|
|
|
|
QModelIndex modelIndex = plannerModel->index(index, DivePlannerPointsModel::GAS);
|
|
|
|
plannerModel->gasChange(modelIndex.sibling(modelIndex.row() + 1, modelIndex.column()), newCylinderId);
|
|
|
|
|
|
|
|
if (currentState == EDIT)
|
|
|
|
emit stopEdited();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-02 22:23:40 +01:00
|
|
|
void ProfileWidget2::editName(DiveEventItem *item)
|
2014-04-03 21:16:15 +02:00
|
|
|
{
|
2024-05-25 08:16:57 +02:00
|
|
|
if (!d)
|
2020-03-04 18:13:02 +01:00
|
|
|
return;
|
2014-04-03 21:16:15 +02:00
|
|
|
bool ok;
|
2015-11-05 12:58:24 -08:00
|
|
|
QString newName = QInputDialog::getText(this, tr("Edit name of bookmark"),
|
2014-04-03 21:16:15 +02:00
|
|
|
tr("Custom name:"), QLineEdit::Normal,
|
2024-05-25 08:16:57 +02:00
|
|
|
item->ev.name.c_str(), &ok);
|
2014-04-03 12:52:05 -07:00
|
|
|
if (ok && !newName.isEmpty()) {
|
|
|
|
if (newName.length() > 22) { //longer names will display as garbage.
|
2014-04-03 21:16:15 +02:00
|
|
|
QMessageBox lengthWarning;
|
2014-07-28 18:12:51 +04:00
|
|
|
lengthWarning.setText(tr("Name is too long!"));
|
2014-04-03 21:16:15 +02:00
|
|
|
lengthWarning.exec();
|
|
|
|
return;
|
|
|
|
}
|
2024-05-25 08:16:57 +02:00
|
|
|
Command::renameEvent(mutable_dive(), dc, item->idx, newName.toStdString());
|
2014-04-03 21:16:15 +02:00
|
|
|
}
|
|
|
|
}
|
2024-05-25 00:33:44 +12:00
|
|
|
|
|
|
|
void ProfileWidget2::connectPlannerModel()
|
|
|
|
{
|
|
|
|
connect(plannerModel, &DivePlannerPointsModel::dataChanged, this, &ProfileWidget2::replot);
|
|
|
|
connect(plannerModel, &DivePlannerPointsModel::cylinderModelEdited, this, &ProfileWidget2::replot);
|
|
|
|
connect(plannerModel, &DivePlannerPointsModel::modelReset, this, &ProfileWidget2::pointsReset);
|
|
|
|
connect(plannerModel, &DivePlannerPointsModel::rowsInserted, this, &ProfileWidget2::pointInserted);
|
|
|
|
connect(plannerModel, &DivePlannerPointsModel::rowsRemoved, this, &ProfileWidget2::pointsRemoved);
|
|
|
|
connect(plannerModel, &DivePlannerPointsModel::rowsMoved, this, &ProfileWidget2::pointsMoved);
|
|
|
|
}
|
2015-11-05 16:05:44 -08:00
|
|
|
#endif
|
2014-05-21 21:18:10 -03:00
|
|
|
|
2021-01-28 14:24:38 +01:00
|
|
|
void ProfileWidget2::profileChanged(dive *dive)
|
2020-03-01 17:16:08 +01:00
|
|
|
{
|
2021-01-28 14:24:38 +01:00
|
|
|
if (dive != d)
|
2020-03-01 17:16:08 +01:00
|
|
|
return; // Cylinders of a differnt dive than the shown one changed.
|
|
|
|
replot();
|
|
|
|
}
|
|
|
|
|
2018-01-10 13:55:29 +01:00
|
|
|
#endif
|
2015-11-03 21:17:50 +01:00
|
|
|
|
2021-01-28 14:24:38 +01:00
|
|
|
struct dive *ProfileWidget2::mutable_dive() const
|
|
|
|
{
|
|
|
|
return const_cast<dive *>(d);
|
|
|
|
}
|