2023-05-20 14:27:20 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#ifndef PROFILE_VIEW_H
|
|
|
|
#define PROFILE_VIEW_H
|
|
|
|
|
|
|
|
#include "qt-quick/chartview.h"
|
2023-08-12 22:59:56 +02:00
|
|
|
#include "core/units.h"
|
2023-05-20 14:27:20 +02:00
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
class ChartGraphicsSceneItem;
|
2024-01-20 21:03:02 +01:00
|
|
|
class ChartLineItem;
|
2023-08-12 22:59:56 +02:00
|
|
|
class ChartRectItem;
|
2024-01-20 21:03:02 +01:00
|
|
|
class DivePlannerPointsModel;
|
|
|
|
class HandleItem;
|
2023-08-12 22:59:56 +02:00
|
|
|
class PictureItem;
|
2023-05-20 15:22:02 +02:00
|
|
|
class ProfileAnimation;
|
2023-05-20 14:27:20 +02:00
|
|
|
class ProfileScene;
|
2023-06-16 18:24:22 +02:00
|
|
|
class ToolTipItem;
|
2023-08-12 22:59:56 +02:00
|
|
|
struct picture;
|
2024-01-12 22:26:32 +01:00
|
|
|
class RulerItem;
|
2024-01-20 21:03:02 +01:00
|
|
|
class QModelIndex;
|
2023-05-20 14:27:20 +02:00
|
|
|
|
|
|
|
class ProfileView : public ChartView {
|
|
|
|
Q_OBJECT
|
2023-05-20 20:58:38 +02:00
|
|
|
|
|
|
|
// Communication with the mobile interface is via properties. I hate it.
|
|
|
|
Q_PROPERTY(int diveId READ getDiveId WRITE setDiveId)
|
|
|
|
Q_PROPERTY(int numDC READ numDC NOTIFY numDCChanged)
|
|
|
|
Q_PROPERTY(double zoomLevel MEMBER zoomLevel NOTIFY zoomLevelChanged)
|
2023-05-20 14:27:20 +02:00
|
|
|
public:
|
|
|
|
ProfileView();
|
|
|
|
ProfileView(QQuickItem *parent);
|
|
|
|
~ProfileView();
|
|
|
|
|
2024-01-20 21:03:02 +01:00
|
|
|
// Flag set when constructing the object. Because QtQuick may decide to destroy the old one. :(
|
|
|
|
bool initialized;
|
|
|
|
void setPlannerModel(DivePlannerPointsModel &model); // enables planning and edit mdoe
|
|
|
|
|
2023-05-20 14:27:20 +02:00
|
|
|
struct RenderFlags {
|
|
|
|
static constexpr int None = 0;
|
|
|
|
static constexpr int Instant = 1 << 0;
|
|
|
|
static constexpr int DontRecalculatePlotInfo = 1 << 1;
|
|
|
|
static constexpr int EditMode = 1 << 2;
|
|
|
|
static constexpr int PlanMode = 1 << 3;
|
2023-08-12 22:59:56 +02:00
|
|
|
static constexpr int Simplified = 1 << 4; // For mobile's overview page
|
2024-01-20 21:03:02 +01:00
|
|
|
static constexpr int DontCalculateMax = 1 << 5;
|
2023-05-20 14:27:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
void plotDive(const struct dive *d, int dc, int flags = RenderFlags::None);
|
2023-08-12 22:59:56 +02:00
|
|
|
int timeAt(QPointF pos) const;
|
2023-05-20 14:27:20 +02:00
|
|
|
void clear();
|
2023-05-20 17:12:33 +02:00
|
|
|
void resetZoom();
|
2023-05-20 15:22:02 +02:00
|
|
|
void anim(double fraction);
|
2024-01-20 21:03:02 +01:00
|
|
|
void rulerDragged(); // Called by the RulterItem when a handle was dragged.
|
|
|
|
void handleSelected(int idx); // Called by the HandleItem when it is clicked.
|
|
|
|
void handleDragged(int idx, QPointF pos); // Called by the HandleItem when it is dragged.
|
|
|
|
void handleReleased(int idx); // Called by the HandleItem when it is released.
|
2023-05-20 20:58:38 +02:00
|
|
|
|
|
|
|
// For mobile
|
|
|
|
Q_INVOKABLE void pinchStart();
|
|
|
|
Q_INVOKABLE void pinch(double factor);
|
|
|
|
Q_INVOKABLE void nextDC();
|
|
|
|
Q_INVOKABLE void prevDC();
|
|
|
|
Q_INVOKABLE void panStart(double x, double y);
|
|
|
|
Q_INVOKABLE void pan(double x, double y);
|
2024-01-20 21:03:02 +01:00
|
|
|
|
2023-05-20 20:58:38 +02:00
|
|
|
signals:
|
|
|
|
void numDCChanged();
|
|
|
|
void zoomLevelChanged();
|
2024-01-20 21:03:02 +01:00
|
|
|
void stopAdded(); // only emitted in edit mode
|
|
|
|
void stopRemoved(int count); // only emitted in edit mode
|
|
|
|
void stopMoved(int count); // only emitted in edit mode
|
2023-05-20 14:27:20 +02:00
|
|
|
private:
|
2024-01-20 21:03:02 +01:00
|
|
|
enum Mode {
|
|
|
|
Normal,
|
|
|
|
Edit,
|
|
|
|
Plan
|
|
|
|
};
|
2023-05-20 14:27:20 +02:00
|
|
|
const struct dive *d;
|
|
|
|
int dc;
|
2024-01-20 21:03:02 +01:00
|
|
|
DivePlannerPointsModel *plannerModel;
|
|
|
|
Mode mode;
|
2023-08-12 22:59:56 +02:00
|
|
|
bool simplified;
|
2023-06-16 18:24:22 +02:00
|
|
|
double dpr;
|
2023-05-20 20:58:38 +02:00
|
|
|
double zoomLevel, zoomLevelPinchStart;
|
2023-05-20 14:27:20 +02:00
|
|
|
double zoomedPosition; // Position when zoomed: 0.0 = beginning, 1.0 = end.
|
2023-05-20 17:12:33 +02:00
|
|
|
bool panning; // Currently panning.
|
|
|
|
double panningOriginalMousePosition;
|
|
|
|
double panningOriginalProfilePosition;
|
2023-05-20 14:27:20 +02:00
|
|
|
bool empty; // No dive shown.
|
2023-05-20 15:22:02 +02:00
|
|
|
QColor background;
|
2023-05-20 14:27:20 +02:00
|
|
|
std::unique_ptr<ProfileScene> profileScene;
|
|
|
|
ChartItemPtr<ChartGraphicsSceneItem> profileItem;
|
2023-05-20 15:22:02 +02:00
|
|
|
std::unique_ptr<ProfileAnimation> animation;
|
2024-01-20 21:03:02 +01:00
|
|
|
ChartItemPtr<ChartLineItem> mouseFollowerHorizontal, mouseFollowerVertical;
|
2023-05-20 14:27:20 +02:00
|
|
|
|
|
|
|
void plotAreaChanged(const QSizeF &size) override;
|
|
|
|
void resetPointers() override;
|
2023-05-20 15:37:11 +02:00
|
|
|
void replot();
|
2024-01-20 21:03:02 +01:00
|
|
|
int rerenderFlags() const;
|
2023-05-20 20:58:38 +02:00
|
|
|
void setZoom(double level);
|
2023-05-20 17:12:33 +02:00
|
|
|
|
2023-06-16 18:24:22 +02:00
|
|
|
void hoverEnterEvent(QHoverEvent *event) override;
|
|
|
|
void hoverMoveEvent(QHoverEvent *event) override;
|
2023-05-20 17:12:33 +02:00
|
|
|
void wheelEvent(QWheelEvent *event) override;
|
|
|
|
void mousePressEvent(QMouseEvent *event) override;
|
|
|
|
void mouseMoveEvent(QMouseEvent *event) override;
|
|
|
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
2024-01-20 21:03:02 +01:00
|
|
|
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
|
|
|
void keyPressEvent(QKeyEvent *e) override;
|
2023-05-20 20:58:38 +02:00
|
|
|
|
2023-06-16 18:24:22 +02:00
|
|
|
ChartItemPtr<ToolTipItem> tooltip;
|
2023-07-06 16:08:19 +02:00
|
|
|
void updateTooltip(QPointF pos, bool plannerMode, int animSpeed);
|
|
|
|
std::unique_ptr<ProfileAnimation> tooltip_animation;
|
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
std::unique_ptr<RulerItem> ruler;
|
|
|
|
void updateRuler(int animSpeed);
|
|
|
|
std::unique_ptr<ProfileAnimation> ruler_animation;
|
|
|
|
|
2024-01-20 21:03:02 +01:00
|
|
|
void updateMouseFollowers(QPointF pos);
|
|
|
|
|
2023-08-12 22:59:56 +02:00
|
|
|
QPointF previousHoverMovePosition;
|
2024-01-20 21:03:02 +01:00
|
|
|
std::vector<std::unique_ptr<HandleItem>> handles;
|
|
|
|
int selectedHandleIdx;
|
|
|
|
void clearHandles();
|
|
|
|
void resetHandles();
|
|
|
|
void placeHandles();
|
|
|
|
void reindexHandles();
|
|
|
|
void moveHandle(int time, int depth);
|
|
|
|
void deleteHandle();
|
|
|
|
|
|
|
|
void pointsInserted(const QModelIndex &, int from, int to);
|
|
|
|
void pointsRemoved(const QModelIndex &, int start, int end);
|
|
|
|
void pointsMoved(const QModelIndex &, int start, int end, const QModelIndex &destination, int row);
|
2023-08-12 22:59:56 +02:00
|
|
|
|
|
|
|
// The list of pictures in this plot. The pictures are sorted by offset in seconds.
|
|
|
|
// For the same offset, sort by filename.
|
|
|
|
// Pictures that are outside of the dive time are not shown.
|
|
|
|
struct PictureEntry {
|
|
|
|
offset_t offset;
|
|
|
|
double x, y;
|
|
|
|
duration_t duration;
|
|
|
|
QString filename;
|
|
|
|
ChartItemPtr<PictureItem> thumbnail;
|
|
|
|
// For videos with known duration, we represent the duration of the video by a line
|
|
|
|
ChartItemPtr<ChartRectItem> durationLine;
|
|
|
|
std::unique_ptr<ProfileAnimation> animation;
|
|
|
|
PictureEntry (offset_t offset, const QString &filename, ChartItemPtr<PictureItem> thumbnail, double dpr, bool synchronous);
|
|
|
|
bool operator< (const PictureEntry &e) const;
|
|
|
|
};
|
|
|
|
std::vector<PictureEntry> pictures;
|
|
|
|
PictureEntry *highlightedPicture;
|
|
|
|
|
|
|
|
// Picture (media) related functions
|
|
|
|
void picturesRemoved(dive *d, QVector<QString> filenames);
|
|
|
|
void picturesAdded(dive *d, QVector<picture> pics);
|
|
|
|
void pictureOffsetChanged(dive *d, QString filename, offset_t offset);
|
|
|
|
void updateDurationLine(PictureEntry &e);
|
|
|
|
void updateThumbnail(QString filename, QImage thumbnail, duration_t duration);
|
|
|
|
void updateThumbnailPaintOrder();
|
|
|
|
void calculatePictureYPositions();
|
|
|
|
void updateThumbnailXPos(PictureEntry &e);
|
|
|
|
void plotPictures(const struct dive *d, bool synchronous);
|
|
|
|
void updateThumbnails();
|
|
|
|
void clearPictures();
|
|
|
|
void removePictureThumbnail(PictureEntry &entry);
|
|
|
|
void unhighlightPicture();
|
|
|
|
void shrinkPictureItem(PictureEntry &e, int animSpeed);
|
|
|
|
void growPictureItem(PictureEntry &e, int animSpeed);
|
|
|
|
void moveThumbnailBefore(PictureEntry &e, std::vector<PictureEntry>::iterator &before);
|
|
|
|
PictureEntry *getPictureUnderMouse(QPointF pos);
|
2023-06-16 18:24:22 +02:00
|
|
|
|
2023-05-20 20:58:38 +02:00
|
|
|
// For mobile
|
|
|
|
int getDiveId() const;
|
|
|
|
void setDiveId(int id);
|
|
|
|
int numDC() const;
|
|
|
|
void rotateDC(int dir);
|
2023-05-20 14:27:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|