mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
Merge pull request #2643 from bstoeger/cylinder4
First steps of cylinder-editing undo
This commit is contained in:
commit
6d187b5f4a
37 changed files with 1335 additions and 795 deletions
96
core/dive.c
96
core/dive.c
|
|
@ -11,6 +11,7 @@
|
|||
#include "device.h"
|
||||
#include "divelist.h"
|
||||
#include "divesite.h"
|
||||
#include "errorhelper.h"
|
||||
#include "qthelper.h"
|
||||
#include "metadata.h"
|
||||
#include "membuffer.h"
|
||||
|
|
@ -126,10 +127,10 @@ int event_is_gaschange(const struct event *ev)
|
|||
ev->type == SAMPLE_EVENT_GASCHANGE2;
|
||||
}
|
||||
|
||||
struct event *add_event(struct divecomputer *dc, unsigned int time, int type, int flags, int value, const char *name)
|
||||
struct event *create_event(unsigned int time, int type, int flags, int value, const char *name)
|
||||
{
|
||||
int gas_index = -1;
|
||||
struct event *ev, **p;
|
||||
struct event *ev;
|
||||
unsigned int size, len = strlen(name);
|
||||
|
||||
size = sizeof(*ev) + len + 1;
|
||||
|
|
@ -164,18 +165,85 @@ struct event *add_event(struct divecomputer *dc, unsigned int time, int type, in
|
|||
break;
|
||||
}
|
||||
|
||||
return ev;
|
||||
}
|
||||
|
||||
/* warning: does not test idx for validity */
|
||||
struct event *create_gas_switch_event(struct dive *dive, struct divecomputer *dc, int seconds, int idx)
|
||||
{
|
||||
/* The gas switch event format is insane for historical reasons */
|
||||
struct gasmix mix = get_cylinder(dive, idx)->gasmix;
|
||||
int o2 = get_o2(mix);
|
||||
int he = get_he(mix);
|
||||
struct event *ev;
|
||||
int value;
|
||||
|
||||
o2 = (o2 + 5) / 10;
|
||||
he = (he + 5) / 10;
|
||||
value = o2 + (he << 16);
|
||||
|
||||
ev = create_event(seconds, he ? SAMPLE_EVENT_GASCHANGE2 : SAMPLE_EVENT_GASCHANGE, 0, value, "gaschange");
|
||||
ev->gas.index = idx;
|
||||
ev->gas.mix = mix;
|
||||
return ev;
|
||||
}
|
||||
|
||||
struct event *clone_event_rename(const struct event *ev, const char *name)
|
||||
{
|
||||
return create_event(ev->time.seconds, ev->type, ev->flags, ev->value, name);
|
||||
}
|
||||
|
||||
void add_event_to_dc(struct divecomputer *dc, struct event *ev)
|
||||
{
|
||||
struct event **p;
|
||||
|
||||
p = &dc->events;
|
||||
|
||||
/* insert in the sorted list of events */
|
||||
while (*p && (*p)->time.seconds <= time)
|
||||
while (*p && (*p)->time.seconds <= ev->time.seconds)
|
||||
p = &(*p)->next;
|
||||
ev->next = *p;
|
||||
*p = ev;
|
||||
}
|
||||
|
||||
struct event *add_event(struct divecomputer *dc, unsigned int time, int type, int flags, int value, const char *name)
|
||||
{
|
||||
struct event *ev = create_event(time, type, flags, value, name);
|
||||
|
||||
if (!ev)
|
||||
return NULL;
|
||||
|
||||
add_event_to_dc(dc, ev);
|
||||
|
||||
remember_event(name);
|
||||
return ev;
|
||||
}
|
||||
|
||||
static int same_event(const struct event *a, const struct event *b)
|
||||
void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int seconds, int idx)
|
||||
{
|
||||
/* sanity check so we don't crash */
|
||||
if (idx < 0 || idx >= dive->cylinders.nr) {
|
||||
report_error("Unknown cylinder index: %d", idx);
|
||||
return;
|
||||
}
|
||||
struct event *ev = create_gas_switch_event(dive, dc, seconds, idx);
|
||||
add_event_to_dc(dc, ev);
|
||||
}
|
||||
|
||||
/* Substitutes an event in a divecomputer for another. No reordering is performed! */
|
||||
void swap_event(struct divecomputer *dc, struct event *from, struct event *to)
|
||||
{
|
||||
for (struct event **ep = &dc->events; *ep; ep = &(*ep)->next) {
|
||||
if (*ep == from) {
|
||||
to->next = from->next;
|
||||
*ep = to;
|
||||
from->next = NULL; // For good measure.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool same_event(const struct event *a, const struct event *b)
|
||||
{
|
||||
if (a->time.seconds != b->time.seconds)
|
||||
return 0;
|
||||
|
|
@ -188,19 +256,15 @@ static int same_event(const struct event *a, const struct event *b)
|
|||
return !strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
void remove_event(struct event *event)
|
||||
/* Remove given event from dive computer. Does *not* free the event. */
|
||||
void remove_event_from_dc(struct divecomputer *dc, struct event *event)
|
||||
{
|
||||
struct event **ep = ¤t_dc->events;
|
||||
while (ep && !same_event(*ep, event))
|
||||
ep = &(*ep)->next;
|
||||
if (ep) {
|
||||
/* we can't link directly with event->next
|
||||
* because 'event' can be a copy from another
|
||||
* dive (for instance the displayed_dive
|
||||
* that we use on the interface to show things). */
|
||||
struct event *temp = (*ep)->next;
|
||||
free(*ep);
|
||||
*ep = temp;
|
||||
for (struct event **ep = &dc->events; *ep; ep = &(*ep)->next) {
|
||||
if (*ep == event) {
|
||||
*ep = event->next;
|
||||
event->next = NULL; // For good measure.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
15
core/dive.h
15
core/dive.h
|
|
@ -358,10 +358,15 @@ extern void copy_used_cylinders(const struct dive *s, struct dive *d, bool used_
|
|||
extern void copy_samples(const struct divecomputer *s, struct divecomputer *d);
|
||||
extern bool is_cylinder_used(const struct dive *dive, int idx);
|
||||
extern bool is_cylinder_prot(const struct dive *dive, int idx);
|
||||
extern void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl);
|
||||
extern void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int time, int idx);
|
||||
extern struct event *create_event(unsigned int time, int type, int flags, int value, const char *name);
|
||||
extern struct event *create_gas_switch_event(struct dive *dive, struct divecomputer *dc, int seconds, int idx);
|
||||
extern struct event *clone_event_rename(const struct event *ev, const char *name);
|
||||
extern void add_event_to_dc(struct divecomputer *dc, struct event *ev);
|
||||
extern void swap_event(struct divecomputer *dc, struct event *from, struct event *to);
|
||||
extern bool same_event(const struct event *a, const struct event *b);
|
||||
extern struct event *add_event(struct divecomputer *dc, unsigned int time, int type, int flags, int value, const char *name);
|
||||
extern void remove_event(struct event *event);
|
||||
extern void remove_event_from_dc(struct divecomputer *dc, struct event *event);
|
||||
extern void update_event_name(struct dive *d, struct event *event, const char *name);
|
||||
extern void add_extra_data(struct divecomputer *dc, const char *key, const char *value);
|
||||
extern void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, int *mean, int *duration);
|
||||
|
|
@ -372,15 +377,9 @@ extern int nr_weightsystems(const struct dive *dive);
|
|||
|
||||
/* UI related protopypes */
|
||||
|
||||
// extern void report_error(GError* error);
|
||||
|
||||
extern void remember_event(const char *eventname);
|
||||
extern void invalidate_dive_cache(struct dive *dc);
|
||||
|
||||
#if WE_DONT_USE_THIS /* this is a missing feature in Qt - selecting which events to display */
|
||||
extern int evn_foreach(void (*callback)(const char *, bool *, void *), void *data);
|
||||
#endif /* WE_DONT_USE_THIS */
|
||||
|
||||
extern void clear_events(void);
|
||||
|
||||
extern void set_dc_nickname(struct dive *dive);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ void free_weightsystem(weightsystem_t ws)
|
|||
ws.description = NULL;
|
||||
}
|
||||
|
||||
static void free_cylinder(cylinder_t c)
|
||||
void free_cylinder(cylinder_t c)
|
||||
{
|
||||
free((void *)c.type.description);
|
||||
c.type.description = NULL;
|
||||
|
|
@ -137,12 +137,18 @@ void add_cloned_weightsystem_at(struct weightsystem_table *t, weightsystem_t ws)
|
|||
add_to_weightsystem_table(t, t->nr, clone_weightsystem(ws));
|
||||
}
|
||||
|
||||
cylinder_t clone_cylinder(cylinder_t cyl)
|
||||
{
|
||||
cylinder_t res = cyl;
|
||||
res.type.description = copy_string(res.type.description);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Add a clone of a cylinder to the end of a cylinder table.
|
||||
* Cloned in means that the description-string is copied. */
|
||||
void add_cloned_cylinder(struct cylinder_table *t, cylinder_t cyl)
|
||||
{
|
||||
cyl.type.description = copy_string(cyl.type.description);
|
||||
add_to_cylinder_table(t, t->nr, cyl);
|
||||
add_to_cylinder_table(t, t->nr, clone_cylinder(cyl));
|
||||
}
|
||||
|
||||
bool same_weightsystem(weightsystem_t w1, weightsystem_t w2)
|
||||
|
|
@ -151,15 +157,6 @@ bool same_weightsystem(weightsystem_t w1, weightsystem_t w2)
|
|||
same_string(w1.description, w2.description);
|
||||
}
|
||||
|
||||
bool same_cylinder(cylinder_t cyl1, cylinder_t cyl2)
|
||||
{
|
||||
return same_string(cyl1.type.description, cyl2.type.description) &&
|
||||
same_gasmix(cyl1.gasmix, cyl2.gasmix) &&
|
||||
cyl1.start.mbar == cyl2.start.mbar &&
|
||||
cyl1.end.mbar == cyl2.end.mbar &&
|
||||
cyl1.cylinder_use == cyl2.cylinder_use;
|
||||
}
|
||||
|
||||
void get_gas_string(struct gasmix gasmix, char *text, int len)
|
||||
{
|
||||
if (gasmix_is_air(gasmix))
|
||||
|
|
@ -377,6 +374,46 @@ cylinder_t *get_or_create_cylinder(struct dive *d, int idx)
|
|||
return &d->cylinders.cylinders[idx];
|
||||
}
|
||||
|
||||
/* if a default cylinder is set, use that */
|
||||
void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl)
|
||||
{
|
||||
const char *cyl_name = prefs.default_cylinder;
|
||||
struct tank_info_t *ti = tank_info;
|
||||
pressure_t pO2 = {.mbar = lrint(prefs.modpO2 * 1000.0)};
|
||||
|
||||
if (!cyl_name)
|
||||
return;
|
||||
while (ti->name != NULL && ti < tank_info + MAX_TANK_INFO) {
|
||||
if (strcmp(ti->name, cyl_name) == 0)
|
||||
break;
|
||||
ti++;
|
||||
}
|
||||
if (ti->name == NULL)
|
||||
/* didn't find it */
|
||||
return;
|
||||
cyl->type.description = strdup(ti->name);
|
||||
if (ti->ml) {
|
||||
cyl->type.size.mliter = ti->ml;
|
||||
cyl->type.workingpressure.mbar = ti->bar * 1000;
|
||||
} else {
|
||||
cyl->type.workingpressure.mbar = psi_to_mbar(ti->psi);
|
||||
if (ti->psi)
|
||||
cyl->type.size.mliter = lrint(cuft_to_l(ti->cuft) * 1000 / bar_to_atm(psi_to_bar(ti->psi)));
|
||||
}
|
||||
// MOD of air
|
||||
cyl->depth = gas_mod(cyl->gasmix, pO2, dive, 1);
|
||||
}
|
||||
|
||||
cylinder_t create_new_cylinder(const struct dive *d)
|
||||
{
|
||||
cylinder_t cyl = empty_cylinder;
|
||||
fill_default_cylinder(d, &cyl);
|
||||
cyl.start = cyl.type.workingpressure;
|
||||
cyl.manually_added = true;
|
||||
cyl.cylinder_use = OC_GAS;
|
||||
return cyl;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CYL
|
||||
void dump_cylinders(struct dive *dive, bool verbose)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ extern weightsystem_t clone_weightsystem(weightsystem_t ws);
|
|||
extern void free_weightsystem(weightsystem_t ws);
|
||||
extern void copy_cylinder_types(const struct dive *s, struct dive *d);
|
||||
extern void add_cloned_weightsystem(struct weightsystem_table *t, weightsystem_t ws);
|
||||
extern cylinder_t clone_cylinder(cylinder_t cyl);
|
||||
extern void free_cylinder(cylinder_t cyl);
|
||||
extern cylinder_t *add_empty_cylinder(struct cylinder_table *t);
|
||||
extern void add_cloned_cylinder(struct cylinder_table *t, cylinder_t cyl);
|
||||
extern cylinder_t *get_cylinder(const struct dive *d, int idx);
|
||||
|
|
@ -82,13 +84,14 @@ extern cylinder_t *get_or_create_cylinder(struct dive *d, int idx);
|
|||
extern void add_cylinder_description(const cylinder_type_t *);
|
||||
extern void add_weightsystem_description(const weightsystem_t *);
|
||||
extern bool same_weightsystem(weightsystem_t w1, weightsystem_t w2);
|
||||
extern bool same_cylinder(cylinder_t cyl1, cylinder_t cyl2);
|
||||
extern void remove_cylinder(struct dive *dive, int idx);
|
||||
extern void remove_weightsystem(struct dive *dive, int idx);
|
||||
extern void set_weightsystem(struct dive *dive, int idx, weightsystem_t ws);
|
||||
extern void reset_cylinders(struct dive *dive, bool track_gas);
|
||||
extern int gas_volume(const cylinder_t *cyl, pressure_t p); /* Volume in mliter of a cylinder at pressure 'p' */
|
||||
extern int find_best_gasmix_match(struct gasmix mix, const struct cylinder_table *cylinders);
|
||||
extern void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl); /* dive is needed to fill out MOD, which depends on salinity. */
|
||||
extern cylinder_t create_new_cylinder(const struct dive *dive); /* dive is needed to fill out MOD, which depends on salinity. */
|
||||
#ifdef DEBUG_CYL
|
||||
extern void dump_cylinders(struct dive *dive, bool verbose);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -698,31 +698,6 @@ static void try_to_match_autogroup(const char *name, char *buf)
|
|||
nonmatch("autogroup", name, buf);
|
||||
}
|
||||
|
||||
void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int seconds, int idx)
|
||||
{
|
||||
/* sanity check so we don't crash */
|
||||
if (idx < 0 || idx >= dive->cylinders.nr) {
|
||||
report_error("Unknown cylinder index: %d", idx);
|
||||
return;
|
||||
}
|
||||
/* The gas switch event format is insane for historical reasons */
|
||||
struct gasmix mix = get_cylinder(dive, idx)->gasmix;
|
||||
int o2 = get_o2(mix);
|
||||
int he = get_he(mix);
|
||||
struct event *ev;
|
||||
int value;
|
||||
|
||||
o2 = (o2 + 5) / 10;
|
||||
he = (he + 5) / 10;
|
||||
value = o2 + (he << 16);
|
||||
|
||||
ev = add_event(dc, seconds, he ? SAMPLE_EVENT_GASCHANGE2 : SAMPLE_EVENT_GASCHANGE, 0, value, "gaschange");
|
||||
if (ev) {
|
||||
ev->gas.index = idx;
|
||||
ev->gas.mix = mix;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_cylinderindex(char *buffer, uint8_t *i, struct parser_state *state)
|
||||
{
|
||||
*i = atoi(buffer);
|
||||
|
|
|
|||
|
|
@ -175,37 +175,6 @@ static int tissue_at_end(struct deco_state *ds, struct dive *dive, struct deco_s
|
|||
return surface_interval;
|
||||
}
|
||||
|
||||
|
||||
/* if a default cylinder is set, use that */
|
||||
void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl)
|
||||
{
|
||||
const char *cyl_name = prefs.default_cylinder;
|
||||
struct tank_info_t *ti = tank_info;
|
||||
pressure_t pO2 = {.mbar = 1600};
|
||||
|
||||
if (!cyl_name)
|
||||
return;
|
||||
while (ti->name != NULL && ti < tank_info + MAX_TANK_INFO) {
|
||||
if (strcmp(ti->name, cyl_name) == 0)
|
||||
break;
|
||||
ti++;
|
||||
}
|
||||
if (ti->name == NULL)
|
||||
/* didn't find it */
|
||||
return;
|
||||
cyl->type.description = strdup(ti->name);
|
||||
if (ti->ml) {
|
||||
cyl->type.size.mliter = ti->ml;
|
||||
cyl->type.workingpressure.mbar = ti->bar * 1000;
|
||||
} else {
|
||||
cyl->type.workingpressure.mbar = psi_to_mbar(ti->psi);
|
||||
if (ti->psi)
|
||||
cyl->type.size.mliter = lrint(cuft_to_l(ti->cuft) * 1000 / bar_to_atm(psi_to_bar(ti->psi)));
|
||||
}
|
||||
// MOD of air
|
||||
cyl->depth = gas_mod(cyl->gasmix, pO2, dive, 1);
|
||||
}
|
||||
|
||||
/* calculate the new end pressure of the cylinder, based on its current end pressure and the
|
||||
* latest segment. */
|
||||
static void update_cylinder_pressure(struct dive *d, int old_depth, int new_depth, int duration, int sac, cylinder_t *cyl, bool in_deco, enum divemode_t divemode)
|
||||
|
|
@ -315,7 +284,7 @@ static void create_dive_from_plan(struct diveplan *diveplan, struct dive *dive,
|
|||
}
|
||||
if (dp->divemode != type) {
|
||||
type = dp->divemode;
|
||||
add_event(dc, lasttime, 8, 0, type, "modechange");
|
||||
add_event(dc, lasttime, SAMPLE_EVENT_BOOKMARK, 0, type, "modechange");
|
||||
}
|
||||
|
||||
/* Create sample */
|
||||
|
|
|
|||
|
|
@ -120,19 +120,6 @@ struct ev_select *ev_namelist;
|
|||
int evn_allocated;
|
||||
int evn_used;
|
||||
|
||||
#if WE_DONT_USE_THIS /* we need to implement event filters in Qt */
|
||||
int evn_foreach (void (*callback)(const char *, bool *, void *), void *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < evn_used; i++) {
|
||||
/* here we display an event name on screen - so translate */
|
||||
callback(translate("gettextFromC", ev_namelist[i].ev_name), &ev_namelist[i].plot_ev, data);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
#endif /* WE_DONT_USE_THIS */
|
||||
|
||||
void clear_events(void)
|
||||
{
|
||||
for (int i = 0; i < evn_used; i++)
|
||||
|
|
|
|||
|
|
@ -1662,3 +1662,36 @@ extern "C" char *get_changes_made()
|
|||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Generate a cylinder-renumber map for use when the n-th cylinder
|
||||
// of a dive with count cylinders is removed. It fills an int vector
|
||||
// with 0..n, -1, n..count-1. Each entry in the vector represents
|
||||
// the new id of the cylinder, whereby <0 means that this particular
|
||||
// cylinder does not get any new id. This should probably be moved
|
||||
// to the C-core, but using std::vector is simply more convenient.
|
||||
// The function assumes that n < count!
|
||||
std::vector<int> get_cylinder_map_for_remove(int count, int n)
|
||||
{
|
||||
// 1) Fill mapping[0]..mapping[n-1] with 0..n-1
|
||||
// 2) Set mapping[n] to -1
|
||||
// 3) Fill mapping[n+1]..mapping[count-1] with n..count-2
|
||||
std::vector<int> mapping(count);
|
||||
std::iota(mapping.begin(), mapping.begin() + n, 0);
|
||||
mapping[n] = -1;
|
||||
std::iota(mapping.begin() + n + 1, mapping.end(), n);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
// Generate a cylinder-renumber map for use when a cylinder is added
|
||||
// before the n-th cylinder. It fills an int vector with
|
||||
// with 0..n-1, n+1..count. Each entry in the vector represents
|
||||
// the new id of the cylinder. This probably should be moved
|
||||
// to the C-core, but using std::vector is simply more convenient.
|
||||
// This function assumes that that n <= count!
|
||||
std::vector<int> get_cylinder_map_for_add(int count, int n)
|
||||
{
|
||||
std::vector<int> mapping(count);
|
||||
std::iota(mapping.begin(), mapping.begin() + n, 0);
|
||||
std::iota(mapping.begin() + n, mapping.end(), n + 1);
|
||||
return mapping;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ QLocale getLocale();
|
|||
QVector<QPair<QString, int>> selectedDivesGasUsed();
|
||||
QString getUserAgent();
|
||||
QString printGPSCoords(const location_t *loc);
|
||||
std::vector<int> get_cylinder_map_for_remove(int count, int n);
|
||||
std::vector<int> get_cylinder_map_for_add(int count, int n);
|
||||
|
||||
extern QString (*changesCallback)();
|
||||
void uiNotification(const QString &msg);
|
||||
|
|
|
|||
|
|
@ -87,6 +87,9 @@ signals:
|
|||
void divesTimeChanged(timestamp_t delta, const QVector<dive *> &dives);
|
||||
|
||||
void cylindersReset(const QVector<dive *> &dives);
|
||||
void cylinderAdded(dive *d, int pos);
|
||||
void cylinderRemoved(dive *d, int pos);
|
||||
void cylinderEdited(dive *d, int pos);
|
||||
void weightsystemsReset(const QVector<dive *> &dives);
|
||||
void weightAdded(dive *d, int pos);
|
||||
void weightRemoved(dive *d, int pos);
|
||||
|
|
@ -110,6 +113,9 @@ signals:
|
|||
void numShownChanged();
|
||||
void filterReset();
|
||||
|
||||
// Event-related signals. Currently, we're very blunt: only one signal for any changes to the events.
|
||||
void eventsChanged(dive *d);
|
||||
|
||||
// This signal is emited every time a command is executed.
|
||||
// This is used to hide an old multi-dives-edited warning message.
|
||||
// This is necessary, so that the user can't click on the "undo" button and undo
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue