diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2020-04-14 22:07:00 +0200 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2020-05-06 13:58:09 -0700 |
commit | e61641c79cd57bfa55d2371615a7eef7c73b4eb7 (patch) | |
tree | 85333dfed1630b1d968498495d1d1c151570e015 /profile-widget | |
parent | ebdb3e3c3029d3762207e8dcadfa3a61bf0a9293 (diff) | |
download | subsurface-e61641c79cd57bfa55d2371615a7eef7c73b4eb7.tar.gz |
undo: implement undo of setting a picture time by drag&drop
Even though the functionality is seemingly trivial, this is a bit
invasive, as the code has to be split into two distinct parts:
1) Post undo command
2) React to changes to the divelist
Don't compile that code on mobile.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'profile-widget')
-rw-r--r-- | profile-widget/profilewidget2.cpp | 145 | ||||
-rw-r--r-- | profile-widget/profilewidget2.h | 1 |
2 files changed, 72 insertions, 74 deletions
diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp index 71db3d66f..cea5a50f0 100644 --- a/profile-widget/profilewidget2.cpp +++ b/profile-widget/profilewidget2.cpp @@ -19,7 +19,7 @@ #include "core/pref.h" #include "qt-models/diveplannermodel.h" #include "qt-models/models.h" -#include "qt-models/divepicturemodel.h" +#include "qt-models/divepicturemodel.h" // TODO: remove once divepictures have been undo-ified #include "core/divelist.h" #include "core/errorhelper.h" #ifndef SUBSURFACE_MOBILE @@ -174,6 +174,7 @@ ProfileWidget2::ProfileWidget2(QWidget *parent) : QGraphicsView(parent), connect(DivePictureModel::instance(), &DivePictureModel::modelReset, this, &ProfileWidget2::plotPictures); connect(&diveListNotifier, &DiveListNotifier::cylinderEdited, this, &ProfileWidget2::profileChanged); connect(&diveListNotifier, &DiveListNotifier::eventsChanged, this, &ProfileWidget2::profileChanged); + connect(&diveListNotifier, &DiveListNotifier::pictureOffsetChanged, this, &ProfileWidget2::pictureOffsetChanged); #endif // SUBSURFACE_MOBILE #if !defined(QT_NO_DEBUG) && defined(SHOW_PLOT_INFO_TABLE) @@ -2175,86 +2176,16 @@ void ProfileWidget2::profileChanged(dive *d) void ProfileWidget2::dropEvent(QDropEvent *event) { +#ifndef SUBSURFACE_MOBILE if (event->mimeData()->hasFormat("application/x-subsurfaceimagedrop")) { QByteArray itemData = event->mimeData()->data("application/x-subsurfaceimagedrop"); QDataStream dataStream(&itemData, QIODevice::ReadOnly); QString filename; - int diveId; - dataStream >> filename >> diveId; - - // If the id of the drag & dropped picture belongs to a different dive, then - // the offset we determine makes no sense what so ever. Simply ignore such an event. - // In the future, we might think about duplicating the picture or moving the picture - // from one dive to the other. - if (!current_dive || displayed_dive.id != diveId) { - event->ignore(); - return; - } - -#ifndef SUBSURFACE_MOBILE - // Calculate time in dive where picture was dropped and whether the new position is during the dive. + dataStream >> filename; QPointF mappedPos = mapToScene(event->pos()); offset_t offset { (int32_t)lrint(timeAxis->valueAt(mappedPos)) }; - bool duringDive = current_dive && offset.seconds > 0 && offset.seconds < current_dive->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. - // Calculate the new position and move the picture. - // 1b) The image was on the profile and is moved outside of the dive time. - // Remove the picture. - // 2a) The image was not on the profile and is moved into the dive time. - // Add the picture to the profile. - // 2b) The image was not on the profile and is moved outside of the dive time. - // Do nothing. - auto oldPos = std::find_if(pictures.begin(), pictures.end(), [filename](const PictureEntry &e) - { return e.filename == filename; }); - if (oldPos != pictures.end()) { - // Cases 1a) and 1b): picture is on profile - if (duringDive) { - // Case 1a): move to new position - // First, find new position. Note that we also have to compare filenames, - // because it is quite easy to generate equal offsets. - auto newPos = std::find_if(pictures.begin(), pictures.end(), [offset, &filename](const PictureEntry &e) - { return std::tie(e.offset.seconds, e.filename) > std::tie(offset.seconds, filename); }); - // Set new offset - oldPos->offset.seconds = offset.seconds; - updateThumbnailXPos(*oldPos); - - // Move image from old to new position - int oldIndex = oldPos - pictures.begin(); - int newIndex = newPos - pictures.begin(); - moveInVector(pictures, oldIndex, oldIndex + 1, newIndex); - } else { - // Case 1b): remove picture - pictures.erase(oldPos); - } - - // In both cases the picture list changed, therefore we must recalculate the y-coordinatesA. - calculatePictureYPositions(); - } else { - // Cases 2a) and 2b): picture not on profile. We only have to take action for - // the first case: picture is moved into dive-time. - if (duringDive) { - // Case 2a): add the picture at the appropriate position. - // The case move from outside-to-outside of the profile plot was handled by - // the "&& duringDive" condition in the if above. - // As for case 1a), we have to also consider filenames in the case of equal offsets. - auto newPos = std::find_if(pictures.begin(), pictures.end(), [offset, &filename](const PictureEntry &e) - { return std::tie(e.offset.seconds, e.filename) > std::tie(offset.seconds, filename); }); - // emplace() constructs the element at the given position in the vector. - // The parameters are passed directly to the contructor. - // The call returns an iterator to the new element (which might differ from - // the old iterator, since the buffer might have been reallocated). - newPos = pictures.emplace(newPos, offset, filename, scene(), false); - updateThumbnailXPos(*newPos); - calculatePictureYPositions(); - } - } - - // Only signal the drag&drop action if the picture actually belongs to the dive. - DivePictureModel::instance()->updateDivePictureOffset(displayed_dive.id, filename, offset.seconds); -#endif + Command::setPictureOffset(current_dive, filename, offset); if (event->source() == this) { event->setDropAction(Qt::MoveAction); @@ -2265,7 +2196,73 @@ void ProfileWidget2::dropEvent(QDropEvent *event) } else { event->ignore(); } +#endif +} + +#ifndef SUBSURFACE_MOBILE +void ProfileWidget2::pictureOffsetChanged(dive *d, QString filename, offset_t offset) +{ + if (d->id != displayed_dive.id) + 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; + + // 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. + // Calculate the new position and move the picture. + // 1b) The image was on the profile and is moved outside of the dive time. + // Remove the picture. + // 2a) The image was not on the profile and is moved into the dive time. + // Add the picture to the profile. + // 2b) The image was not on the profile and is moved outside of the dive time. + // Do nothing. + auto oldPos = std::find_if(pictures.begin(), pictures.end(), [filename](const PictureEntry &e) + { return e.filename == filename; }); + if (oldPos != pictures.end()) { + // Cases 1a) and 1b): picture is on profile + if (duringDive) { + // Case 1a): move to new position + // First, find new position. Note that we also have to compare filenames, + // because it is quite easy to generate equal offsets. + auto newPos = std::find_if(pictures.begin(), pictures.end(), [offset, &filename](const PictureEntry &e) + { return std::tie(e.offset.seconds, e.filename) > std::tie(offset.seconds, filename); }); + // Set new offset + oldPos->offset.seconds = offset.seconds; + updateThumbnailXPos(*oldPos); + + // Move image from old to new position + int oldIndex = oldPos - pictures.begin(); + int newIndex = newPos - pictures.begin(); + moveInVector(pictures, oldIndex, oldIndex + 1, newIndex); + } else { + // Case 1b): remove picture + pictures.erase(oldPos); + } + + // In both cases the picture list changed, therefore we must recalculate the y-coordinatesA. + calculatePictureYPositions(); + } else { + // Cases 2a) and 2b): picture not on profile. We only have to take action for + // the first case: picture is moved into dive-time. + if (duringDive) { + // Case 2a): add the picture at the appropriate position. + // The case move from outside-to-outside of the profile plot was handled by + // the "&& duringDive" condition in the if above. + // As for case 1a), we have to also consider filenames in the case of equal offsets. + auto newPos = std::find_if(pictures.begin(), pictures.end(), [offset, &filename](const PictureEntry &e) + { return std::tie(e.offset.seconds, e.filename) > std::tie(offset.seconds, filename); }); + // emplace() constructs the element at the given position in the vector. + // The parameters are passed directly to the contructor. + // The call returns an iterator to the new element (which might differ from + // the old iterator, since the buffer might have been reallocated). + newPos = pictures.emplace(newPos, offset, filename, scene(), false); + updateThumbnailXPos(*newPos); + calculatePictureYPositions(); + } + } } +#endif void ProfileWidget2::dragEnterEvent(QDragEnterEvent *event) { diff --git a/profile-widget/profilewidget2.h b/profile-widget/profilewidget2.h index 96191a1d6..039424d87 100644 --- a/profile-widget/profilewidget2.h +++ b/profile-widget/profilewidget2.h @@ -117,6 +117,7 @@ slots: // Necessary to call from QAction's signals. void pointsRemoved(const QModelIndex &, int start, int end); void updateThumbnail(QString filename, QImage thumbnail, duration_t duration); void profileChanged(dive *d); + void pictureOffsetChanged(dive *d, QString filename, offset_t offset); /* this is called for every move on the handlers. maybe we can speed up this a bit? */ void recreatePlannedDive(); |