mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
profile: show events in ToolTipItem
Reimplement a feature that was lost when porting the ToolTipOtem to QtQuick. This is a bit of a longer commit, because the icon of the event is now drawn explicitly, instead of using HTML. This encompasses a UI change: the icon is now the icon shown on the profile and not a general "warning" icon. This commit also fixes update of the tooltip when panning the profile. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
c6eeeb7d28
commit
06b0a7eeae
8 changed files with 105 additions and 91 deletions
|
@ -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("<img height=\"16\" src=\":status-warning-icon\"> ") + name);
|
||||
return name;
|
||||
}
|
||||
|
||||
void DiveEventItem::eventVisibilityChanged(const QString&, bool)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -615,3 +615,14 @@ int ProfileScene::timeAt(QPointF pos) const
|
|||
{
|
||||
return lrint(timeAxis->valueAt(pos));
|
||||
}
|
||||
|
||||
std::vector<std::pair<QString, QPixmap>> ProfileScene::eventsAt(QPointF pos) const
|
||||
{
|
||||
std::vector<std::pair<QString, QPixmap>> res;
|
||||
for (const auto &item: eventItems) {
|
||||
if (!item->contains(item->mapFromScene(pos)))
|
||||
continue;
|
||||
res.emplace_back(item->text, item->pixmap);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -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<std::pair<QString, QPixmap>> eventsAt(QPointF pos) const;
|
||||
|
||||
const struct dive *d;
|
||||
int dc;
|
||||
|
|
|
@ -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<ToolTipItem>(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);
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ private:
|
|||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
|
||||
ChartItemPtr<ToolTipItem> tooltip;
|
||||
void updateTooltip(QPointF pos, bool plannerMode);
|
||||
|
||||
// For mobile
|
||||
int getDiveId() const;
|
||||
|
|
|
@ -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<std::pair<QString, QPixmap>> &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<QSizeF> 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<double>(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<double>(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<double>(strings.size()) + 1.0) * fontHeight,
|
||||
static_cast<double>(tissues.height()));
|
||||
height = std::max(height, static_cast<double>(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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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<std::pair<QString, QPixmap>> &events, bool inPlanner);
|
||||
private:
|
||||
QFont font;
|
||||
QFontMetrics fm;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue