mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
profile: display arbitrary dive
So far the profile operated on the global displayed_dive. Instead, take the dive to be displayed as a parameter to the plotDive() functions. This is necessary if we want to have multiple concurrent profile objects. Think for example for printing or for mobile where multiple dive objects are active at the same time. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
36f0ba9abe
commit
2789bb05b1
9 changed files with 121 additions and 131 deletions
desktop-widgets
profile-widget
qt-models
|
@ -229,7 +229,7 @@ void exportProfile(const struct dive *dive, const QString filename)
|
|||
profile->setPrintMode(true);
|
||||
double scale = profile->getFontPrintScale();
|
||||
profile->setFontPrintScale(4 * scale);
|
||||
profile->plotDive(dive, true, false, true);
|
||||
profile->plotDive(dive, 0, true, false, true);
|
||||
QImage image = QImage(profile->size() * 4, QImage::Format_RGB32);
|
||||
QPainter paint;
|
||||
paint.begin(&image);
|
||||
|
@ -238,5 +238,5 @@ void exportProfile(const struct dive *dive, const QString filename)
|
|||
profile->setToolTipVisibile(true);
|
||||
profile->setFontPrintScale(scale);
|
||||
profile->setPrintMode(false);
|
||||
profile->plotDive(dive, true);
|
||||
profile->plotDive(dive, 0, true); // TODO: Shouldn't this plot the current dive?
|
||||
}
|
||||
|
|
|
@ -541,7 +541,7 @@ void PlannerWidgets::planDive()
|
|||
{
|
||||
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::PLAN);
|
||||
|
||||
MainWindow::instance()->graphics->setPlanState();
|
||||
MainWindow::instance()->graphics->setPlanState(&displayed_dive, 0);
|
||||
dc_number = 0;
|
||||
|
||||
// create a simple starting dive, using the first gas from the just copied cylinders
|
||||
|
@ -569,7 +569,7 @@ void PlannerWidgets::replanDive()
|
|||
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::PLAN);
|
||||
DivePlannerPointsModel::instance()->loadFromDive(&displayed_dive);
|
||||
|
||||
MainWindow::instance()->graphics->setPlanState();
|
||||
MainWindow::instance()->graphics->setPlanState(&displayed_dive, 0);
|
||||
|
||||
plannerWidget.setReplanButton(true);
|
||||
plannerWidget.setupStartTime(timestampToDateTime(displayed_dive.when));
|
||||
|
|
|
@ -434,7 +434,7 @@ void MainWindow::selectionChanged()
|
|||
configureToolbar();
|
||||
enableDisableOtherDCsActions();
|
||||
}
|
||||
graphics->plotDive(current_dive, false);
|
||||
graphics->plotDive(current_dive, dc_number, false);
|
||||
MapWidget::instance()->selectionChanged();
|
||||
}
|
||||
|
||||
|
@ -685,7 +685,7 @@ void MainWindow::enableShortcuts()
|
|||
void MainWindow::showProfile()
|
||||
{
|
||||
enableShortcuts();
|
||||
graphics->setProfileState();
|
||||
graphics->setProfileState(current_dive, dc_number);
|
||||
setApplicationState(ApplicationState::Default);
|
||||
}
|
||||
|
||||
|
@ -738,7 +738,7 @@ void MainWindow::refreshProfile()
|
|||
{
|
||||
showProfile();
|
||||
configureToolbar();
|
||||
graphics->plotDive(current_dive, true);
|
||||
graphics->plotDive(current_dive, dc_number, true);
|
||||
}
|
||||
|
||||
void MainWindow::planCanceled()
|
||||
|
@ -919,7 +919,7 @@ void MainWindow::on_actionPreviousDC_triggered()
|
|||
unsigned nrdc = number_of_computers(current_dive);
|
||||
dc_number = (dc_number + nrdc - 1) % nrdc;
|
||||
configureToolbar();
|
||||
graphics->plotDive(current_dive, false);
|
||||
graphics->plotDive(current_dive, dc_number, false);
|
||||
mainTab->updateDiveInfo();
|
||||
}
|
||||
|
||||
|
@ -928,7 +928,7 @@ void MainWindow::on_actionNextDC_triggered()
|
|||
unsigned nrdc = number_of_computers(current_dive);
|
||||
dc_number = (dc_number + 1) % nrdc;
|
||||
configureToolbar();
|
||||
graphics->plotDive(current_dive, false);
|
||||
graphics->plotDive(current_dive, dc_number, false);
|
||||
mainTab->updateDiveInfo();
|
||||
}
|
||||
|
||||
|
@ -1516,7 +1516,7 @@ void MainWindow::editCurrentDive()
|
|||
disableShortcuts();
|
||||
copy_dive(current_dive, &displayed_dive); // Work on a copy of the dive
|
||||
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::ADD);
|
||||
graphics->setAddState();
|
||||
graphics->setAddState(&displayed_dive, 0);
|
||||
setApplicationState(ApplicationState::EditDive);
|
||||
DivePlannerPointsModel::instance()->loadFromDive(&displayed_dive);
|
||||
mainTab->enableEdition();
|
||||
|
|
|
@ -38,7 +38,7 @@ void Printer::putProfileImage(const QRect &profilePlaceholder, const QRect &view
|
|||
int y = profilePlaceholder.y() - viewPort.y();
|
||||
// use the placeHolder and the viewPort position to calculate the relative position of the dive profile.
|
||||
QRect pos(x, y, profilePlaceholder.width(), profilePlaceholder.height());
|
||||
profile->plotDive(dive, true, true);
|
||||
profile->plotDive(dive, 0, true, true);
|
||||
|
||||
if (!printOptions.color_selected) {
|
||||
QImage image(pos.width(), pos.height(), QImage::Format_ARGB32);
|
||||
|
@ -193,7 +193,7 @@ void Printer::render(int pages)
|
|||
qPrefDisplay::set_animation_speed(animationOriginal);
|
||||
|
||||
//replot the dive after returning the settings
|
||||
profile->plotDive(current_dive, true, true);
|
||||
profile->plotDive(current_dive, dc_number, true, true);
|
||||
}
|
||||
|
||||
//value: ranges from 0 : 100 and shows the progress of the templating engine
|
||||
|
|
|
@ -541,11 +541,6 @@ void MainTab::rejectChanges()
|
|||
// no harm done to call cancelPlan even if we were not PLAN mode...
|
||||
DivePlannerPointsModel::instance()->cancelPlan();
|
||||
|
||||
// now make sure that the correct dive is displayed
|
||||
if (current_dive)
|
||||
copy_dive(current_dive, &displayed_dive);
|
||||
else
|
||||
clear_dive(&displayed_dive);
|
||||
updateDiveInfo();
|
||||
|
||||
// show the profile and dive info
|
||||
|
|
|
@ -360,7 +360,7 @@ void ProfileWidget2::setupItemOnScene()
|
|||
|
||||
void ProfileWidget2::replot()
|
||||
{
|
||||
plotDive(current_dive, true, false);
|
||||
plotDive(d, dc, true, false);
|
||||
}
|
||||
|
||||
PartialPressureGasItem *ProfileWidget2::createPPGas(int column, color_index_t color, color_index_t colorAlert,
|
||||
|
@ -521,29 +521,21 @@ void ProfileWidget2::resetZoom()
|
|||
}
|
||||
|
||||
// Currently just one dive, but the plan is to enable All of the selected dives.
|
||||
void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPictures, bool instant)
|
||||
void ProfileWidget2::plotDive(const struct dive *dIn, int dcIn, bool force, bool doClearPictures, bool instant)
|
||||
{
|
||||
d = dIn;
|
||||
dc = dcIn;
|
||||
if (!d) {
|
||||
setEmptyState();
|
||||
return;
|
||||
}
|
||||
|
||||
QElapsedTimer measureDuration; // let's measure how long this takes us (maybe we'll turn of TTL calculation later
|
||||
measureDuration.start();
|
||||
#ifdef SUBSURFACE_MOBILE
|
||||
Q_UNUSED(doClearPictures);
|
||||
#endif
|
||||
if ((currentState != ADD && currentState != PLAN) || !plannerModel) {
|
||||
if (!d) {
|
||||
setEmptyState();
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to do this again if we are already showing the same dive
|
||||
// computer of the same dive, so we check the unique id of the dive
|
||||
// and the selected dive computer number against the ones we are
|
||||
// showing (can't compare the dive pointers as those might change).
|
||||
if (d->id == displayed_dive.id && dc_number == dataModel->dcShown() && !force)
|
||||
return;
|
||||
|
||||
// this copies the dive and makes copies of all the relevant additional data
|
||||
copy_dive(d, &displayed_dive);
|
||||
|
||||
if (decoMode(false) == VPMB)
|
||||
decoModelParameters->setText(QString("VPM-B +%1").arg(prefs.vpmb_conservatism));
|
||||
else
|
||||
|
@ -563,7 +555,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
|
|||
#endif
|
||||
}
|
||||
|
||||
struct divecomputer *currentdc = select_dc(&displayed_dive);
|
||||
const struct divecomputer *currentdc = get_dive_dc_const(d, dc);
|
||||
if (!currentdc || !currentdc->samples)
|
||||
return setEmptyState();
|
||||
|
||||
|
@ -581,7 +573,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
|
|||
if (currentState == EMPTY)
|
||||
setProfileState();
|
||||
|
||||
bool setpointflag = (currentdc->divemode == CCR) && prefs.pp_graphs.po2 && current_dive;
|
||||
bool setpointflag = (currentdc->divemode == CCR) && prefs.pp_graphs.po2;
|
||||
bool sensorflag = setpointflag && prefs.show_ccr_sensors;
|
||||
o2SetpointGasItem->setVisible(setpointflag && prefs.show_ccr_setpoint);
|
||||
ccrsensor1GasItem->setVisible(sensorflag);
|
||||
|
@ -602,9 +594,9 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
|
|||
#ifndef SUBSURFACE_MOBILE
|
||||
// A non-null planner_ds signals to create_plot_info_new that the dive is currently planned.
|
||||
struct deco_state *planner_ds = currentState == PLAN && plannerModel ? &plannerModel->final_deco_state : nullptr;
|
||||
create_plot_info_new(&displayed_dive, currentdc, &plotInfo, !shouldCalculateMaxDepth, planner_ds);
|
||||
create_plot_info_new(d, get_dive_dc_const(d, dc), &plotInfo, !shouldCalculateMaxDepth, planner_ds);
|
||||
#else
|
||||
create_plot_info_new(&displayed_dive, currentdc, &plotInfo, !shouldCalculateMaxDepth, nullptr);
|
||||
create_plot_info_new(d, get_dive_dc_const(d, dc), &plotInfo, !shouldCalculateMaxDepth, nullptr);
|
||||
#endif
|
||||
int newMaxtime = get_maxtime(&plotInfo);
|
||||
if (shouldCalculateMaxTime || newMaxtime > maxtime)
|
||||
|
@ -682,7 +674,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
|
|||
cylinderPressureAxis->setMinimum(plotInfo.minpressure);
|
||||
cylinderPressureAxis->setMaximum(plotInfo.maxpressure);
|
||||
#ifndef SUBSURFACE_MOBILE
|
||||
rulerItem->setPlotInfo(&displayed_dive, plotInfo);
|
||||
rulerItem->setPlotInfo(d, plotInfo);
|
||||
#endif
|
||||
|
||||
#ifdef SUBSURFACE_MOBILE
|
||||
|
@ -722,13 +714,13 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
|
|||
ocpo2GasItem->setVisible(false);
|
||||
}
|
||||
#endif
|
||||
tankItem->setData(&plotInfo, &displayed_dive);
|
||||
tankItem->setData(&plotInfo, d);
|
||||
|
||||
gasYAxis->update();
|
||||
|
||||
// Replot dive items
|
||||
for (AbstractProfilePolygonItem *item: profileItems)
|
||||
item->replot(&displayed_dive, currentState == PLAN);
|
||||
item->replot(d, currentState == PLAN);
|
||||
|
||||
// The event items are a bit special since we don't know how many events are going to
|
||||
// exist on a dive, so I cant create cache items for that. that's why they are here
|
||||
|
@ -736,7 +728,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
|
|||
qDeleteAll(eventItems);
|
||||
eventItems.clear();
|
||||
struct event *event = currentdc->events;
|
||||
struct gasmix lastgasmix = get_gasmix_at_time(&displayed_dive, current_dc, duration_t{1});
|
||||
struct gasmix lastgasmix = get_gasmix_at_time(d, get_dive_dc_const(d, dc), duration_t{1});
|
||||
|
||||
while (event) {
|
||||
#ifndef SUBSURFACE_MOBILE
|
||||
|
@ -759,7 +751,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
|
|||
item->setHorizontalAxis(timeAxis);
|
||||
item->setVerticalAxis(profileYAxis, qPrefDisplay::animation_speed());
|
||||
item->setModel(dataModel);
|
||||
item->setEvent(&displayed_dive, event, lastgasmix);
|
||||
item->setEvent(d, event, lastgasmix);
|
||||
item->setZValue(2);
|
||||
#ifndef SUBSURFACE_MOBILE
|
||||
item->setScale(printMode ? 4 :1);
|
||||
|
@ -767,7 +759,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
|
|||
scene()->addItem(item);
|
||||
eventItems.push_back(item);
|
||||
if (event_is_gaschange(event))
|
||||
lastgasmix = get_gasmix_from_event(&displayed_dive, event);
|
||||
lastgasmix = get_gasmix_from_event(d, event);
|
||||
event = event->next;
|
||||
}
|
||||
|
||||
|
@ -784,8 +776,8 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
|
|||
dcText = tr("Unknown dive computer");
|
||||
#ifndef SUBSURFACE_MOBILE
|
||||
int nr;
|
||||
if ((nr = number_of_computers(&displayed_dive)) > 1)
|
||||
dcText += tr(" (#%1 of %2)").arg(dc_number + 1).arg(nr);
|
||||
if ((nr = number_of_computers(d)) > 1)
|
||||
dcText += tr(" (#%1 of %2)").arg(dc + 1).arg(nr);
|
||||
#endif
|
||||
diveComputerText->setText(dcText);
|
||||
|
||||
|
@ -799,7 +791,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
|
|||
else
|
||||
plotPicturesInternal(d, instant);
|
||||
|
||||
toolTipItem->refresh(&displayed_dive, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN);
|
||||
toolTipItem->refresh(d, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN);
|
||||
#endif
|
||||
|
||||
// OK, how long did this take us? Anything above the second is way too long,
|
||||
|
@ -1025,7 +1017,7 @@ void ProfileWidget2::scrollViewTo(const QPoint &pos)
|
|||
void ProfileWidget2::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
QPointF pos = mapToScene(event->pos());
|
||||
toolTipItem->refresh(&displayed_dive, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN);
|
||||
toolTipItem->refresh(d, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN);
|
||||
|
||||
if (zoomLevel == 0) {
|
||||
QGraphicsView::mouseMoveEvent(event);
|
||||
|
@ -1123,6 +1115,14 @@ void ProfileWidget2::setEmptyState()
|
|||
hideAll(gases);
|
||||
}
|
||||
|
||||
void ProfileWidget2::setProfileState(const dive *dIn, int dcIn)
|
||||
{
|
||||
d = dIn;
|
||||
dc = dcIn;
|
||||
|
||||
setProfileState();
|
||||
}
|
||||
|
||||
void ProfileWidget2::setProfileState()
|
||||
{
|
||||
// Then starting Empty State, move the background up.
|
||||
|
@ -1207,13 +1207,14 @@ void ProfileWidget2::setProfileState()
|
|||
po2GasItem->setVisible(prefs.pp_graphs.po2);
|
||||
pheGasItem->setVisible(prefs.pp_graphs.phe);
|
||||
|
||||
bool setpointflag = current_dive && (current_dc->divemode == CCR) && prefs.pp_graphs.po2;
|
||||
const struct divecomputer *currentdc = d ? get_dive_dc_const(d, dc) : nullptr;
|
||||
bool setpointflag = currentdc && currentdc->divemode == CCR && prefs.pp_graphs.po2;
|
||||
bool sensorflag = setpointflag && prefs.show_ccr_sensors;
|
||||
o2SetpointGasItem->setVisible(setpointflag && prefs.show_ccr_setpoint);
|
||||
ccrsensor1GasItem->setVisible(sensorflag);
|
||||
ccrsensor2GasItem->setVisible(sensorflag && (current_dc->no_o2sensors > 1));
|
||||
ccrsensor3GasItem->setVisible(sensorflag && (current_dc->no_o2sensors > 2));
|
||||
ocpo2GasItem->setVisible(current_dive && (current_dc->divemode == PSCR) && prefs.show_scr_ocpo2);
|
||||
ccrsensor2GasItem->setVisible(currentdc && sensorflag && currentdc->no_o2sensors > 1);
|
||||
ccrsensor3GasItem->setVisible(currentdc && sensorflag && currentdc->no_o2sensors > 2);
|
||||
ocpo2GasItem->setVisible(currentdc && currentdc->divemode == PSCR && prefs.show_scr_ocpo2);
|
||||
|
||||
heartBeatItem->setVisible(prefs.hrgraph);
|
||||
#endif
|
||||
|
@ -1272,12 +1273,12 @@ void ProfileWidget2::connectPlannerModel()
|
|||
connect(plannerModel, &DivePlannerPointsModel::rowsMoved, this, &ProfileWidget2::pointsMoved);
|
||||
}
|
||||
|
||||
void ProfileWidget2::setAddState()
|
||||
void ProfileWidget2::setAddState(const dive *d, int dc)
|
||||
{
|
||||
if (currentState == ADD)
|
||||
return;
|
||||
|
||||
setProfileState();
|
||||
setProfileState(d, dc);
|
||||
mouseFollowerHorizontal->setVisible(true);
|
||||
mouseFollowerVertical->setVisible(true);
|
||||
mouseFollowerHorizontal->setLine(timeAxis->line());
|
||||
|
@ -1300,12 +1301,12 @@ void ProfileWidget2::setAddState()
|
|||
setBackgroundBrush(QColor("#A7DCFF"));
|
||||
}
|
||||
|
||||
void ProfileWidget2::setPlanState()
|
||||
void ProfileWidget2::setPlanState(const dive *d, int dc)
|
||||
{
|
||||
if (currentState == PLAN)
|
||||
return;
|
||||
|
||||
setProfileState();
|
||||
setProfileState(d, dc);
|
||||
mouseFollowerHorizontal->setVisible(true);
|
||||
mouseFollowerVertical->setVisible(true);
|
||||
mouseFollowerHorizontal->setLine(timeAxis->line());
|
||||
|
@ -1369,7 +1370,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
|||
}
|
||||
QMenu m;
|
||||
bool isDCName = false;
|
||||
if (!current_dive)
|
||||
if (!d)
|
||||
return;
|
||||
// figure out if we are ontop of the dive computer name in the profile
|
||||
QGraphicsItem *sceneItem = itemAt(mapFromGlobal(event->globalPos()));
|
||||
|
@ -1383,13 +1384,13 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
|||
parentItem = parentItem->parentItem();
|
||||
}
|
||||
if (isDCName) {
|
||||
if (dc_number == 0 && number_of_computers(current_dive) == 1)
|
||||
if (dc == 0 && number_of_computers(d) == 1)
|
||||
// nothing to do, can't delete or reorder
|
||||
return;
|
||||
// create menu to show when right clicking on dive computer name
|
||||
if (dc_number > 0)
|
||||
if (dc > 0)
|
||||
m.addAction(tr("Make first dive computer"), this, &ProfileWidget2::makeFirstDC);
|
||||
if (number_of_computers(current_dive) > 1) {
|
||||
if (number_of_computers(d) > 1) {
|
||||
m.addAction(tr("Delete this dive computer"), this, &ProfileWidget2::deleteCurrentDC);
|
||||
m.addAction(tr("Split this dive computer into own dive"), this, &ProfileWidget2::splitCurrentDC);
|
||||
}
|
||||
|
@ -1405,19 +1406,19 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
|||
DiveEventItem *item = dynamic_cast<DiveEventItem *>(sceneItem);
|
||||
|
||||
// Add or edit Gas Change
|
||||
if (current_dive && item && event_is_gaschange(item->getEvent())) {
|
||||
if (d && item && event_is_gaschange(item->getEvent())) {
|
||||
int eventTime = item->getEvent()->time.seconds;
|
||||
QMenu *gasChange = m.addMenu(tr("Edit Gas Change"));
|
||||
for (int i = 0; i < current_dive->cylinders.nr; i++) {
|
||||
const cylinder_t *cylinder = get_cylinder(current_dive, i);
|
||||
for (int i = 0; i < d->cylinders.nr; i++) {
|
||||
const cylinder_t *cylinder = get_cylinder(d, i);
|
||||
QString label = printCylinderDescription(i, cylinder);
|
||||
gasChange->addAction(label, [this, i, eventTime] { changeGas(i, eventTime); });
|
||||
}
|
||||
} else if (current_dive && current_dive->cylinders.nr > 1) {
|
||||
} else if (d && d->cylinders.nr > 1) {
|
||||
// if we have more than one gas, offer to switch to another one
|
||||
QMenu *gasChange = m.addMenu(tr("Add gas change"));
|
||||
for (int i = 0; i < current_dive->cylinders.nr; i++) {
|
||||
const cylinder_t *cylinder = get_cylinder(current_dive, i);
|
||||
for (int i = 0; i < d->cylinders.nr; i++) {
|
||||
const cylinder_t *cylinder = get_cylinder(d, i);
|
||||
QString label = printCylinderDescription(i, cylinder);
|
||||
gasChange->addAction(label, [this, i, seconds] { changeGas(i, seconds); });
|
||||
}
|
||||
|
@ -1428,7 +1429,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
|||
const struct event *ev = NULL;
|
||||
enum divemode_t divemode = UNDEF_COMP_TYPE;
|
||||
|
||||
get_current_divemode(current_dc, seconds, &ev, &divemode);
|
||||
get_current_divemode(get_dive_dc_const(d, dc), seconds, &ev, &divemode);
|
||||
QMenu *changeMode = m.addMenu(tr("Change divemode"));
|
||||
if (divemode != OC)
|
||||
changeMode->addAction(gettextFromC::tr(divemode_text_ui[OC]),
|
||||
|
@ -1440,7 +1441,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
|||
changeMode->addAction(gettextFromC::tr(divemode_text_ui[PSCR]),
|
||||
[this, seconds](){ addDivemodeSwitch(seconds, PSCR); });
|
||||
|
||||
if (same_string(current_dc->model, "manually added dive"))
|
||||
if (same_string(get_dive_dc_const(d, dc)->model, "manually added dive"))
|
||||
m.addAction(tr("Edit the profile"), this, &ProfileWidget2::editCurrentDive);
|
||||
|
||||
if (DiveEventItem *item = dynamic_cast<DiveEventItem *>(sceneItem)) {
|
||||
|
@ -1471,7 +1472,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
|||
int newGasIdx = gasChangeIdx + 1;
|
||||
const struct plot_data &newGasEntry = plotInfo.entry[newGasIdx];
|
||||
qDebug() << "after gas change at " << newGasEntry->sec << ": sensor pressure" << newGasEntry->pressure[0] << "interpolated" << newGasEntry->pressure[1];
|
||||
if (get_plot_sensor_pressure(&plotInfo, gasChangeIdx) == 0 || get_cylinder(&displayed_dive, gasChangeEntry->sensor[0])->sample_start.mbar == 0) {
|
||||
if (get_plot_sensor_pressure(&plotInfo, gasChangeIdx) == 0 || get_cylinder(d, gasChangeEntry->sensor[0])->sample_start.mbar == 0) {
|
||||
// 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
|
||||
|
@ -1480,7 +1481,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
|||
QAction *adjustOldPressure = m.addAction(tr("Adjust pressure of cyl. %1 (currently interpolated as %2)")
|
||||
.arg(gasChangeEntry->sensor[0] + 1).arg(get_pressure_string(pressure)));
|
||||
}
|
||||
if (get_plot_sensor_pressure(&plotInfo, newGasIdx) == 0 || get_cylinder(&displayed_dive, newGasEntry->sensor[0])->sample_start.mbar == 0) {
|
||||
if (get_plot_sensor_pressure(&plotInfo, newGasIdx) == 0 || get_cylinder(d, newGasEntry->sensor[0])->sample_start.mbar == 0) {
|
||||
// we only have interpolated press -- see commend above
|
||||
pressure_t pressure;
|
||||
pressure.mbar = get_plot_interpolated_pressure(&plotInfo, newGasIdx) ? : get_plot_sensor_pressure(&plotInfo, newGasIdx);
|
||||
|
@ -1505,17 +1506,20 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
|||
|
||||
void ProfileWidget2::deleteCurrentDC()
|
||||
{
|
||||
Command::deleteDiveComputer(current_dive, dc_number);
|
||||
if (d)
|
||||
Command::deleteDiveComputer(mutable_dive(), dc);
|
||||
}
|
||||
|
||||
void ProfileWidget2::splitCurrentDC()
|
||||
{
|
||||
Command::splitDiveComputer(current_dive, dc_number);
|
||||
if (d)
|
||||
Command::splitDiveComputer(mutable_dive(), dc);
|
||||
}
|
||||
|
||||
void ProfileWidget2::makeFirstDC()
|
||||
{
|
||||
Command::moveDiveComputerToFront(current_dive, dc_number);
|
||||
if (d)
|
||||
Command::moveDiveComputerToFront(mutable_dive(), dc);
|
||||
}
|
||||
|
||||
void ProfileWidget2::hideEvents(DiveEventItem *item)
|
||||
|
@ -1551,68 +1555,54 @@ void ProfileWidget2::unhideEvents()
|
|||
item->show();
|
||||
}
|
||||
|
||||
// The profile displays a copy of the current_dive, namely displayed_dive.
|
||||
// Therefore, the events we get are likewise copies. This function finds
|
||||
// the original event. TODO: Remove function once the profile can display
|
||||
// arbitrary dives.
|
||||
static event *find_event(const struct event *ev)
|
||||
{
|
||||
struct divecomputer *dc = current_dc;
|
||||
if (!dc)
|
||||
return nullptr;
|
||||
for (struct event *act = current_dc->events; act; act = act->next) {
|
||||
if (same_event(act, ev))
|
||||
return act;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ProfileWidget2::removeEvent(DiveEventItem *item)
|
||||
{
|
||||
struct event *event = find_event(item->getEvent());
|
||||
if (!event)
|
||||
struct event *event = item->getEvent();
|
||||
if (!event || !d)
|
||||
return;
|
||||
|
||||
if (QMessageBox::question(this, TITLE_OR_TEXT(
|
||||
tr("Remove the selected event?"),
|
||||
tr("%1 @ %2:%3").arg(event->name).arg(event->time.seconds / 60).arg(event->time.seconds % 60, 2, 10, QChar('0'))),
|
||||
QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok)
|
||||
Command::removeEvent(current_dive, dc_number, event);
|
||||
Command::removeEvent(mutable_dive(), dc, event);
|
||||
}
|
||||
|
||||
void ProfileWidget2::addBookmark(int seconds)
|
||||
{
|
||||
Command::addEventBookmark(current_dive, dc_number, seconds);
|
||||
if (d)
|
||||
Command::addEventBookmark(mutable_dive(), dc, seconds);
|
||||
}
|
||||
|
||||
void ProfileWidget2::addDivemodeSwitch(int seconds, int divemode)
|
||||
{
|
||||
Command::addEventDivemodeSwitch(current_dive, dc_number, seconds, divemode);
|
||||
if (d)
|
||||
Command::addEventDivemodeSwitch(mutable_dive(), dc, seconds, divemode);
|
||||
}
|
||||
|
||||
void ProfileWidget2::addSetpointChange(int seconds)
|
||||
{
|
||||
SetpointDialog dialog(current_dive, dc_number, seconds);
|
||||
if (!d)
|
||||
return;
|
||||
SetpointDialog dialog(mutable_dive(), dc, seconds);
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
void ProfileWidget2::splitDive(int seconds)
|
||||
{
|
||||
#ifndef SUBSURFACE_MOBILE
|
||||
// Make sure that this is an actual dive and we're not in add mode
|
||||
dive *d = get_dive_by_uniq_id(displayed_dive.id);
|
||||
if (!d)
|
||||
return;
|
||||
Command::splitDives(d, duration_t{ seconds });
|
||||
Command::splitDives(mutable_dive(), duration_t{ seconds });
|
||||
#endif
|
||||
}
|
||||
|
||||
void ProfileWidget2::changeGas(int tank, int seconds)
|
||||
{
|
||||
if (!current_dive || tank < 0 || tank >= current_dive->cylinders.nr)
|
||||
if (!d || tank < 0 || tank >= d->cylinders.nr)
|
||||
return;
|
||||
|
||||
Command::addGasSwitch(current_dive, dc_number, seconds, tank);
|
||||
Command::addGasSwitch(mutable_dive(), dc, seconds, tank);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1660,8 +1650,8 @@ double ProfileWidget2::getFontPrintScale() const
|
|||
#ifndef SUBSURFACE_MOBILE
|
||||
void ProfileWidget2::editName(DiveEventItem *item)
|
||||
{
|
||||
struct event *event = find_event(item->getEvent());
|
||||
if (!event)
|
||||
struct event *event = item->getEvent();
|
||||
if (!event || !d)
|
||||
return;
|
||||
bool ok;
|
||||
QString newName = QInputDialog::getText(this, tr("Edit name of bookmark"),
|
||||
|
@ -1674,7 +1664,7 @@ void ProfileWidget2::editName(DiveEventItem *item)
|
|||
lengthWarning.exec();
|
||||
return;
|
||||
}
|
||||
Command::renameEvent(current_dive, dc_number, event, qPrintable(newName));
|
||||
Command::renameEvent(mutable_dive(), dc, event, qPrintable(newName));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1710,7 +1700,7 @@ int ProfileWidget2::handleIndex(const DiveHandler *h) const
|
|||
|
||||
DiveHandler *ProfileWidget2::createHandle()
|
||||
{
|
||||
DiveHandler *item = new DiveHandler(&displayed_dive);
|
||||
DiveHandler *item = new DiveHandler(d);
|
||||
scene()->addItem(item);
|
||||
connect(item, &DiveHandler::moved, this, &ProfileWidget2::divePlannerHandlerMoved);
|
||||
connect(item, &DiveHandler::clicked, this, &ProfileWidget2::divePlannerHandlerClicked);
|
||||
|
@ -1792,8 +1782,8 @@ void ProfileWidget2::repositionDiveHandlers()
|
|||
QLineF line(p1, p2);
|
||||
QPointF pos = line.pointAt(0.5);
|
||||
gases[i]->setPos(pos);
|
||||
if (datapoint.cylinderid >= 0 && datapoint.cylinderid < displayed_dive.cylinders.nr)
|
||||
gases[i]->setText(get_gas_string(get_cylinder(&displayed_dive, datapoint.cylinderid)->gasmix));
|
||||
if (datapoint.cylinderid >= 0 && datapoint.cylinderid < d->cylinders.nr)
|
||||
gases[i]->setText(get_gas_string(get_cylinder(d, datapoint.cylinderid)->gasmix));
|
||||
else
|
||||
gases[i]->setText(QString());
|
||||
gases[i]->setVisible(datapoint.entered &&
|
||||
|
@ -2067,7 +2057,7 @@ void ProfileWidget2::updateThumbnailXPos(PictureEntry &e)
|
|||
// This function resets the picture thumbnails of the current dive.
|
||||
void ProfileWidget2::plotPictures()
|
||||
{
|
||||
plotPicturesInternal(current_dive, false);
|
||||
plotPicturesInternal(d, false);
|
||||
}
|
||||
|
||||
void ProfileWidget2::plotPicturesInternal(const struct dive *d, bool synchronous)
|
||||
|
@ -2099,8 +2089,6 @@ void ProfileWidget2::plotPicturesInternal(const struct dive *d, bool synchronous
|
|||
// Remove the pictures with the given filenames from the profile plot.
|
||||
void ProfileWidget2::picturesRemoved(dive *d, QVector<QString> fileUrls)
|
||||
{
|
||||
if (d->id != displayed_dive.id)
|
||||
return;
|
||||
// To remove the pictures, we use the std::remove_if() algorithm.
|
||||
// std::remove_if() does not actually delete the elements, but moves
|
||||
// them to the end of the given range. It returns an iterator to the
|
||||
|
@ -2116,9 +2104,6 @@ void ProfileWidget2::picturesRemoved(dive *d, QVector<QString> fileUrls)
|
|||
|
||||
void ProfileWidget2::picturesAdded(dive *d, QVector<PictureObj> pics)
|
||||
{
|
||||
if (d->id != displayed_dive.id)
|
||||
return;
|
||||
|
||||
for (const PictureObj &pic: pics) {
|
||||
if (pic.offset.seconds > 0 && pic.offset.seconds <= d->duration.seconds) {
|
||||
pictures.emplace_back(pic.offset, QString::fromStdString(pic.filename), this, false);
|
||||
|
@ -2135,14 +2120,13 @@ void ProfileWidget2::picturesAdded(dive *d, QVector<PictureObj> pics)
|
|||
|
||||
void ProfileWidget2::removePicture(const QString &fileUrl)
|
||||
{
|
||||
struct dive *d = get_dive_by_uniq_id(displayed_dive.id);
|
||||
if (d)
|
||||
Command::removePictures({ { d, { fileUrl.toStdString() } } });
|
||||
Command::removePictures({ { mutable_dive(), { fileUrl.toStdString() } } });
|
||||
}
|
||||
|
||||
void ProfileWidget2::profileChanged(dive *d)
|
||||
void ProfileWidget2::profileChanged(dive *dive)
|
||||
{
|
||||
if (!d || d->id != displayed_dive.id)
|
||||
if (dive != d)
|
||||
return; // Cylinders of a differnt dive than the shown one changed.
|
||||
replot();
|
||||
}
|
||||
|
@ -2152,7 +2136,7 @@ void ProfileWidget2::profileChanged(dive *d)
|
|||
void ProfileWidget2::dropEvent(QDropEvent *event)
|
||||
{
|
||||
#ifndef SUBSURFACE_MOBILE
|
||||
if (event->mimeData()->hasFormat("application/x-subsurfaceimagedrop")) {
|
||||
if (event->mimeData()->hasFormat("application/x-subsurfaceimagedrop") && d) {
|
||||
QByteArray itemData = event->mimeData()->data("application/x-subsurfaceimagedrop");
|
||||
QDataStream dataStream(&itemData, QIODevice::ReadOnly);
|
||||
|
||||
|
@ -2160,7 +2144,7 @@ void ProfileWidget2::dropEvent(QDropEvent *event)
|
|||
dataStream >> filename;
|
||||
QPointF mappedPos = mapToScene(event->pos());
|
||||
offset_t offset { (int32_t)lrint(timeAxis->valueAt(mappedPos)) };
|
||||
Command::setPictureOffset(current_dive, filename, offset);
|
||||
Command::setPictureOffset(mutable_dive(), filename, offset);
|
||||
|
||||
if (event->source() == this) {
|
||||
event->setDropAction(Qt::MoveAction);
|
||||
|
@ -2175,13 +2159,13 @@ void ProfileWidget2::dropEvent(QDropEvent *event)
|
|||
}
|
||||
|
||||
#ifndef SUBSURFACE_MOBILE
|
||||
void ProfileWidget2::pictureOffsetChanged(dive *d, QString filename, offset_t offset)
|
||||
void ProfileWidget2::pictureOffsetChanged(dive *dIn, QString filename, offset_t offset)
|
||||
{
|
||||
if (d->id != displayed_dive.id)
|
||||
if (dIn != d)
|
||||
return; // Picture of a different dive than the one shown changed.
|
||||
|
||||
// Calculate time in dive where picture was dropped and whether the new position is during the dive.
|
||||
bool duringDive = current_dive && offset.seconds > 0 && offset.seconds < current_dive->duration.seconds;
|
||||
bool duringDive = d && offset.seconds > 0 && offset.seconds < d->duration.seconds;
|
||||
|
||||
// A picture was drag&dropped onto the profile: We have four cases to consider:
|
||||
// 1a) The image was already shown on the profile and is moved to a different position on the profile.
|
||||
|
@ -2266,3 +2250,8 @@ void ProfileWidget2::dragMoveEvent(QDragMoveEvent *event)
|
|||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
struct dive *ProfileWidget2::mutable_dive() const
|
||||
{
|
||||
return const_cast<dive *>(d);
|
||||
}
|
||||
|
|
|
@ -80,7 +80,10 @@ public:
|
|||
~ProfileWidget2();
|
||||
void resetZoom();
|
||||
void scale(qreal sx, qreal sy);
|
||||
void plotDive(const struct dive *d, bool force = false, bool clearPictures = false, bool instant = false);
|
||||
void plotDive(const struct dive *d, int dc, bool force = false, bool clearPictures = false, bool instant = false);
|
||||
void setProfileState(const struct dive *d, int dc);
|
||||
void setPlanState(const struct dive *d, int dc);
|
||||
void setAddState(const struct dive *d, int dc);
|
||||
void setPrintMode(bool mode, bool grayscale = false);
|
||||
bool getPrintMode() const;
|
||||
bool isPointOutOfBoundaries(const QPointF &point) const;
|
||||
|
@ -107,13 +110,10 @@ slots: // Necessary to call from QAction's signals.
|
|||
void actionRequestedReplot(bool triggered);
|
||||
void divesChanged(const QVector<dive *> &dives, DiveField field);
|
||||
void setEmptyState();
|
||||
void setProfileState();
|
||||
#ifndef SUBSURFACE_MOBILE
|
||||
void plotPictures();
|
||||
void picturesRemoved(dive *d, QVector<QString> filenames);
|
||||
void picturesAdded(dive *d, QVector<PictureObj> pics);
|
||||
void setPlanState();
|
||||
void setAddState();
|
||||
void pointsReset();
|
||||
void pointInserted(const QModelIndex &parent, int start, int end);
|
||||
void pointsRemoved(const QModelIndex &, int start, int end);
|
||||
|
@ -139,6 +139,7 @@ slots: // Necessary to call from QAction's signals.
|
|||
#endif
|
||||
|
||||
private:
|
||||
void setProfileState(); // keep currently displayed dive
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
#ifndef SUBSURFACE_MOBILE
|
||||
void wheelEvent(QWheelEvent *event) override;
|
||||
|
@ -194,6 +195,8 @@ private:
|
|||
// All those here should probably be merged into one structure,
|
||||
// So it's esyer to replicate for more dives later.
|
||||
// In the meantime, keep it here.
|
||||
const struct dive *d;
|
||||
int dc;
|
||||
struct plot_info plotInfo;
|
||||
DepthAxis *profileYAxis;
|
||||
PartialGasPressureAxis *gasYAxis;
|
||||
|
@ -272,6 +275,12 @@ private:
|
|||
int maxtime;
|
||||
int maxdepth;
|
||||
double fontPrintScale;
|
||||
|
||||
// We store a const pointer to the shown dive. However, the undo commands want
|
||||
// (understandably) a non-const pointer. Since the profile has a context-menu
|
||||
// with actions, it needs such a non-const pointer. This function turns the
|
||||
// currently shown dive into such a pointer. Ugly, yes.
|
||||
struct dive *mutable_dive() const;
|
||||
};
|
||||
|
||||
#endif // PROFILEWIDGET2_H
|
||||
|
|
|
@ -20,7 +20,7 @@ QMLProfile::QMLProfile(QQuickItem *parent) :
|
|||
{
|
||||
setAntialiasing(true);
|
||||
setFlags(QQuickItem::ItemClipsChildrenToShape | QQuickItem::ItemHasContents );
|
||||
m_profileWidget->setProfileState();
|
||||
m_profileWidget->setProfileState(nullptr, 0);
|
||||
m_profileWidget->setPrintMode(true);
|
||||
m_profileWidget->setFontPrintScale(fontScale);
|
||||
connect(QMLManager::instance(), &QMLManager::sendScreenChanged, this, &QMLProfile::screenChanged);
|
||||
|
@ -135,7 +135,7 @@ void QMLProfile::updateProfile()
|
|||
return;
|
||||
if (verbose)
|
||||
qDebug() << "update profile for dive #" << d->number << "offeset" << QString::number(m_xOffset, 'f', 1) << "/" << QString::number(m_yOffset, 'f', 1);
|
||||
m_profileWidget->plotDive(d, true);
|
||||
m_profileWidget->plotDive(d, dc_number, true);
|
||||
}
|
||||
|
||||
void QMLProfile::setDiveId(int diveId)
|
||||
|
@ -189,10 +189,9 @@ void QMLProfile::divesChanged(const QVector<dive *> &dives, DiveField)
|
|||
for (struct dive *d: dives) {
|
||||
if (d->id == m_diveId) {
|
||||
qDebug() << "dive #" << d->number << "changed, trigger profile update";
|
||||
m_profileWidget->plotDive(d, true);
|
||||
m_profileWidget->plotDive(d, dc_number, true);
|
||||
triggerUpdate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -193,7 +193,6 @@ void DivePictureModel::picturesRemoved(dive *d, QVector<QString> filenamesIn)
|
|||
endRemoveRows();
|
||||
toIdx -= j - i;
|
||||
}
|
||||
copy_dive(current_dive, &displayed_dive); // TODO: Remove once displayed_dive is moved to the planner
|
||||
}
|
||||
|
||||
// Assumes that pics is sorted!
|
||||
|
@ -306,7 +305,6 @@ void DivePictureModel::pictureOffsetChanged(dive *d, const QString filenameIn, o
|
|||
|
||||
// Update the offset here and in the backend
|
||||
oldPos->offsetSeconds = offset.seconds;
|
||||
copy_dive(current_dive, &displayed_dive); // TODO: remove once profile can display arbitrary dives
|
||||
|
||||
// Henceforth we will work with indices instead of iterators
|
||||
int oldIndex = oldPos - pictures.begin();
|
||||
|
|
Loading…
Add table
Reference in a new issue