diff --git a/profile-widget/diveeventitem.cpp b/profile-widget/diveeventitem.cpp
index c5848c9ea..38dc5f8de 100644
--- a/profile-widget/diveeventitem.cpp
+++ b/profile-widget/diveeventitem.cpp
@@ -19,6 +19,8 @@ static int depthAtTime(const plot_info &pi, duration_t time);
DiveEventItem::DiveEventItem(const struct dive *d, int idx, const struct event &ev, struct gasmix lastgasmix,
const plot_info &pi, DiveCartesianAxis *hAxis, DiveCartesianAxis *vAxis,
int speed, const DivePixmaps &pixmaps, QGraphicsItem *parent) : DivePixmapItem(parent),
+ text(setupToolTipString(d, ev, lastgasmix)),
+ pixmap(setupPixmap(d, ev, lastgasmix, pixmaps)),
vAxis(vAxis),
hAxis(hAxis),
idx(idx),
@@ -27,55 +29,42 @@ DiveEventItem::DiveEventItem(const struct dive *d, int idx, const struct event &
depth(depthAtTime(pi, ev.time))
{
setFlag(ItemIgnoresTransformations);
-
- setupPixmap(lastgasmix, pixmaps);
- setupToolTipString(lastgasmix);
+ setPixmap(pixmap);
recalculatePos();
+
+ if (ev.type == SAMPLE_EVENT_BOOKMARK)
+ setOffset(QPointF(0.0, -pixmap.height()));
}
DiveEventItem::~DiveEventItem()
{
}
-void DiveEventItem::setupPixmap(struct gasmix lastgasmix, const DivePixmaps &pixmaps)
+QPixmap DiveEventItem::setupPixmap(const struct dive *dive, const struct event &ev, struct gasmix lastgasmix, const DivePixmaps &pixmaps)
{
event_severity severity = ev.get_severity();
- if (ev.name.empty()) {
- setPixmap(pixmaps.warning);
- } else if (same_string_caseinsensitive(ev.name.c_str(), "modechange")) {
- if (ev.value == 0)
- setPixmap(pixmaps.bailout);
- else
- setPixmap(pixmaps.onCCRLoop);
- } else if (ev.type == SAMPLE_EVENT_BOOKMARK) {
- setPixmap(pixmaps.bookmark);
- setOffset(QPointF(0.0, -pixmap().height()));
- } else if (ev.is_gaschange()) {
+ if (ev.name.empty())
+ return pixmaps.warning;
+
+ if (same_string_caseinsensitive(ev.name.c_str(), "modechange"))
+ return ev.value == 0 ? pixmaps.bailout : pixmaps.onCCRLoop;
+
+ if (ev.type == SAMPLE_EVENT_BOOKMARK)
+ return pixmaps.bookmark;
+
+ if (ev.is_gaschange()) {
struct gasmix mix = dive->get_gasmix_from_event(ev);
struct icd_data icd_data;
bool icd = isobaric_counterdiffusion(lastgasmix, mix, &icd_data);
- if (mix.he.permille) {
- if (icd)
- setPixmap(pixmaps.gaschangeTrimixICD);
- else
- setPixmap(pixmaps.gaschangeTrimix);
- } else if (gasmix_is_air(mix)) {
- if (icd)
- setPixmap(pixmaps.gaschangeAirICD);
- else
- setPixmap(pixmaps.gaschangeAir);
- } else if (mix.o2.permille == 1000) {
- if (icd)
- setPixmap(pixmaps.gaschangeOxygenICD);
- else
- setPixmap(pixmaps.gaschangeOxygen);
- } else {
- if (icd)
- setPixmap(pixmaps.gaschangeEANICD);
- else
- setPixmap(pixmaps.gaschangeEAN);
- }
- } else if ((((ev.flags & SAMPLE_FLAGS_SEVERITY_MASK) >> SAMPLE_FLAGS_SEVERITY_SHIFT) == 1) ||
+ if (mix.he.permille)
+ return icd ? pixmaps.gaschangeTrimixICD : pixmaps.gaschangeTrimix;
+ if (gasmix_is_air(mix))
+ return icd ? pixmaps.gaschangeAirICD : pixmaps.gaschangeAir;
+ if (mix.o2.permille == 1000)
+ return icd ? pixmaps.gaschangeOxygenICD : pixmaps.gaschangeOxygen;
+ return icd ? pixmaps.gaschangeEANICD : pixmaps.gaschangeEAN;
+ }
+ if ((((ev.flags & SAMPLE_FLAGS_SEVERITY_MASK) >> SAMPLE_FLAGS_SEVERITY_SHIFT) == 1) ||
// those are useless internals of the dive computer
same_string_caseinsensitive(ev.name.c_str(), "heading") ||
(same_string_caseinsensitive(ev.name.c_str(), "SP change") && ev.time.seconds == 0)) {
@@ -86,35 +75,35 @@ void DiveEventItem::setupPixmap(struct gasmix lastgasmix, const DivePixmaps &pix
// so set an "almost invisible" pixmap (a narrow but somewhat tall, basically transparent pixmap)
// that allows tooltips to work when we don't want to show a specific
// pixmap for an event, but want to show the event value in the tooltip
- setPixmap(pixmaps.transparent);
- } else if (severity == EVENT_SEVERITY_INFO) {
- setPixmap(pixmaps.info);
- } else if (severity == EVENT_SEVERITY_WARN) {
- setPixmap(pixmaps.warning);
- } else if (severity == EVENT_SEVERITY_ALARM) {
- setPixmap(pixmaps.violation);
- } else if (same_string_caseinsensitive(ev.name.c_str(), "violation") || // generic libdivecomputer
+ return pixmaps.transparent;
+ }
+ if (severity == EVENT_SEVERITY_INFO)
+ return pixmaps.info;
+ if (severity == EVENT_SEVERITY_WARN)
+ return pixmaps.warning;
+ if (severity == EVENT_SEVERITY_ALARM)
+ return pixmaps.violation;
+ if (same_string_caseinsensitive(ev.name.c_str(), "violation") || // generic libdivecomputer
same_string_caseinsensitive(ev.name.c_str(), "Safety stop violation") || // the rest are from the Uemis downloader
same_string_caseinsensitive(ev.name.c_str(), "pO₂ ascend alarm") ||
same_string_caseinsensitive(ev.name.c_str(), "RGT alert") ||
same_string_caseinsensitive(ev.name.c_str(), "Dive time alert") ||
same_string_caseinsensitive(ev.name.c_str(), "Low battery alert") ||
- same_string_caseinsensitive(ev.name.c_str(), "Speed alarm")) {
- setPixmap(pixmaps.violation);
- } else if (same_string_caseinsensitive(ev.name.c_str(), "non stop time") || // generic libdivecomputer
- same_string_caseinsensitive(ev.name.c_str(), "safety stop") ||
- same_string_caseinsensitive(ev.name.c_str(), "safety stop (voluntary)") ||
- same_string_caseinsensitive(ev.name.c_str(), "Tank change suggested") || // Uemis downloader
- same_string_caseinsensitive(ev.name.c_str(), "Marker")) {
- setPixmap(pixmaps.info);
- } else {
- // we should do some guessing based on the type / name of the event;
- // for now they all get the warning icon
- setPixmap(pixmaps.warning);
- }
+ same_string_caseinsensitive(ev.name.c_str(), "Speed alarm"))
+ return pixmaps.violation;
+ if (same_string_caseinsensitive(ev.name.c_str(), "non stop time") || // generic libdivecomputer
+ same_string_caseinsensitive(ev.name.c_str(), "safety stop") ||
+ same_string_caseinsensitive(ev.name.c_str(), "safety stop (voluntary)") ||
+ same_string_caseinsensitive(ev.name.c_str(), "Tank change suggested") || // Uemis downloader
+ same_string_caseinsensitive(ev.name.c_str(), "Marker"))
+ return pixmaps.info;
+
+ // we should do some guessing based on the type / name of the event;
+ // for now they all get the warning icon
+ return pixmaps.warning;
}
-void DiveEventItem::setupToolTipString(struct gasmix lastgasmix)
+QString DiveEventItem::setupToolTipString(const struct dive *dive, const struct event &ev, struct gasmix lastgasmix)
{
// we display the event on screen - so translate
QString name = gettextFromC::tr(ev.name.c_str());
@@ -158,7 +147,7 @@ void DiveEventItem::setupToolTipString(struct gasmix lastgasmix)
name += ev.flags & SAMPLE_FLAGS_BEGIN ? tr(" begin", "Starts with space!") :
ev.flags & SAMPLE_FLAGS_END ? tr(" end", "Starts with space!") : "";
}
- setToolTip(QString("
") + name);
+ return name;
}
void DiveEventItem::eventVisibilityChanged(const QString&, bool)
diff --git a/profile-widget/diveeventitem.h b/profile-widget/diveeventitem.h
index 215ae4eb0..ea21181e9 100644
--- a/profile-widget/diveeventitem.h
+++ b/profile-widget/diveeventitem.h
@@ -23,10 +23,11 @@ public:
static bool isInteresting(const struct dive *d, const struct divecomputer *dc,
const struct event &ev, const struct plot_info &pi,
int firstSecond, int lastSecond);
-
+ const QString text;
+ const QPixmap pixmap;
private:
- void setupToolTipString(struct gasmix lastgasmix);
- void setupPixmap(struct gasmix lastgasmix, const DivePixmaps &pixmaps);
+ static QString setupToolTipString(const struct dive *d, const struct event &ev, struct gasmix lastgasmix);
+ static QPixmap setupPixmap(const struct dive *d, const struct event &ev, struct gasmix lastgasmix, const DivePixmaps &pixmaps);
void recalculatePos();
DiveCartesianAxis *vAxis;
DiveCartesianAxis *hAxis;
diff --git a/profile-widget/profilescene.cpp b/profile-widget/profilescene.cpp
index bb44ce371..ff6c78fe1 100644
--- a/profile-widget/profilescene.cpp
+++ b/profile-widget/profilescene.cpp
@@ -615,3 +615,14 @@ int ProfileScene::timeAt(QPointF pos) const
{
return lrint(timeAxis->valueAt(pos));
}
+
+std::vector> ProfileScene::eventsAt(QPointF pos) const
+{
+ std::vector> res;
+ for (const auto &item: eventItems) {
+ if (!item->contains(item->mapFromScene(pos)))
+ continue;
+ res.emplace_back(item->text, item->pixmap);
+ }
+ return res;
+}
diff --git a/profile-widget/profilescene.h b/profile-widget/profilescene.h
index 33488b841..b65aa1a58 100644
--- a/profile-widget/profilescene.h
+++ b/profile-widget/profilescene.h
@@ -50,6 +50,7 @@ public:
double calcZoomPosition(double zoom, double originalPos, double delta);
const plot_info &getPlotInfo() const;
int timeAt(QPointF pos) const;
+ std::vector> eventsAt(QPointF pos) const;
const struct dive *d;
int dc;
diff --git a/profile-widget/profileview.cpp b/profile-widget/profileview.cpp
index 3033989dd..5ea1cdb30 100644
--- a/profile-widget/profileview.cpp
+++ b/profile-widget/profileview.cpp
@@ -184,8 +184,6 @@ void ProfileView::plotDive(const struct dive *dIn, int dcIn, int flags)
//else
//plotPicturesInternal(d, flags & RenderFlags::Instant);
- //toolTipItem->refresh(d, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN);
-
update();
// OK, how long did this take us? Anything above the second is way too long,
@@ -201,8 +199,9 @@ void ProfileView::plotDive(const struct dive *dIn, int dcIn, int flags)
if (!tooltip)
tooltip = createChartItem(dpr);
if (prefs.infobox) {
+ QPoint pos = mapFromGlobal(QCursor::pos()).toPoint();
tooltip->setVisible(true);
- tooltip->update(d, dpr, 0, profileScene->getPlotInfo(), flags & RenderFlags::PlanMode);
+ updateTooltip(pos, flags & RenderFlags::PlanMode);
} else {
tooltip->setVisible(false);
}
@@ -296,8 +295,6 @@ void ProfileView::mouseMoveEvent(QMouseEvent *event)
if (panning)
pan(pos.x(), pos.y());
- //toolTipItem->refresh(d, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN);
-
//if (currentState == PLAN || currentState == EDIT) {
//QRectF rect = profileScene->profileRegion;
//auto [miny, maxy] = profileScene->profileYAxis->screenMinMax();
@@ -378,14 +375,15 @@ void ProfileView::hoverMoveEvent(QHoverEvent *event)
{
if (!profileScene)
return;
- QPointF pos = event->pos();
- int time = profileScene->timeAt(pos);
- bool requires_update = false;
- if (tooltip) {
- tooltip->update(d, dpr, time, profileScene->getPlotInfo(), false); // TODO: plan mode
- requires_update = true;
- }
-
- if (requires_update)
+ if (tooltip && prefs.infobox) {
+ updateTooltip(event->pos(), false); // TODO: plan mode
update();
+ }
+}
+
+void ProfileView::updateTooltip(QPointF pos, bool plannerMode)
+{
+ int time = profileScene->timeAt(pos);
+ auto events = profileScene->eventsAt(pos);
+ tooltip->update(d, dpr, time, profileScene->getPlotInfo(), events, plannerMode);
}
diff --git a/profile-widget/profileview.h b/profile-widget/profileview.h
index 5aaf449bc..8d70a0479 100644
--- a/profile-widget/profileview.h
+++ b/profile-widget/profileview.h
@@ -74,6 +74,7 @@ private:
void mouseReleaseEvent(QMouseEvent *event) override;
ChartItemPtr tooltip;
+ void updateTooltip(QPointF pos, bool plannerMode);
// For mobile
int getDiveId() const;
diff --git a/profile-widget/tooltipitem.cpp b/profile-widget/tooltipitem.cpp
index f9dba6783..906c9d572 100644
--- a/profile-widget/tooltipitem.cpp
+++ b/profile-widget/tooltipitem.cpp
@@ -99,19 +99,13 @@ static QPixmap drawTissues(const plot_info &pInfo, double dpr, int idx, bool inP
return tissues.scaled(new_width, new_height);
}
-void ToolTipItem::update(const dive *d, double dpr, int time, const plot_info &pInfo, bool inPlanner)
+void ToolTipItem::update(const dive *d, double dpr, int time, const plot_info &pInfo,
+ const std::vector> &events, bool inPlanner)
{
auto [idx, lines] = get_plot_details_new(d, pInfo, time);
QPixmap tissues = drawTissues(pInfo, dpr, idx, inPlanner);
-
- //TODO: add event tool tips!
- //const auto l = scene()->items(pos, Qt::IntersectsItemBoundingRect, Qt::DescendingOrder,
- //scene()->views().first()->transform());
- //for (QGraphicsItem *item: l) {
- //if (!item->toolTip().isEmpty())
- //addToolTip(item->toolTip(), QPixmap());
- //}
+ std::vector event_sizes;
width = title.size().width();
@@ -125,12 +119,21 @@ void ToolTipItem::update(const dive *d, double dpr, int time, const plot_info &p
strings.push_back(std::make_pair(s, w));
}
+ height = (static_cast(strings.size()) + 1.0) * fontHeight;
+
+ for (auto &[s, pixmap]: events) {
+ double text_width = fm.size(Qt::TextSingleLine, s).width();
+ double total_width = pixmap.width() + text_width;
+ double h = std::max(static_cast(pixmap.height()), fontHeight);
+ width = std::max(width, total_width);
+ height += h;
+ event_sizes.emplace_back(text_width, h);
+ }
+
width += tissues.width();
width += 6.0 * tooltipBorder;
-
- height = 4.0 * tooltipBorder + title.height() +
- std::max((static_cast(strings.size()) + 1.0) * fontHeight,
- static_cast(tissues.height()));
+ height = std::max(height, static_cast(tissues.height()));
+ height += 4.0 * tooltipBorder + title.height();
ChartRectItem::resize(QSizeF(width, height));
painter->setFont(font);
@@ -147,6 +150,15 @@ void ToolTipItem::update(const dive *d, double dpr, int time, const plot_info &p
painter->drawText(rect, s);
y += fontHeight;
}
+ for (size_t i = 0; i < events.size(); ++i) {
+ QSizeF size = event_sizes[i];
+ auto &[s, pixmap] = events[i];
+ painter->drawPixmap(lrint(x), lrint(y + (size.height() - pixmap.height())/2.0), pixmap,
+ 0, 0, pixmap.width(), pixmap.height());
+ QRectF rect(x + pixmap.width(), round(y + (size.height() - fontHeight) / 2.0), size.width(), fontHeight);
+ painter->drawText(rect, s);
+ y += size.height();
+ }
setTextureDirty();
}
diff --git a/profile-widget/tooltipitem.h b/profile-widget/tooltipitem.h
index 6bddae805..5e58529eb 100644
--- a/profile-widget/tooltipitem.h
+++ b/profile-widget/tooltipitem.h
@@ -13,7 +13,8 @@ struct plot_info;
class ToolTipItem : public ChartRectItem {
public:
ToolTipItem(ChartView &view, double dpr);
- void update(const dive *d, double dpr, int time, const plot_info &pInfo, bool inPlanner);
+ void update(const dive *d, double dpr, int time, const plot_info &pInfo,
+ const std::vector> &events, bool inPlanner);
private:
QFont font;
QFontMetrics fm;