diff --git a/core/divecomputer.cpp b/core/divecomputer.cpp index 2a5acba21..bfbc08220 100644 --- a/core/divecomputer.cpp +++ b/core/divecomputer.cpp @@ -334,6 +334,12 @@ struct event *get_event(struct divecomputer *dc, int idx) return &dc->events[idx]; } +bool divecomputer::has_individually_hidden_events() const +{ + return std::any_of(events.begin(), events.end(), + [] (const event &ev) { return ev.hidden; }); +} + void add_extra_data(struct divecomputer *dc, const std::string &key, const std::string &value) { if (key == "Serial") { diff --git a/core/divecomputer.h b/core/divecomputer.h index 074b36bcd..9041e6aa9 100644 --- a/core/divecomputer.h +++ b/core/divecomputer.h @@ -44,6 +44,8 @@ struct divecomputer { std::vector events; std::vector extra_data; + bool has_individually_hidden_events() const; + divecomputer(); ~divecomputer(); divecomputer(const divecomputer &); diff --git a/core/event.h b/core/event.h index d96df5733..22f8b0c0b 100644 --- a/core/event.h +++ b/core/event.h @@ -64,6 +64,8 @@ public: const struct event *next(); // nullptr -> end }; +extern bool has_individually_hidden_events(const struct divecomputer *dc); + /* Get gasmixes at increasing timestamps. */ class gasmix_loop { const struct dive &dive; diff --git a/core/eventtype.cpp b/core/eventtype.cpp index 4352707af..5eff7d869 100644 --- a/core/eventtype.cpp +++ b/core/eventtype.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "eventtype.h" #include "event.h" +#include "divecomputer.h" #include "gettextfromc.h" #include "subsurface-string.h" @@ -42,9 +43,9 @@ void remember_event_type(const struct event *ev) event_types.push_back(std::move(type)); } -bool is_event_type_hidden(const struct event *ev) +bool is_event_type_hidden(const struct event &ev) { - auto it = std::find(event_types.begin(), event_types.end(), ev); + auto it = std::find(event_types.begin(), event_types.end(), &ev); return it != event_types.end() && !it->plot; } @@ -55,10 +56,18 @@ void hide_event_type(const struct event *ev) it->plot = false; } -void show_all_event_types() +static bool has_event_type(const divecomputer &dc, const event_type &et) { - for (event_type &e: event_types) - e.plot = true; + return std::any_of(dc.events.begin(), dc.events.end(), [&et] (const event &ev) + { return ev.name == et.name && ev.get_severity() == et.severity; }); +} + +void show_all_event_types(const divecomputer &dc) +{ + for (event_type &e: event_types) { + if (!e.plot && has_event_type(dc, e)) + e.plot = true; + } } void show_event_type(int idx) @@ -74,11 +83,12 @@ bool any_event_types_hidden() [] (const event_type &e) { return !e.plot; }); } -extern std::vector hidden_event_types() +std::vector hidden_event_types(const struct divecomputer &dc) { std::vector res; for (size_t i = 0; i < event_types.size(); ++i) { - if (!event_types[i].plot) + const event_type &e = event_types[i]; + if (!e.plot && has_event_type(dc, e)) res.push_back(i); } return res; diff --git a/core/eventtype.h b/core/eventtype.h index 6b9f843d3..3424259e7 100644 --- a/core/eventtype.h +++ b/core/eventtype.h @@ -8,12 +8,12 @@ extern void clear_event_types(); extern void remember_event_type(const struct event *ev); -extern bool is_event_type_hidden(const struct event *ev); +extern bool is_event_type_hidden(const struct event &ev); extern void hide_event_type(const struct event *ev); -extern void show_all_event_types(); +extern void show_all_event_types(const struct divecomputer &dc); extern void show_event_type(int idx); extern bool any_event_types_hidden(); -extern std::vector hidden_event_types(); +extern std::vector hidden_event_types(const struct divecomputer &dc); extern QString event_type_name(const event &ev); extern QString event_type_name(int idx); diff --git a/profile-widget/diveeventitem.cpp b/profile-widget/diveeventitem.cpp index 1fbe46d1e..f0d3ac1da 100644 --- a/profile-widget/diveeventitem.cpp +++ b/profile-widget/diveeventitem.cpp @@ -205,7 +205,7 @@ void DiveEventItem::recalculatePos() hide(); return; } - setVisible(!ev.hidden && !is_event_type_hidden(&ev)); + setVisible(!ev.hidden && !is_event_type_hidden(ev)); double x = hAxis->posAtValue(ev.time.seconds); double y = vAxis->posAtValue(depth); setPos(x, y); diff --git a/profile-widget/divetextitem.cpp b/profile-widget/divetextitem.cpp index b032591e1..b92f30f98 100644 --- a/profile-widget/divetextitem.cpp +++ b/profile-widget/divetextitem.cpp @@ -90,6 +90,11 @@ double DiveTextItem::fontHeight(double dpr, double scale) return (double)fm.height(); } +double DiveTextItem::width() const +{ + return boundingRect().width(); +} + double DiveTextItem::height() const { return fontHeight(dpr, scale) + outlineSize * dpr; diff --git a/profile-widget/divetextitem.h b/profile-widget/divetextitem.h index 9e65f8b54..b1924fcf0 100644 --- a/profile-widget/divetextitem.h +++ b/profile-widget/divetextitem.h @@ -17,6 +17,7 @@ public: const QString &text(); static double fontHeight(double dpr, double scale); static std::pair getLabelSize(double dpr, double scale, const QString &label); + double width() const; double height() const; private: diff --git a/profile-widget/profilescene.cpp b/profile-widget/profilescene.cpp index 91ecb455b..1ebf77619 100644 --- a/profile-widget/profilescene.cpp +++ b/profile-widget/profilescene.cpp @@ -11,6 +11,7 @@ #include "core/device.h" #include "core/divecomputer.h" #include "core/event.h" +#include "core/eventtype.h" #include "core/pref.h" #include "core/profile.h" #include "core/qthelper.h" // for decoMode() @@ -95,6 +96,7 @@ ProfileScene::ProfileScene(double dpr, bool printMode, bool isGrayscale) : [](const plot_data &item) { return 0.0; }, // unused 1, dpr)), diveComputerText(new DiveTextItem(dpr, 1.0, Qt::AlignRight | Qt::AlignTop, nullptr)), + eventsHiddenText(new DiveTextItem(dpr, 1.0, Qt::AlignRight | Qt::AlignTop, nullptr)), reportedCeiling(createItem(*profileYAxis, [](const plot_data &item) { return (double)item.ceiling; }, 1, dpr)), @@ -143,6 +145,7 @@ ProfileScene::ProfileScene(double dpr, bool printMode, bool isGrayscale) : // Add items to scene addItem(diveComputerText); + addItem(eventsHiddenText); addItem(tankItem); addItem(decoModelParameters); addItem(profileYAxis); @@ -156,6 +159,8 @@ ProfileScene::ProfileScene(double dpr, bool printMode, bool isGrayscale) : for (AbstractProfilePolygonItem *item: profileItems) addItem(item); + + eventsHiddenText->set(tr("Hidden events!"), getColor(TIME_TEXT, isGrayscale)); } ProfileScene::~ProfileScene() @@ -287,8 +292,10 @@ void ProfileScene::updateAxes(bool diveHasHeartBeat, bool simplified) profileYAxis->setGridIsMultipleOfThree( qPrefDisplay::three_m_based_grid() ); // Place the fixed dive computer text at the bottom - double bottomBorder = sceneRect().height() - diveComputerText->height() - 2.0 * dpr * diveComputerTextBorder; - diveComputerText->setPos(0.0, bottomBorder + dpr * diveComputerTextBorder); + double bottomTextHeight = std::max(diveComputerText->height(), eventsHiddenText->height()); + double bottomBorder = sceneRect().height() - bottomTextHeight - 2.0 * dpr * diveComputerTextBorder; + diveComputerText->setPos(0.0, round(bottomBorder + dpr * diveComputerTextBorder)); + eventsHiddenText->setPos(width - dpr * diveComputerTextBorder - eventsHiddenText->width(), bottomBorder + dpr * diveComputerTextBorder); double topBorder = 0.0; @@ -372,6 +379,12 @@ bool ProfileScene::pointOnDiveComputerText(const QPointF &point) const return diveComputerText->boundingRect().contains(point - diveComputerText->pos()); } +bool ProfileScene::pointOnEventsHiddenText(const QPointF &point) const +{ + return eventsHiddenText->isVisible() && + eventsHiddenText->boundingRect().contains(point - eventsHiddenText->pos()); +} + static double max_gas(const plot_info &pi, double gas_pressures::*gas) { double ret = -1; @@ -525,9 +538,12 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, int animSpeed, boo eventItems.clear(); struct gasmix lastgasmix = d->get_gasmix_at_time(*currentdc, 1_sec); + bool has_hidden_events = false; for (auto [idx, event]: enumerated_range(currentdc->events)) { - if (event.hidden) + if (event.hidden || is_event_type_hidden(event)) { + has_hidden_events = true; continue; + } // if print mode is selected only draw headings, SP change, gas events or bookmark event if (printMode) { if (event.name.empty() || @@ -547,6 +563,7 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, int animSpeed, boo if (event.is_gaschange()) lastgasmix = d->get_gasmix_from_event(event); } + eventsHiddenText->setVisible(has_hidden_events); QString dcText = QString::fromStdString(get_dc_nickname(currentdc)); if (is_dc_planner(currentdc)) diff --git a/profile-widget/profilescene.h b/profile-widget/profilescene.h index ff07f4382..fc3882f09 100644 --- a/profile-widget/profilescene.h +++ b/profile-widget/profilescene.h @@ -38,6 +38,7 @@ public: void clear(); bool pointOnProfile(const QPointF &point) const; bool pointOnDiveComputerText(const QPointF &point) const; + bool pointOnEventsHiddenText(const QPointF &point) const; void anim(double fraction); // Called by the animation with 0.0-1.0 (start to stop). // Can be compared with literal 1.0 to determine "end" state. @@ -96,6 +97,7 @@ private: DiveGasPressureItem *gasPressureItem; std::vector> eventItems; DiveTextItem *diveComputerText; + DiveTextItem *eventsHiddenText; DiveReportedCeiling *reportedCeiling; PartialPressureGasItem *pn2GasItem; PartialPressureGasItem *pheGasItem; diff --git a/profile-widget/profileview.cpp b/profile-widget/profileview.cpp index f43fa37fc..072b19620 100644 --- a/profile-widget/profileview.cpp +++ b/profile-widget/profileview.cpp @@ -509,6 +509,16 @@ static QString formatCylinderDescription(int i, const cylinder_t &cylinder) return label; } +void ProfileView::unhideEvents() +{ + if (!d) + return; + struct divecomputer *currentdc = mutable_dive()->get_dc(dc); + for (auto &ev: currentdc->events) + ev.hidden = false; + replot(); +} + void ProfileView::mousePressEvent(QMouseEvent *event) { // Handle dragging of items @@ -541,6 +551,34 @@ void ProfileView::mousePressEvent(QMouseEvent *event) return execMenu(m, event->globalPos()); } + // Open context menu for event unhiding + if (d && profileScene->pointOnEventsHiddenText(event->pos())) { + std::vector m; + const struct divecomputer *currentdc = d->get_dc(dc); + if (currentdc->has_individually_hidden_events()) { + m.emplace_back(tr("Unhide individually hidden events of this dive"), [this, ¤tdc] { + unhideEvents(); + }); + } + std::vector types = hidden_event_types(*currentdc); + if (!types.empty()) { + std::vector m2; + for (int i: types) { + m2.emplace_back(event_type_name(i), [this, i]() { + show_event_type(i); + replot(); + }); + } + if (types.size() > 1) { + m2.emplace_back(tr("All types"), [this, currentdc]() { + show_all_event_types(*currentdc); + replot(); + }); + } + m.emplace_back(tr("Unhide event type"), std::move(m2)); + } + return execMenu(m, event->globalPos()); + } DiveEventItem *item = profileScene->eventAtPosition(event->pos()); if (d && item) { std::vector m; diff --git a/profile-widget/profileview.h b/profile-widget/profileview.h index c0929a8f5..26ac67cfa 100644 --- a/profile-widget/profileview.h +++ b/profile-widget/profileview.h @@ -142,6 +142,7 @@ private: void hideEvent(DiveEventItem &item); void hideEventType(DiveEventItem &item); void removeEvent(DiveEventItem &item); + void unhideEvents(); // The list of pictures in this plot. The pictures are sorted by offset in seconds. // For the same offset, sort by filename. diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp index 82d416138..562f510b5 100644 --- a/profile-widget/profilewidget2.cpp +++ b/profile-widget/profilewidget2.cpp @@ -370,43 +370,9 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event) changeMode->addAction(gettextFromC::tr(divemode_text_ui[PSCR]), [this, seconds](){ addDivemodeSwitch(seconds, PSCR); }); - if (any_event_types_hidden()) { - QMenu *m2 = m.addMenu(tr("Unhide event type")); - for (int i: hidden_event_types()) { - m2->addAction(event_type_name(i), [this, i]() { - show_event_type(i); - replot(); - }); - } - m2->addAction(tr("All event types"), this, &ProfileWidget2::unhideEventTypes); - } - const struct divecomputer *currentdc = d->get_dc(dc); - if (currentdc && std::any_of(currentdc->events.begin(), currentdc->events.end(), - [] (auto &ev) { return ev.hidden; })) - m.addAction(tr("Unhide individually hidden events of this dive"), this, &ProfileWidget2::unhideEvents); m.exec(event->globalPos()); } -void ProfileWidget2::unhideEvents() -{ - if (!d) - return; - struct divecomputer *currentdc = mutable_dive()->get_dc(dc); - if (!currentdc) - return; - for (auto &ev: currentdc->events) - ev.hidden = false; - for (DiveEventItem *item: profileScene->eventItems) - item->show(); -} - -void ProfileWidget2::unhideEventTypes() -{ - show_all_event_types(); - - replot(); -} - void ProfileWidget2::addBookmark(int seconds) { if (d) diff --git a/profile-widget/profilewidget2.h b/profile-widget/profilewidget2.h index 7ddb885b3..4881a1238 100644 --- a/profile-widget/profilewidget2.h +++ b/profile-widget/profilewidget2.h @@ -109,8 +109,6 @@ private: void addSetpointChange(int seconds); void removeEvent(DiveEventItem *item); void editName(DiveEventItem *item); - void unhideEvents(); - void unhideEventTypes(); void makeFirstDC(); void deleteCurrentDC(); void splitCurrentDC();