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-06-30 19:08:16 -03:00
|
|
|
void ProfileWidget2::divePlannerHandlerClicked()
|
|
|
|
{
|
2021-07-29 17:19:50 +02:00
|
|
|
shouldCalculateMax = false;
|
2014-06-30 19:08:16 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
void ProfileWidget2::divePlannerHandlerReleased()
|
|
|
|
{
|
2022-02-19 11:58:36 +01:00
|
|
|
if (currentState == EDIT)
|
|
|
|
emit stopMoved(1);
|
2021-07-29 17:19:50 +02:00
|
|
|
shouldCalculateMax = true;
|
2014-06-30 19:08:16 -03:00
|
|
|
replot();
|
|
|
|
}
|
|
|
|
|
2016-02-06 13:25:58 -08:00
|
|
|
#endif
|
2014-05-26 17:51:46 -03:00
|
|
|
|
2016-02-06 13:25:58 -08:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
2014-05-21 15:52:24 -03:00
|
|
|
void ProfileWidget2::mouseDoubleClickEvent(QMouseEvent *event)
|
|
|
|
{
|
2021-06-30 07:49:56 +02:00
|
|
|
if ((currentState == PLAN || currentState == EDIT) && plannerModel) {
|
2014-05-21 15:52:24 -03:00
|
|
|
QPointF mappedPos = mapToScene(event->pos());
|
2021-10-26 16:37:38 +02:00
|
|
|
if (!profileScene->pointOnProfile(mappedPos))
|
2014-05-21 15:52:24 -03:00
|
|
|
return;
|
|
|
|
|
2021-06-28 20:29:46 +02:00
|
|
|
int minutes = lrint(profileScene->timeAxis->valueAt(mappedPos) / 60);
|
|
|
|
int milimeters = lrint(profileScene->profileYAxis->valueAt(mappedPos) / M_OR_FT(1, 1)) * M_OR_FT(1, 1);
|
2021-02-27 19:42:42 +01:00
|
|
|
plannerModel->addStop(milimeters, minutes * 60);
|
2022-02-19 11:58:36 +01:00
|
|
|
if (currentState == EDIT)
|
|
|
|
emit stopAdded();
|
2014-05-21 15:52:24 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2024-05-25 00:33:44 +12:00
|
|
|
disconnectPlannerModel();
|
2014-06-03 19:09:12 -03: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
|
|
|
|
2021-01-25 14:38:57 +01:00
|
|
|
connectPlannerModel();
|
|
|
|
|
2022-03-12 13:10:29 +01:00
|
|
|
currentState = EDIT;
|
2021-02-27 16:01:28 +01:00
|
|
|
|
|
|
|
pointsReset();
|
|
|
|
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
|
|
|
|
2021-01-25 14:38:57 +01:00
|
|
|
connectPlannerModel();
|
|
|
|
|
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
|
|
|
|
|
|
|
pointsReset();
|
|
|
|
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;
|
2014-05-19 14:39:34 +09:00
|
|
|
// figure out if we are ontop of the dive computer name in the profile
|
|
|
|
QGraphicsItem *sceneItem = itemAt(mapFromGlobal(event->globalPos()));
|
2021-08-03 09:51:37 +02:00
|
|
|
if (isDiveTextItem(sceneItem, profileScene->diveComputerText)) {
|
2024-06-30 20:38:12 +02:00
|
|
|
const struct divecomputer *currentdc = d->get_dc(dc);
|
2024-06-30 17:16:14 +02:00
|
|
|
if (!currentdc->deviceid && dc == 0 && d->number_of_computers() == 1)
|
2021-08-16 19:51:07 -10:00
|
|
|
// nothing to do, can't rename, delete or reorder
|
2014-05-19 14:39:34 +09:00
|
|
|
return;
|
2021-04-25 22:35:41 +02:00
|
|
|
// create menu to show when right clicking on dive computer name
|
|
|
|
if (dc > 0)
|
|
|
|
m.addAction(tr("Make first dive computer"), this, &ProfileWidget2::makeFirstDC);
|
2024-06-30 17:16:14 +02:00
|
|
|
if (d->number_of_computers() > 1) {
|
2021-04-25 22:35:41 +02:00
|
|
|
m.addAction(tr("Delete this dive computer"), this, &ProfileWidget2::deleteCurrentDC);
|
|
|
|
m.addAction(tr("Split this dive computer into own dive"), this, &ProfileWidget2::splitCurrentDC);
|
2014-05-19 14:39:34 +09:00
|
|
|
}
|
2021-08-16 19:51:07 -10:00
|
|
|
if (currentdc->deviceid)
|
|
|
|
m.addAction(tr("Rename this dive computer"), this, &ProfileWidget2::renameCurrentDC);
|
2021-04-25 22:35:41 +02:00
|
|
|
m.exec(event->globalPos());
|
|
|
|
// don't show the regular profile context menu
|
|
|
|
return;
|
2014-05-19 14:39:34 +09:00
|
|
|
}
|
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());
|
|
|
|
}
|
|
|
|
|
2014-06-11 13:56:33 -07:00
|
|
|
void ProfileWidget2::deleteCurrentDC()
|
|
|
|
{
|
2021-01-28 14:24:38 +01:00
|
|
|
if (d)
|
|
|
|
Command::deleteDiveComputer(mutable_dive(), dc);
|
2014-06-11 13:56:33 -07:00
|
|
|
}
|
|
|
|
|
2019-03-31 10:20:13 +02:00
|
|
|
void ProfileWidget2::splitCurrentDC()
|
|
|
|
{
|
2021-01-28 14:24:38 +01:00
|
|
|
if (d)
|
|
|
|
Command::splitDiveComputer(mutable_dive(), dc);
|
2019-03-31 10:20:13 +02:00
|
|
|
}
|
|
|
|
|
2014-05-19 14:39:34 +09:00
|
|
|
void ProfileWidget2::makeFirstDC()
|
|
|
|
{
|
2021-01-28 14:24:38 +01:00
|
|
|
if (d)
|
|
|
|
Command::moveDiveComputerToFront(mutable_dive(), dc);
|
2014-05-19 14:39:34 +09:00
|
|
|
}
|
|
|
|
|
2021-08-16 19:51:07 -10:00
|
|
|
void ProfileWidget2::renameCurrentDC()
|
|
|
|
{
|
2024-06-30 20:38:12 +02:00
|
|
|
if (!d)
|
2022-03-11 22:49:53 +01:00
|
|
|
return;
|
2024-06-30 20:38:12 +02:00
|
|
|
bool ok;
|
|
|
|
struct divecomputer *currentdc = mutable_dive()->get_dc(dc);
|
2021-08-17 00:10:33 -07:00
|
|
|
QString newName = QInputDialog::getText(this, tr("Edit nickname"),
|
2024-05-18 17:03:19 +02:00
|
|
|
tr("Set new nickname for %1 (serial %2):").arg(QString::fromStdString(currentdc->model)).
|
|
|
|
arg(QString::fromStdString(currentdc->serial)),
|
|
|
|
QLineEdit::Normal, QString::fromStdString(get_dc_nickname(currentdc)), &ok);
|
2021-08-17 11:19:41 -07:00
|
|
|
if (ok)
|
2022-03-11 22:49:53 +01:00
|
|
|
Command::editDeviceNickname(currentdc, newName);
|
2021-08-16 19:51:07 -10:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2024-05-25 00:33:44 +12:00
|
|
|
void ProfileWidget2::disconnectPlannerModel()
|
2014-05-21 21:23:19 -03:00
|
|
|
{
|
2018-01-09 19:32:41 +01:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
2021-01-25 15:06:53 +01:00
|
|
|
if (plannerModel) {
|
|
|
|
disconnect(plannerModel, &DivePlannerPointsModel::dataChanged, this, &ProfileWidget2::replot);
|
|
|
|
disconnect(plannerModel, &DivePlannerPointsModel::cylinderModelEdited, this, &ProfileWidget2::replot);
|
|
|
|
|
|
|
|
disconnect(plannerModel, &DivePlannerPointsModel::modelReset, this, &ProfileWidget2::pointsReset);
|
|
|
|
disconnect(plannerModel, &DivePlannerPointsModel::rowsInserted, this, &ProfileWidget2::pointInserted);
|
|
|
|
disconnect(plannerModel, &DivePlannerPointsModel::rowsRemoved, this, &ProfileWidget2::pointsRemoved);
|
|
|
|
disconnect(plannerModel, &DivePlannerPointsModel::rowsMoved, this, &ProfileWidget2::pointsMoved);
|
|
|
|
}
|
2015-11-12 01:37:18 +01:00
|
|
|
#endif
|
2014-05-21 21:23:19 -03:00
|
|
|
}
|
|
|
|
|
2021-01-24 09:13:56 +01:00
|
|
|
int ProfileWidget2::handleIndex(const DiveHandler *h) const
|
|
|
|
{
|
|
|
|
auto it = std::find_if(handles.begin(), handles.end(),
|
|
|
|
[h] (const std::unique_ptr<DiveHandler> &h2)
|
|
|
|
{ return h == h2.get(); });
|
|
|
|
return it != handles.end() ? it - handles.begin() : -1;
|
|
|
|
}
|
|
|
|
|
2015-11-05 16:05:44 -08:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
2021-01-24 23:29:28 +01:00
|
|
|
|
|
|
|
DiveHandler *ProfileWidget2::createHandle()
|
2014-05-21 21:18:10 -03:00
|
|
|
{
|
2024-05-15 17:23:39 +12:00
|
|
|
DiveHandler *item = new DiveHandler(d, dc);
|
2014-05-21 21:18:10 -03:00
|
|
|
scene()->addItem(item);
|
2021-01-25 15:51:37 +01:00
|
|
|
connect(item, &DiveHandler::moved, this, &ProfileWidget2::divePlannerHandlerMoved);
|
2020-04-12 12:48:38 +02:00
|
|
|
connect(item, &DiveHandler::clicked, this, &ProfileWidget2::divePlannerHandlerClicked);
|
|
|
|
connect(item, &DiveHandler::released, this, &ProfileWidget2::divePlannerHandlerReleased);
|
2021-01-24 23:29:28 +01:00
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
QGraphicsSimpleTextItem *ProfileWidget2::createGas()
|
|
|
|
{
|
2014-05-21 21:18:10 -03:00
|
|
|
QGraphicsSimpleTextItem *gasChooseBtn = new QGraphicsSimpleTextItem();
|
|
|
|
scene()->addItem(gasChooseBtn);
|
|
|
|
gasChooseBtn->setZValue(10);
|
|
|
|
gasChooseBtn->setFlag(QGraphicsItem::ItemIgnoresTransformations);
|
2021-01-24 23:29:28 +01:00
|
|
|
return gasChooseBtn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ProfileWidget2::pointsReset()
|
|
|
|
{
|
|
|
|
handles.clear();
|
|
|
|
gases.clear();
|
2021-01-25 15:06:53 +01:00
|
|
|
int count = plannerModel->rowCount();
|
2021-01-24 23:29:28 +01:00
|
|
|
for (int i = 0; i < count; ++i) {
|
|
|
|
handles.emplace_back(createHandle());
|
|
|
|
gases.emplace_back(createGas());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ProfileWidget2::pointInserted(const QModelIndex &, int from, int to)
|
|
|
|
{
|
|
|
|
for (int i = from; i <= to; ++i) {
|
|
|
|
handles.emplace(handles.begin() + i, createHandle());
|
|
|
|
gases.emplace(gases.begin() + i, createGas());
|
|
|
|
}
|
|
|
|
|
2021-02-27 22:06:05 +01:00
|
|
|
// Note: we don't replot the dive here, because when removing multiple
|
|
|
|
// points, these might trickle in one-by-one. Instead, the model will
|
|
|
|
// emit a data-changed signal.
|
2014-05-21 21:18:10 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
void ProfileWidget2::pointsRemoved(const QModelIndex &, int start, int end)
|
2021-01-24 09:13:56 +01:00
|
|
|
{
|
|
|
|
// Qt's model/view API is mad. The end-point is inclusive, which means that the empty range is [0,-1]!
|
|
|
|
handles.erase(handles.begin() + start, handles.begin() + end + 1);
|
|
|
|
gases.erase(gases.begin() + start, gases.begin() + end + 1);
|
2014-05-21 21:18:10 -03:00
|
|
|
scene()->clearSelection();
|
2021-02-27 22:06:05 +01:00
|
|
|
|
|
|
|
// Note: we don't replot the dive here, because when removing multiple
|
|
|
|
// points, these might trickle in one-by-one. Instead, the model will
|
|
|
|
// emit a data-changed signal.
|
2014-05-21 21:18:10 -03:00
|
|
|
}
|
2014-05-21 23:31:26 -03:00
|
|
|
|
2021-01-24 23:29:28 +01:00
|
|
|
void ProfileWidget2::pointsMoved(const QModelIndex &, int start, int end, const QModelIndex &, int row)
|
|
|
|
{
|
2022-09-24 14:06:56 +02:00
|
|
|
move_in_range(handles, start, end + 1, row);
|
|
|
|
move_in_range(gases, start, end + 1, row);
|
2021-01-24 23:29:28 +01:00
|
|
|
}
|
|
|
|
|
2014-05-21 23:31:26 -03:00
|
|
|
void ProfileWidget2::repositionDiveHandlers()
|
|
|
|
{
|
2018-01-10 16:36:45 +01:00
|
|
|
hideAll(gases);
|
2014-05-21 23:31:26 -03:00
|
|
|
// Re-position the user generated dive handlers
|
|
|
|
for (int i = 0; i < plannerModel->rowCount(); i++) {
|
|
|
|
struct divedatapoint datapoint = plannerModel->at(i);
|
|
|
|
if (datapoint.time == 0) // those are the magic entries for tanks
|
|
|
|
continue;
|
2021-01-24 09:13:56 +01:00
|
|
|
DiveHandler *h = handles[i].get();
|
2014-05-29 23:47:03 -03:00
|
|
|
h->setVisible(datapoint.entered);
|
2021-06-28 20:29:46 +02:00
|
|
|
h->setPos(profileScene->timeAxis->posAtValue(datapoint.time), profileScene->profileYAxis->posAtValue(datapoint.depth.mm));
|
2014-10-21 14:27:50 -07:00
|
|
|
QPointF p1;
|
|
|
|
if (i == 0) {
|
|
|
|
if (prefs.drop_stone_mode)
|
|
|
|
// place the text on the straight line from the drop to stone position
|
2021-06-28 20:29:46 +02:00
|
|
|
p1 = QPointF(profileScene->timeAxis->posAtValue(datapoint.depth.mm / prefs.descrate),
|
|
|
|
profileScene->profileYAxis->posAtValue(datapoint.depth.mm));
|
2014-10-21 14:27:50 -07:00
|
|
|
else
|
|
|
|
// place the text on the straight line from the origin to the first position
|
2021-06-28 20:29:46 +02:00
|
|
|
p1 = QPointF(profileScene->timeAxis->posAtValue(0), profileScene->profileYAxis->posAtValue(0));
|
2014-10-21 14:27:50 -07:00
|
|
|
} else {
|
|
|
|
// place the text on the line from the last position
|
|
|
|
p1 = handles[i - 1]->pos();
|
|
|
|
}
|
2014-05-21 23:31:26 -03:00
|
|
|
QPointF p2 = handles[i]->pos();
|
|
|
|
QLineF line(p1, p2);
|
|
|
|
QPointF pos = line.pointAt(0.5);
|
|
|
|
gases[i]->setPos(pos);
|
2024-05-28 21:31:11 +02:00
|
|
|
if (datapoint.cylinderid >= 0 && datapoint.cylinderid < static_cast<int>(d->cylinders.size()))
|
2024-06-25 07:43:32 +02:00
|
|
|
gases[i]->setText(get_gas_string(d->get_cylinder(datapoint.cylinderid)->gasmix));
|
2021-01-25 21:45:29 +01:00
|
|
|
else
|
|
|
|
gases[i]->setText(QString());
|
2015-05-07 23:40:34 +02:00
|
|
|
gases[i]->setVisible(datapoint.entered &&
|
|
|
|
(i == 0 || gases[i]->text() != gases[i-1]->text()));
|
2014-05-21 23:31:26 -03:00
|
|
|
}
|
|
|
|
}
|
2014-05-23 20:51:30 -03:00
|
|
|
|
2021-01-25 15:51:37 +01:00
|
|
|
void ProfileWidget2::divePlannerHandlerMoved()
|
2014-05-23 20:51:30 -03:00
|
|
|
{
|
2014-05-24 12:39:40 -03:00
|
|
|
DiveHandler *activeHandler = qobject_cast<DiveHandler *>(sender());
|
2021-01-25 15:51:37 +01:00
|
|
|
int index = handleIndex(activeHandler);
|
2014-05-23 20:51:30 -03:00
|
|
|
|
2021-01-25 15:51:37 +01:00
|
|
|
// Grow the time axis if necessary.
|
2021-06-28 20:29:46 +02:00
|
|
|
int minutes = lrint(profileScene->timeAxis->valueAt(activeHandler->pos()) / 60);
|
|
|
|
if (minutes * 60 > profileScene->timeAxis->maximum() * 0.9)
|
2021-09-11 21:57:49 +02:00
|
|
|
profileScene->timeAxis->setBounds(0.0, profileScene->timeAxis->maximum() * 1.02);
|
2014-05-23 20:51:30 -03:00
|
|
|
|
|
|
|
divedatapoint data = plannerModel->at(index);
|
2021-06-28 20:29:46 +02:00
|
|
|
data.depth.mm = lrint(profileScene->profileYAxis->valueAt(activeHandler->pos()) / M_OR_FT(1, 1)) * M_OR_FT(1, 1);
|
|
|
|
data.time = lrint(profileScene->timeAxis->valueAt(activeHandler->pos()));
|
2014-05-23 20:51:30 -03:00
|
|
|
|
2021-01-25 15:51:37 +01:00
|
|
|
plannerModel->editStop(index, data);
|
2014-05-23 20:51:30 -03:00
|
|
|
}
|
2014-05-24 12:39:40 -03:00
|
|
|
|
2022-02-19 11:58:36 +01:00
|
|
|
std::vector<int> ProfileWidget2::selectedDiveHandleIndices() const
|
|
|
|
{
|
|
|
|
std::vector<int> res;
|
|
|
|
res.reserve(scene()->selectedItems().size());
|
|
|
|
for (QGraphicsItem *item: scene()->selectedItems()) {
|
|
|
|
if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(item))
|
|
|
|
res.push_back(handleIndex(handler));
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-05-24 12:39:40 -03:00
|
|
|
void ProfileWidget2::keyDownAction()
|
|
|
|
{
|
2021-06-30 07:49:56 +02:00
|
|
|
if ((currentState != EDIT && currentState != PLAN) || !plannerModel)
|
2014-05-24 12:39:40 -03:00
|
|
|
return;
|
|
|
|
|
2022-02-19 11:58:36 +01:00
|
|
|
std::vector<int> handleIndices = selectedDiveHandleIndices();
|
|
|
|
for (int row: handleIndices) {
|
|
|
|
divedatapoint dp = plannerModel->at(row);
|
2014-05-24 12:39:40 -03:00
|
|
|
|
2022-02-19 11:58:36 +01:00
|
|
|
dp.depth.mm += M_OR_FT(1, 5);
|
|
|
|
plannerModel->editStop(row, dp);
|
2014-05-24 12:39:40 -03:00
|
|
|
}
|
2022-02-19 11:58:36 +01:00
|
|
|
if (currentState == EDIT && !handleIndices.empty())
|
|
|
|
emit stopMoved(handleIndices.size()); // TODO: Accumulate key moves
|
2014-05-24 12:39:40 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
void ProfileWidget2::keyUpAction()
|
|
|
|
{
|
2021-06-30 07:49:56 +02:00
|
|
|
if ((currentState != EDIT && currentState != PLAN) || !plannerModel)
|
2014-05-24 12:39:40 -03:00
|
|
|
return;
|
|
|
|
|
2022-02-19 11:58:36 +01:00
|
|
|
std::vector<int> handleIndices = selectedDiveHandleIndices();
|
|
|
|
for (int row: handleIndices) {
|
|
|
|
divedatapoint dp = plannerModel->at(row);
|
2014-05-24 12:39:40 -03:00
|
|
|
|
2022-02-19 11:58:36 +01:00
|
|
|
if (dp.depth.mm <= 0)
|
|
|
|
continue;
|
2014-05-24 12:39:40 -03:00
|
|
|
|
2022-02-19 11:58:36 +01:00
|
|
|
dp.depth.mm -= M_OR_FT(1, 5);
|
|
|
|
plannerModel->editStop(row, dp);
|
2014-05-24 12:39:40 -03:00
|
|
|
}
|
2022-02-19 11:58:36 +01:00
|
|
|
if (currentState == EDIT && !handleIndices.empty())
|
|
|
|
emit stopMoved(handleIndices.size()); // TODO: Accumulate key moves
|
2014-05-24 12:39:40 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
void ProfileWidget2::keyLeftAction()
|
|
|
|
{
|
2021-06-30 07:49:56 +02:00
|
|
|
if ((currentState != EDIT && currentState != PLAN) || !plannerModel)
|
2014-05-24 12:39:40 -03:00
|
|
|
return;
|
|
|
|
|
2022-02-19 11:58:36 +01:00
|
|
|
std::vector<int> handleIndices = selectedDiveHandleIndices();
|
|
|
|
for (int row: handleIndices) {
|
|
|
|
divedatapoint dp = plannerModel->at(row);
|
2014-05-24 12:39:40 -03:00
|
|
|
|
2022-02-19 11:58:36 +01:00
|
|
|
if (dp.time / 60 <= 0)
|
|
|
|
continue;
|
2014-05-24 12:39:40 -03:00
|
|
|
|
2022-02-19 11:58:36 +01:00
|
|
|
dp.time -= 60;
|
|
|
|
plannerModel->editStop(row, dp);
|
2014-05-24 12:39:40 -03:00
|
|
|
}
|
2022-02-19 11:58:36 +01:00
|
|
|
if (currentState == EDIT && !handleIndices.empty())
|
|
|
|
emit stopMoved(handleIndices.size()); // TODO: Accumulate key moves
|
2014-05-24 12:39:40 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
void ProfileWidget2::keyRightAction()
|
|
|
|
{
|
2021-06-30 07:49:56 +02:00
|
|
|
if ((currentState != EDIT && currentState != PLAN) || !plannerModel)
|
2014-05-24 12:39:40 -03:00
|
|
|
return;
|
|
|
|
|
2022-02-19 11:58:36 +01:00
|
|
|
std::vector<int> handleIndices = selectedDiveHandleIndices();
|
|
|
|
for (int row: handleIndices) {
|
|
|
|
divedatapoint dp = plannerModel->at(row);
|
2014-05-24 12:39:40 -03:00
|
|
|
|
2022-02-19 11:58:36 +01:00
|
|
|
dp.time += 60;
|
|
|
|
plannerModel->editStop(row, dp);
|
2014-05-24 12:39:40 -03:00
|
|
|
}
|
2022-02-19 11:58:36 +01:00
|
|
|
if (currentState == EDIT && !handleIndices.empty())
|
|
|
|
emit stopMoved(handleIndices.size()); // TODO: Accumulate key moves
|
2014-05-24 12:39:40 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
void ProfileWidget2::keyDeleteAction()
|
|
|
|
{
|
2021-06-30 07:49:56 +02:00
|
|
|
if ((currentState != EDIT && currentState != PLAN) || !plannerModel)
|
2014-05-24 12:39:40 -03:00
|
|
|
return;
|
|
|
|
|
2022-02-19 11:58:36 +01:00
|
|
|
std::vector<int> handleIndices = selectedDiveHandleIndices();
|
|
|
|
// For now, we have to convert to QVector.
|
|
|
|
for (int index: handleIndices)
|
|
|
|
handles[index]->hide();
|
|
|
|
if (!handleIndices.empty()) {
|
|
|
|
plannerModel->removeSelectedPoints(handleIndices);
|
|
|
|
if (currentState == EDIT)
|
|
|
|
emit stopRemoved(handleIndices.size());
|
2014-05-24 12:39:40 -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);
|
|
|
|
}
|