From 0bf1d35a4b9e8f2755d5b68749a60aabfae408d1 Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Fri, 1 Mar 2024 13:02:35 +0100 Subject: [PATCH] profile: port event unhiding to QtQuick This has UI changes: - The unhiding options are accessed by a field that appears when there are hidden events. - Only event-types of this particular dive are unhidden. Signed-off-by: Berthold Stoeger --- core/event.c | 10 ++++++++ core/event.h | 3 +++ core/eventtype.cpp | 30 +++++++++++++++--------- core/eventtype.h | 7 +++--- profile-widget/diveeventitem.cpp | 2 -- profile-widget/divetextitem.cpp | 5 ++++ profile-widget/divetextitem.h | 1 + profile-widget/profilescene.cpp | 23 ++++++++++++++++--- profile-widget/profilescene.h | 2 ++ profile-widget/profileview.cpp | 38 +++++++++++++++++++++++++++++++ profile-widget/profileview.h | 1 + profile-widget/profilewidget2.cpp | 28 ----------------------- profile-widget/profilewidget2.h | 2 -- 13 files changed, 103 insertions(+), 49 deletions(-) diff --git a/core/event.c b/core/event.c index dd5551761..ad8c2f876 100644 --- a/core/event.c +++ b/core/event.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "event.h" #include "eventtype.h" +#include "divecomputer.h" #include "subsurface-string.h" #include @@ -116,3 +117,12 @@ extern enum event_severity get_event_severity(const struct event *ev) return EVENT_SEVERITY_NONE; } } + +extern bool has_individually_hidden_events(const struct divecomputer *dc) +{ + for (const struct event *ev = dc->events; ev; ev = ev->next) { + if (ev->hidden) + return true; + } + return false; +} diff --git a/core/event.h b/core/event.h index fc8a03d64..ff3b4890d 100644 --- a/core/event.h +++ b/core/event.h @@ -8,6 +8,8 @@ #include +struct divecomputer; + #ifdef __cplusplus extern "C" { #endif @@ -55,6 +57,7 @@ extern struct event *create_event(unsigned int time, int type, int flags, int va extern struct event *clone_event_rename(const struct event *ev, const char *name); extern bool same_event(const struct event *a, const struct event *b); extern enum event_severity get_event_severity(const struct event *ev); +extern bool has_individually_hidden_events(const struct divecomputer *dc); /* Since C doesn't have parameter-based overloading, two versions of get_next_event. */ extern const struct event *get_next_event(const struct event *event, const char *name); diff --git a/core/eventtype.cpp b/core/eventtype.cpp index 5e88480a1..1356e4da3 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" @@ -55,10 +56,22 @@ extern "C" void hide_event_type(const struct event *ev) it->plot = false; } -extern "C" 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; + for (const event *ev = dc->events; ev; ev = ev->next) { + if (ev->name == et.name && + get_event_severity(ev) == et.severity) + return true; + } + return false; +} + +extern "C" 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; + } } extern "C" void show_event_type(int idx) @@ -68,17 +81,12 @@ extern "C" void show_event_type(int idx) event_types[idx].plot = true; } -extern "C" bool any_event_types_hidden() -{ - return std::any_of(event_types.begin(), event_types.end(), - [] (const event_type &e) { return !e.plot; }); -} - -extern std::vector hidden_event_types() +extern std::vector hidden_event_types(const 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 8f5a8f5ac..0acaff6ca 100644 --- a/core/eventtype.h +++ b/core/eventtype.h @@ -3,6 +3,8 @@ #ifndef EVENTNAME_H #define EVENTNAME_H +struct divecomputer; + #ifdef __cplusplus extern "C" { #endif @@ -11,9 +13,8 @@ extern void clear_event_types(void); extern void remember_event_type(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(); #ifdef __cplusplus } @@ -22,7 +23,7 @@ extern bool any_event_types_hidden(); #include #include -extern std::vector hidden_event_types(); +extern std::vector hidden_event_types(const divecomputer *dc); QString event_type_name(const event *ev); QString event_type_name(int idx); diff --git a/profile-widget/diveeventitem.cpp b/profile-widget/diveeventitem.cpp index 9550514b8..87ebeac07 100644 --- a/profile-widget/diveeventitem.cpp +++ b/profile-widget/diveeventitem.cpp @@ -4,7 +4,6 @@ #include "profile-widget/divepixmapcache.h" #include "profile-widget/animationfunctions.h" #include "core/event.h" -#include "core/eventtype.h" #include "core/format.h" #include "core/profile.h" #include "core/gettextfromc.h" @@ -217,7 +216,6 @@ void DiveEventItem::recalculatePos() hide(); return; } - 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 0d93aaabf..f23c712e7 100644 --- a/profile-widget/profilescene.cpp +++ b/profile-widget/profilescene.cpp @@ -9,6 +9,7 @@ #include "tankitem.h" #include "core/device.h" #include "core/event.h" +#include "core/eventtype.h" #include "core/pref.h" #include "core/profile.h" #include "core/qthelper.h" // for decoMode() @@ -92,6 +93,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)), @@ -142,6 +144,7 @@ ProfileScene::ProfileScene(double dpr, bool printMode, bool isGrayscale) : // Add items to scene addItem(diveComputerText); + addItem(eventsHiddenText); addItem(tankItem); addItem(decoModelParameters); addItem(profileYAxis); @@ -155,6 +158,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 = get_gasmix_at_time(d, currentdc, duration_t{1}); + bool has_hidden_events = false; for (struct event *event = currentdc->events; event; event = event->next) { - 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 (empty_string(event->name) || @@ -548,6 +564,7 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, int animSpeed, boo if (event_is_gaschange(event)) lastgasmix = get_gasmix_from_event(d, event); } + eventsHiddenText->setVisible(has_hidden_events); QString dcText = get_dc_nickname(currentdc); if (dcText == "planned dive") 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 d550fd06c..e395ec187 100644 --- a/profile-widget/profileview.cpp +++ b/profile-widget/profileview.cpp @@ -474,6 +474,16 @@ static QString formatCylinderDescription(int i, const cylinder_t *cylinder) return label; } +void ProfileView::unhideEvents() +{ + if (!d) + return; + const struct divecomputer *currentdc = get_dive_dc_const(d, dc); + for (struct event *ev = currentdc->events; ev; ev = ev->next) + ev->hidden = false; + replot(); +} + void ProfileView::mousePressEvent(QMouseEvent *event) { // Handle dragging of items @@ -506,6 +516,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 = get_dive_dc_const(d, dc); + if (has_individually_hidden_events(currentdc)) { + 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 6c58bb579..76d4b8f75 100644 --- a/profile-widget/profileview.h +++ b/profile-widget/profileview.h @@ -138,6 +138,7 @@ private: // Event related void editEventName(struct event *event); + 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 c3d0368e9..1d44a8c3f 100644 --- a/profile-widget/profilewidget2.cpp +++ b/profile-widget/profilewidget2.cpp @@ -365,37 +365,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); - } - if (std::any_of(profileScene->eventItems.begin(), profileScene->eventItems.end(), - [] (const DiveEventItem *item) { return item->getEvent()->hidden; })) - m.addAction(tr("Unhide individually hidden events of this dive"), this, &ProfileWidget2::unhideEvents); m.exec(event->globalPos()); } -void ProfileWidget2::unhideEvents() -{ - for (DiveEventItem *item: profileScene->eventItems) { - item->getEventMutable()->hidden = false; - 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 a8b5362b1..a49979954 100644 --- a/profile-widget/profilewidget2.h +++ b/profile-widget/profilewidget2.h @@ -107,8 +107,6 @@ private: void addSetpointChange(int seconds); void removeEvent(DiveEventItem *item); void editName(DiveEventItem *item); - void unhideEvents(); - void unhideEventTypes(); void makeFirstDC(); void deleteCurrentDC(); void splitCurrentDC();