Compare commits

...

6 commits

Author SHA1 Message Date
bstoeger
5aa1c44a5b
Merge 163e10c08b into 7a74a6c426 2024-02-21 20:39:08 +00:00
Berthold Stoeger
163e10c08b profile: make event hiding persistent across change of dive
Currently, the "hide event" status is lost when switching dives.
Save it in the event struct instead to make it persistent.

In the future we might save this information to the log file.
Then this should be integrated in the undo-system.

This commit also makes the "unhide events" menu entry more
fine grained: It now differentiates between individual
events and event types.

Note this adds an additional field to the event structure.
There is a "deleted" field that is used internally for
book-keeping, but probably should be removed. Not touching
this at the moment as long as this is C-only code. When/if
switching to C++ we can make the event linked list a table,
which will make this much simpler.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2024-02-21 21:38:23 +01:00
Berthold Stoeger
0d8c6c4bc4 cleanup: fix typos in comments
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2024-02-18 18:44:37 +01:00
Berthold Stoeger
b98c35ab52 events: make event severity explicit
Currently the event type code uses libdivecomputer's flags
to differentiate between events. Make this explicit and extract
the event severity.

The reason is that later we want to be more explicit about showing/
hiding events and thereto we must format the name of events.

Moreover, this encapsulates the complexities of extracting
the severity in the event code (that used to be in the profile
code).

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2024-02-14 21:51:22 +01:00
Berthold Stoeger
fdbd076e0d core: pass event to event_type functions
Instead of passing name / flag pairs to event_type functions,
pass a pointer to the event. This hides implementation details.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2024-02-14 21:50:47 +01:00
Berthold Stoeger
7dd52ef494 core: rename eventname.* to eventtype.*
This structure is used to hide events of a certain type.
The type was inferred from its name, but now includes flags.
So event_type is more appropriate.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2024-02-14 10:59:13 +01:00
16 changed files with 227 additions and 120 deletions

View file

@ -51,7 +51,7 @@ SOURCES += subsurface-mobile-main.cpp \
core/divecomputer.c \
core/divefilter.cpp \
core/event.c \
core/eventname.cpp \
core/eventtype.cpp \
core/filterconstraint.cpp \
core/filterpreset.cpp \
core/divelist.c \
@ -202,7 +202,7 @@ HEADERS += \
core/dive.h \
core/divecomputer.h \
core/event.h \
core/eventname.h \
core/eventtype.h \
core/extradata.h \
core/git-access.h \
core/globals.h \

View file

@ -81,8 +81,8 @@ set(SUBSURFACE_CORE_LIB_SRCS
downloadfromdcthread.h
event.c
event.h
eventname.cpp
eventname.h
eventtype.cpp
eventtype.h
equipment.c
equipment.h
errorhelper.c

View file

@ -9,7 +9,7 @@
#include "divelog.h"
#include "divesite.h"
#include "event.h"
#include "eventname.h"
#include "eventtype.h"
#include "filterpreset.h"
#include "fulltext.h"
#include "interpolate.h"
@ -1319,7 +1319,7 @@ void clear_dive_file_data()
current_dive = NULL;
clear_divelog(&divelog);
clear_event_names();
clear_event_types();
reset_min_datafile_version();
clear_git_id();

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include "event.h"
#include "eventname.h"
#include "eventtype.h"
#include "subsurface-string.h"
#include <string.h>
@ -80,7 +80,7 @@ struct event *create_event(unsigned int time, int type, int flags, int value, co
break;
}
remember_event_name(name, flags);
remember_event_type(ev);
return ev;
}
@ -102,3 +102,17 @@ bool same_event(const struct event *a, const struct event *b)
return 0;
return !strcmp(a->name, b->name);
}
extern enum event_severity get_event_severity(const struct event *ev)
{
switch (ev->flags & SAMPLE_FLAGS_SEVERITY_MASK) {
case SAMPLE_FLAGS_SEVERITY_INFO:
return EVENT_SEVERITY_INFO;
case SAMPLE_FLAGS_SEVERITY_WARN:
return EVENT_SEVERITY_WARN;
case SAMPLE_FLAGS_SEVERITY_ALARM:
return EVENT_SEVERITY_ALARM;
default:
return EVENT_SEVERITY_NONE;
}
}

View file

@ -12,6 +12,13 @@
extern "C" {
#endif
enum event_severity {
EVENT_SEVERITY_NONE = 0,
EVENT_SEVERITY_INFO,
EVENT_SEVERITY_WARN,
EVENT_SEVERITY_ALARM
};
/*
* Events are currently based straight on what libdivecomputer gives us.
* We need to wrap these into our own events at some point to remove some of the limitations.
@ -35,7 +42,8 @@ struct event {
struct gasmix mix;
} gas;
};
bool deleted;
bool deleted; // used internally in the parser and in fixup_dive().
bool hidden;
char name[];
};
@ -46,12 +54,12 @@ extern void free_events(struct event *ev);
extern struct event *create_event(unsigned int time, int type, int flags, int value, const char *name);
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);
/* 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);
extern struct event *get_next_event_mutable(struct event *event, const char *name);
#ifdef __cplusplus
}
#endif

View file

@ -1,60 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include "eventname.h"
#include "subsurface-string.h"
#include <string>
#include <vector>
#include <algorithm>
struct event_name {
std::string name;
int flags;
bool plot;
};
static std::vector<event_name> event_names;
// Small helper so that we can compare events to C-strings
static bool operator==(const event_name &en1, const event_name &en2)
{
return en1.name == en2.name && en1.flags == en2.flags;
}
extern "C" void clear_event_names()
{
event_names.clear();
}
extern "C" void remember_event_name(const char *eventname, const int flags)
{
if (empty_string(eventname))
return;
if (std::find(event_names.begin(), event_names.end(), event_name{ eventname, flags }) != event_names.end())
return;
event_names.push_back({ eventname, flags, true });
}
extern "C" bool is_event_hidden(const char *eventname, const int flags)
{
auto it = std::find(event_names.begin(), event_names.end(), event_name{ eventname, flags });
return it != event_names.end() && !it->plot;
}
extern "C" void hide_similar_events(const char *eventname, const int flags)
{
auto it = std::find(event_names.begin(), event_names.end(), event_name{ eventname, flags });
if (it != event_names.end())
it->plot = false;
}
extern "C" void show_all_events()
{
for (event_name &en: event_names)
en.plot = true;
}
extern "C" bool any_events_hidden()
{
return std::any_of(event_names.begin(), event_names.end(),
[] (const event_name &en) { return !en.plot; });
}

View file

@ -1,21 +0,0 @@
// collect all event names and whether we display events of that type
// SPDX-License-Identifier: GPL-2.0
#ifndef EVENTNAME_H
#define EVENTNAME_H
#ifdef __cplusplus
extern "C" {
#endif
extern void clear_event_names(void);
extern void remember_event_name(const char *eventname, const int flags);
extern bool is_event_hidden(const char *eventname, const int flags);
extern void hide_similar_events(const char *eventname, const int flags);
extern void show_all_events();
extern bool any_events_hidden();
#ifdef __cplusplus
}
#endif
#endif

122
core/eventtype.cpp Normal file
View file

@ -0,0 +1,122 @@
// SPDX-License-Identifier: GPL-2.0
#include "eventtype.h"
#include "event.h"
#include "gettextfromc.h"
#include "subsurface-string.h"
#include <string>
#include <vector>
#include <algorithm>
struct event_type {
std::string name;
event_severity severity;
bool plot;
event_type(const struct event *ev) :
name(ev->name),
severity(get_event_severity(ev)),
plot(true)
{
}
};
static std::vector<event_type> event_types;
static bool operator==(const event_type &en1, const event_type &en2)
{
return en1.name == en2.name && en1.severity == en2.severity;
}
extern "C" void clear_event_types()
{
event_types.clear();
}
extern "C" void remember_event_type(const struct event *ev)
{
if (empty_string(ev->name))
return;
event_type type(ev);
if (std::find(event_types.begin(), event_types.end(), type) != event_types.end())
return;
event_types.push_back(std::move(type));
}
extern "C" bool is_event_type_hidden(const struct event *ev)
{
auto it = std::find(event_types.begin(), event_types.end(), ev);
return it != event_types.end() && !it->plot;
}
extern "C" void hide_event_type(const struct event *ev)
{
auto it = std::find(event_types.begin(), event_types.end(), ev);
if (it != event_types.end())
it->plot = false;
}
extern "C" void show_all_event_types()
{
for (event_type &e: event_types)
e.plot = true;
}
extern "C" void show_event_type(int idx)
{
if (idx < 0 || idx >= (int)event_types.size())
return;
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<int> hidden_event_types()
{
std::vector<int> res;
for (size_t i = 0; i < event_types.size(); ++i) {
if (!event_types[i].plot)
res.push_back(i);
}
return res;
}
static QString event_severity_name(event_severity severity)
{
switch (severity) {
case EVENT_SEVERITY_INFO: return gettextFromC::tr("info");
case EVENT_SEVERITY_WARN: return gettextFromC::tr("warn");
case EVENT_SEVERITY_ALARM: return gettextFromC::tr("alarm");
default: return QString();
}
}
static QString event_type_name(QString name, event_severity severity)
{
QString severity_name = event_severity_name(severity);
if (severity_name.isEmpty())
return name;
return QStringLiteral("%1 (%2)").arg(name, severity_name);
}
QString event_type_name(const event *ev)
{
if (!ev || empty_string(ev->name))
return QString();
QString name = QString::fromUtf8(ev->name);
return event_type_name(std::move(name), get_event_severity(ev));
}
QString event_type_name(int idx)
{
if (idx < 0 || idx >= (int)event_types.size())
return QString();
const event_type &t = event_types[idx];
QString name = QString::fromUtf8(t.name.c_str());
return event_type_name(std::move(name), t.severity);
}

31
core/eventtype.h Normal file
View file

@ -0,0 +1,31 @@
// collect all event names and whether we display events of that type
// SPDX-License-Identifier: GPL-2.0
#ifndef EVENTNAME_H
#define EVENTNAME_H
#ifdef __cplusplus
extern "C" {
#endif
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_event_type(int idx);
extern bool any_event_types_hidden();
#ifdef __cplusplus
}
// C++-only functions
#include <vector>
#include <QString>
extern std::vector<int> hidden_event_types();
QString event_type_name(const event *ev);
QString event_type_name(int idx);
#endif
#endif

View file

@ -1,6 +1,7 @@
#include "string-format.h"
#include "dive.h"
#include "divesite.h"
#include "event.h"
#include "format.h"
#include "qthelper.h"
#include "subsurface-string.h"

View file

@ -7,6 +7,7 @@
struct dive;
struct dive_trip;
struct event;
QString formatSac(const dive *d);
QString formatNotes(const dive *d);

View file

@ -4,7 +4,7 @@
#include "profile-widget/divepixmapcache.h"
#include "profile-widget/animationfunctions.h"
#include "core/event.h"
#include "core/eventname.h"
#include "core/eventtype.h"
#include "core/format.h"
#include "core/profile.h"
#include "core/gettextfromc.h"
@ -47,6 +47,7 @@ struct event *DiveEventItem::getEventMutable()
void DiveEventItem::setupPixmap(struct gasmix lastgasmix, const DivePixmaps &pixmaps)
{
event_severity severity = get_event_severity(ev);
if (empty_string(ev->name)) {
setPixmap(pixmaps.warning);
} else if (same_string_caseinsensitive(ev->name, "modechange")) {
@ -82,12 +83,8 @@ void DiveEventItem::setupPixmap(struct gasmix lastgasmix, const DivePixmaps &pix
else
setPixmap(pixmaps.gaschangeEAN);
}
#ifdef SAMPLE_FLAGS_SEVERITY_SHIFT
} else if ((((ev->flags & SAMPLE_FLAGS_SEVERITY_MASK) >> SAMPLE_FLAGS_SEVERITY_SHIFT) == 1) ||
// those are useless internals of the dive computer
#else
} else if (
#endif
same_string_caseinsensitive(ev->name, "heading") ||
(same_string_caseinsensitive(ev->name, "SP change") && ev->time.seconds == 0)) {
// 2 cases:
@ -98,14 +95,12 @@ void DiveEventItem::setupPixmap(struct gasmix lastgasmix, const DivePixmaps &pix
// 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);
#ifdef SAMPLE_FLAGS_SEVERITY_SHIFT
} else if (((ev->flags & SAMPLE_FLAGS_SEVERITY_MASK) >> SAMPLE_FLAGS_SEVERITY_SHIFT) == 2) {
} else if (severity == EVENT_SEVERITY_INFO) {
setPixmap(pixmaps.info);
} else if (((ev->flags & SAMPLE_FLAGS_SEVERITY_MASK) >> SAMPLE_FLAGS_SEVERITY_SHIFT) == 3) {
} else if (severity == EVENT_SEVERITY_WARN) {
setPixmap(pixmaps.warning);
} else if (((ev->flags & SAMPLE_FLAGS_SEVERITY_MASK) >> SAMPLE_FLAGS_SEVERITY_SHIFT) == 4) {
} else if (severity == EVENT_SEVERITY_ALARM) {
setPixmap(pixmaps.violation);
#endif
} else if (same_string_caseinsensitive(ev->name, "violation") || // generic libdivecomputer
same_string_caseinsensitive(ev->name, "Safety stop violation") || // the rest are from the Uemis downloader
same_string_caseinsensitive(ev->name, "pO₂ ascend alarm") ||
@ -224,11 +219,6 @@ bool DiveEventItem::isInteresting(const struct dive *d, const struct divecompute
return true;
}
bool DiveEventItem::shouldBeHidden()
{
return is_event_hidden(ev->name, ev->flags);
}
void DiveEventItem::recalculatePos()
{
if (!ev)
@ -238,7 +228,7 @@ void DiveEventItem::recalculatePos()
hide();
return;
}
setVisible(!shouldBeHidden());
setVisible(!ev->hidden && !is_event_type_hidden(ev));
double x = hAxis->posAtValue(ev->time.seconds);
double y = vAxis->posAtValue(depth);
setPos(x, y);

View file

@ -21,7 +21,6 @@ public:
void eventVisibilityChanged(const QString &eventName, bool visible);
void setVerticalAxis(DiveCartesianAxis *axis, int speed);
void setHorizontalAxis(DiveCartesianAxis *axis);
bool shouldBeHidden();
static bool isInteresting(const struct dive *d, const struct divecomputer *dc,
const struct event *ev, const struct plot_info &pi,
int firstSecond, int lastSecond);

View file

@ -40,7 +40,7 @@ DivePixmaps::DivePixmaps(int dpr) : dpr(dpr)
gaschangeEANICD = createPixmap(":gaschange-ean-ICD-icon", sz_bigger);
gaschangeEAN = createPixmap(":gaschange-ean-icon", sz_bigger);
// The transparen pixmap is a very obscure feature to enable tooltips without showing a pixmap.
// The transparent pixmap is a very obscure feature to enable tooltips without showing a pixmap.
// See code in diveeventitem.cpp. This should probably be replaced by a different mechanism.
QPixmap transparentPixmap(lrint(4 * dprf), lrint(20 * dprf));
transparentPixmap.fill(makeColor(1.0, 1.0, 1.0, 0.01));
@ -52,7 +52,7 @@ static std::vector<std::shared_ptr<const DivePixmaps>> cache;
// Note that the idiomatic way would be to store std::weak_ptr<>s.
// That would mean that the pixmaps are destroyed when the last user uses
// them. We want to keep them around at least until the next caller!
// Therefore we also std::shared_ptr<>s.
// Therefore we also store std::shared_ptr<>s.
std::shared_ptr<const DivePixmaps> getDivePixmaps(double dprIn)
{
using ptr = std::shared_ptr<const DivePixmaps>;

View file

@ -3,7 +3,7 @@
#include "profile-widget/profilescene.h"
#include "core/device.h"
#include "core/event.h"
#include "core/eventname.h"
#include "core/eventtype.h"
#include "core/subsurface-string.h"
#include "core/qthelper.h"
#include "core/range.h"
@ -608,10 +608,11 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
[this, seconds](){ addDivemodeSwitch(seconds, PSCR); });
if (DiveEventItem *item = dynamic_cast<DiveEventItem *>(sceneItem)) {
const struct event *dcEvent = item->getEvent();
m.addAction(tr("Remove event"), [this,item] { removeEvent(item); });
m.addAction(tr("Hide event"), [this, item] { hideEvent(item); });
m.addAction(tr("Hide similar events"), [this, item] { hideSimilarEvents(item); });
const struct event *dcEvent = item->getEvent();
m.addAction(tr("Hide events of type '%1'").arg(event_type_name(dcEvent)),
[this, item] { hideEventType(item); });
if (dcEvent->type == SAMPLE_EVENT_BOOKMARK)
m.addAction(tr("Edit name"), [this, item] { editName(item); });
#if 0 // TODO::: FINISH OR DISABLE
@ -656,8 +657,19 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
}
#endif
}
if (any_events_hidden() || std::any_of(profileScene->eventItems.begin(), profileScene->eventItems.end(), [] (const DiveEventItem *item) { return !item->isVisible(); }))
m.addAction(tr("Unhide all events"), this, &ProfileWidget2::unhideEvents);
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());
}
@ -694,15 +706,16 @@ void ProfileWidget2::renameCurrentDC()
void ProfileWidget2::hideEvent(DiveEventItem *item)
{
item->getEventMutable()->hidden = true;
item->hide();
}
void ProfileWidget2::hideSimilarEvents(DiveEventItem *item)
void ProfileWidget2::hideEventType(DiveEventItem *item)
{
const struct event *event = item->getEvent();
if (!empty_string(event->name)) {
hide_similar_events(event->name, event->flags);
hide_event_type(event);
replot();
}
@ -710,9 +723,17 @@ void ProfileWidget2::hideSimilarEvents(DiveEventItem *item)
void ProfileWidget2::unhideEvents()
{
show_all_events();
for (DiveEventItem *item: profileScene->eventItems)
for (DiveEventItem *item: profileScene->eventItems) {
item->getEventMutable()->hidden = false;
item->show();
}
}
void ProfileWidget2::unhideEventTypes()
{
show_all_event_types();
replot();
}
void ProfileWidget2::removeEvent(DiveEventItem *item)

View file

@ -126,9 +126,10 @@ private:
void addSetpointChange(int seconds);
void removeEvent(DiveEventItem *item);
void hideEvent(DiveEventItem *item);
void hideSimilarEvents(DiveEventItem *item);
void hideEventType(DiveEventItem *item);
void editName(DiveEventItem *item);
void unhideEvents();
void unhideEventTypes();
void makeFirstDC();
void deleteCurrentDC();
void splitCurrentDC();