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 <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2024-03-01 13:02:35 +01:00
parent 7c7469b8ab
commit b099e17042
14 changed files with 98 additions and 50 deletions

View file

@ -334,6 +334,12 @@ struct event *get_event(struct divecomputer *dc, int idx)
return &dc->events[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) void add_extra_data(struct divecomputer *dc, const std::string &key, const std::string &value)
{ {
if (key == "Serial") { if (key == "Serial") {

View file

@ -44,6 +44,8 @@ struct divecomputer {
std::vector<struct event> events; std::vector<struct event> events;
std::vector<struct extra_data> extra_data; std::vector<struct extra_data> extra_data;
bool has_individually_hidden_events() const;
divecomputer(); divecomputer();
~divecomputer(); ~divecomputer();
divecomputer(const divecomputer &); divecomputer(const divecomputer &);

View file

@ -64,6 +64,8 @@ public:
const struct event *next(); // nullptr -> end const struct event *next(); // nullptr -> end
}; };
extern bool has_individually_hidden_events(const struct divecomputer *dc);
/* Get gasmixes at increasing timestamps. */ /* Get gasmixes at increasing timestamps. */
class gasmix_loop { class gasmix_loop {
const struct dive &dive; const struct dive &dive;

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include "eventtype.h" #include "eventtype.h"
#include "event.h" #include "event.h"
#include "divecomputer.h"
#include "gettextfromc.h" #include "gettextfromc.h"
#include "subsurface-string.h" #include "subsurface-string.h"
@ -42,9 +43,9 @@ void remember_event_type(const struct event *ev)
event_types.push_back(std::move(type)); 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; return it != event_types.end() && !it->plot;
} }
@ -55,10 +56,18 @@ void hide_event_type(const struct event *ev)
it->plot = false; 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) return std::any_of(dc.events.begin(), dc.events.end(), [&et] (const event &ev)
e.plot = true; { 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) void show_event_type(int idx)
@ -74,11 +83,12 @@ bool any_event_types_hidden()
[] (const event_type &e) { return !e.plot; }); [] (const event_type &e) { return !e.plot; });
} }
extern std::vector<int> hidden_event_types() std::vector<int> hidden_event_types(const struct divecomputer &dc)
{ {
std::vector<int> res; std::vector<int> res;
for (size_t i = 0; i < event_types.size(); ++i) { 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); res.push_back(i);
} }
return res; return res;

View file

@ -8,12 +8,12 @@
extern void clear_event_types(); extern void clear_event_types();
extern void remember_event_type(const struct event *ev); 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 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 void show_event_type(int idx);
extern bool any_event_types_hidden(); extern bool any_event_types_hidden();
extern std::vector<int> hidden_event_types(); extern std::vector<int> hidden_event_types(const struct divecomputer &dc);
extern QString event_type_name(const event &ev); extern QString event_type_name(const event &ev);
extern QString event_type_name(int idx); extern QString event_type_name(int idx);

View file

@ -205,7 +205,7 @@ void DiveEventItem::recalculatePos()
hide(); hide();
return; 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 x = hAxis->posAtValue(ev.time.seconds);
double y = vAxis->posAtValue(depth); double y = vAxis->posAtValue(depth);
setPos(x, y); setPos(x, y);

View file

@ -90,6 +90,11 @@ double DiveTextItem::fontHeight(double dpr, double scale)
return (double)fm.height(); return (double)fm.height();
} }
double DiveTextItem::width() const
{
return boundingRect().width();
}
double DiveTextItem::height() const double DiveTextItem::height() const
{ {
return fontHeight(dpr, scale) + outlineSize * dpr; return fontHeight(dpr, scale) + outlineSize * dpr;

View file

@ -17,6 +17,7 @@ public:
const QString &text(); const QString &text();
static double fontHeight(double dpr, double scale); static double fontHeight(double dpr, double scale);
static std::pair<double, double> getLabelSize(double dpr, double scale, const QString &label); static std::pair<double, double> getLabelSize(double dpr, double scale, const QString &label);
double width() const;
double height() const; double height() const;
private: private:

View file

@ -11,6 +11,7 @@
#include "core/device.h" #include "core/device.h"
#include "core/divecomputer.h" #include "core/divecomputer.h"
#include "core/event.h" #include "core/event.h"
#include "core/eventtype.h"
#include "core/pref.h" #include "core/pref.h"
#include "core/profile.h" #include "core/profile.h"
#include "core/qthelper.h" // for decoMode() #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 [](const plot_data &item) { return 0.0; }, // unused
1, dpr)), 1, dpr)),
diveComputerText(new DiveTextItem(dpr, 1.0, Qt::AlignRight | Qt::AlignTop, nullptr)), diveComputerText(new DiveTextItem(dpr, 1.0, Qt::AlignRight | Qt::AlignTop, nullptr)),
eventsHiddenText(new DiveTextItem(dpr, 1.0, Qt::AlignRight | Qt::AlignTop, nullptr)),
reportedCeiling(createItem<DiveReportedCeiling>(*profileYAxis, reportedCeiling(createItem<DiveReportedCeiling>(*profileYAxis,
[](const plot_data &item) { return (double)item.ceiling; }, [](const plot_data &item) { return (double)item.ceiling; },
1, dpr)), 1, dpr)),
@ -143,6 +145,7 @@ ProfileScene::ProfileScene(double dpr, bool printMode, bool isGrayscale) :
// Add items to scene // Add items to scene
addItem(diveComputerText); addItem(diveComputerText);
addItem(eventsHiddenText);
addItem(tankItem); addItem(tankItem);
addItem(decoModelParameters); addItem(decoModelParameters);
addItem(profileYAxis); addItem(profileYAxis);
@ -156,6 +159,8 @@ ProfileScene::ProfileScene(double dpr, bool printMode, bool isGrayscale) :
for (AbstractProfilePolygonItem *item: profileItems) for (AbstractProfilePolygonItem *item: profileItems)
addItem(item); addItem(item);
eventsHiddenText->set(tr("Hidden events!"), getColor(TIME_TEXT, isGrayscale));
} }
ProfileScene::~ProfileScene() ProfileScene::~ProfileScene()
@ -287,8 +292,10 @@ void ProfileScene::updateAxes(bool diveHasHeartBeat, bool simplified)
profileYAxis->setGridIsMultipleOfThree( qPrefDisplay::three_m_based_grid() ); profileYAxis->setGridIsMultipleOfThree( qPrefDisplay::three_m_based_grid() );
// Place the fixed dive computer text at the bottom // Place the fixed dive computer text at the bottom
double bottomBorder = sceneRect().height() - diveComputerText->height() - 2.0 * dpr * diveComputerTextBorder; double bottomTextHeight = std::max(diveComputerText->height(), eventsHiddenText->height());
diveComputerText->setPos(0.0, bottomBorder + dpr * diveComputerTextBorder); 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; double topBorder = 0.0;
@ -372,6 +379,12 @@ bool ProfileScene::pointOnDiveComputerText(const QPointF &point) const
return diveComputerText->boundingRect().contains(point - diveComputerText->pos()); 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) static double max_gas(const plot_info &pi, double gas_pressures::*gas)
{ {
double ret = -1; double ret = -1;
@ -525,9 +538,12 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, int animSpeed, boo
eventItems.clear(); eventItems.clear();
struct gasmix lastgasmix = d->get_gasmix_at_time(*currentdc, 1_sec); struct gasmix lastgasmix = d->get_gasmix_at_time(*currentdc, 1_sec);
bool has_hidden_events = false;
for (auto [idx, event]: enumerated_range(currentdc->events)) { for (auto [idx, event]: enumerated_range(currentdc->events)) {
if (event.hidden) if (event.hidden || is_event_type_hidden(event)) {
has_hidden_events = true;
continue; continue;
}
// if print mode is selected only draw headings, SP change, gas events or bookmark event // if print mode is selected only draw headings, SP change, gas events or bookmark event
if (printMode) { if (printMode) {
if (event.name.empty() || if (event.name.empty() ||
@ -547,6 +563,7 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, int animSpeed, boo
if (event.is_gaschange()) if (event.is_gaschange())
lastgasmix = d->get_gasmix_from_event(event); lastgasmix = d->get_gasmix_from_event(event);
} }
eventsHiddenText->setVisible(has_hidden_events);
QString dcText = QString::fromStdString(get_dc_nickname(currentdc)); QString dcText = QString::fromStdString(get_dc_nickname(currentdc));
if (is_dc_planner(currentdc)) if (is_dc_planner(currentdc))

View file

@ -38,6 +38,7 @@ public:
void clear(); void clear();
bool pointOnProfile(const QPointF &point) const; bool pointOnProfile(const QPointF &point) const;
bool pointOnDiveComputerText(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). 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. // Can be compared with literal 1.0 to determine "end" state.
@ -96,6 +97,7 @@ private:
DiveGasPressureItem *gasPressureItem; DiveGasPressureItem *gasPressureItem;
std::vector<std::unique_ptr<DiveEventItem>> eventItems; std::vector<std::unique_ptr<DiveEventItem>> eventItems;
DiveTextItem *diveComputerText; DiveTextItem *diveComputerText;
DiveTextItem *eventsHiddenText;
DiveReportedCeiling *reportedCeiling; DiveReportedCeiling *reportedCeiling;
PartialPressureGasItem *pn2GasItem; PartialPressureGasItem *pn2GasItem;
PartialPressureGasItem *pheGasItem; PartialPressureGasItem *pheGasItem;

View file

@ -509,6 +509,16 @@ static QString formatCylinderDescription(int i, const cylinder_t &cylinder)
return label; 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) void ProfileView::mousePressEvent(QMouseEvent *event)
{ {
// Handle dragging of items // Handle dragging of items
@ -541,6 +551,34 @@ void ProfileView::mousePressEvent(QMouseEvent *event)
return execMenu(m, event->globalPos()); return execMenu(m, event->globalPos());
} }
// Open context menu for event unhiding
if (d && profileScene->pointOnEventsHiddenText(event->pos())) {
std::vector<MenuEntry> 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, &currentdc] {
unhideEvents();
});
}
std::vector<int> types = hidden_event_types(*currentdc);
if (!types.empty()) {
std::vector<MenuEntry> 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()); DiveEventItem *item = profileScene->eventAtPosition(event->pos());
if (d && item) { if (d && item) {
std::vector<MenuEntry> m; std::vector<MenuEntry> m;

View file

@ -142,6 +142,7 @@ private:
void hideEvent(DiveEventItem &item); void hideEvent(DiveEventItem &item);
void hideEventType(DiveEventItem &item); void hideEventType(DiveEventItem &item);
void removeEvent(DiveEventItem &item); void removeEvent(DiveEventItem &item);
void unhideEvents();
// The list of pictures in this plot. The pictures are sorted by offset in seconds. // The list of pictures in this plot. The pictures are sorted by offset in seconds.
// For the same offset, sort by filename. // For the same offset, sort by filename.

View file

@ -370,43 +370,9 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
changeMode->addAction(gettextFromC::tr(divemode_text_ui[PSCR]), changeMode->addAction(gettextFromC::tr(divemode_text_ui[PSCR]),
[this, seconds](){ addDivemodeSwitch(seconds, 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()); 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) void ProfileWidget2::addBookmark(int seconds)
{ {
if (d) if (d)

View file

@ -109,8 +109,6 @@ private:
void addSetpointChange(int seconds); void addSetpointChange(int seconds);
void removeEvent(DiveEventItem *item); void removeEvent(DiveEventItem *item);
void editName(DiveEventItem *item); void editName(DiveEventItem *item);
void unhideEvents();
void unhideEventTypes();
void makeFirstDC(); void makeFirstDC();
void deleteCurrentDC(); void deleteCurrentDC();
void splitCurrentDC(); void splitCurrentDC();