summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dive.h6
-rw-r--r--divelist.c24
-rw-r--r--divelist.h1
-rw-r--r--gtk-gui.c110
-rw-r--r--planner.c80
5 files changed, 203 insertions, 18 deletions
diff --git a/dive.h b/dive.h
index aae57e8b7..697ab8512 100644
--- a/dive.h
+++ b/dive.h
@@ -595,8 +595,12 @@ struct diveplan {
};
extern void test_planner(void);
-void plan(struct diveplan *diveplan);
+void plan(struct diveplan *diveplan, char **cache_datap, struct dive **divep);
void plan_add_segment(struct diveplan *diveplan, int duration, int depth, int o2, int he);
+void add_duration_to_nth_dp(struct diveplan *diveplan, int idx, int duration);
+void add_depth_to_nth_dp(struct diveplan *diveplan, int idx, int depth);
+void add_gas_to_nth_dp(struct diveplan *diveplan, int idx, int o2, int he);
+void free_dps(struct divedatapoint *dp);
#ifdef DEBUGFILE
extern char *debugfilename;
diff --git a/divelist.c b/divelist.c
index fd141ba28..6397f62fd 100644
--- a/divelist.c
+++ b/divelist.c
@@ -1304,6 +1304,30 @@ static void clear_trip_indexes(void)
trip->index = 0;
}
+void select_last_dive(void)
+{
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ struct dive *dive;
+ int i;
+
+ /* select the last dive (and make sure it's an actual dive that is selected) */
+ /* WARNING - this only works when sorted by date!!!
+ *
+ *
+ *
+ */
+ gtk_tree_model_get_iter_first(MODEL(dive_list), &iter);
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
+ gtk_tree_selection_unselect_all(selection);
+ for_each_dive(i, dive)
+ dive->selected = FALSE;
+ amount_selected = 0;
+ gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &selected_dive, -1);
+ first_leaf(MODEL(dive_list), &iter, &selected_dive);
+ gtk_tree_selection_select_iter(selection, &iter);
+}
+
static void fill_dive_list(void)
{
int i, trip_index = 0;
diff --git a/divelist.h b/divelist.h
index 1690ec657..89762187b 100644
--- a/divelist.h
+++ b/divelist.h
@@ -15,5 +15,6 @@ extern void remember_tree_state(void);
extern void restore_tree_state(void);
extern void select_next_dive(void);
extern void select_prev_dive(void);
+extern void select_last_dive(void);
extern double init_decompression(struct dive * dive);
#endif
diff --git a/gtk-gui.c b/gtk-gui.c
index ee6008c1a..70be30120 100644
--- a/gtk-gui.c
+++ b/gtk-gui.c
@@ -1322,19 +1322,106 @@ static GtkWidget *add_entry_to_box(GtkWidget *box, const char *label)
GtkWidget *entry_depth[MAX_WAYPOINTS], *entry_duration[MAX_WAYPOINTS], *entry_gas[MAX_WAYPOINTS];
int nr_waypoints = 0;
static GtkListStore *gas_model = NULL;
+struct diveplan diveplan = {};
+char *cache_data = NULL;
+struct dive *planned_dive = NULL;
+
+/* make a copy of the diveplan so far and display the corresponding dive */
+void show_planned_dive(void)
+{
+ struct diveplan tempplan;
+ struct divedatapoint *dp, **dpp;
+
+ memcpy(&tempplan, &diveplan, sizeof(struct diveplan));
+ dpp = &tempplan.dp;
+ dp = diveplan.dp;
+ while(*dpp) {
+ *dpp = malloc(sizeof(struct divedatapoint));
+ memcpy(*dpp, dp, sizeof(struct divedatapoint));
+ dp = dp->next;
+ if (dp && !dp->time) {
+ /* we have an incomplete entry - stop before it */
+ (*dpp)->next = NULL;
+ break;
+ }
+ dpp = &(*dpp)->next;
+ }
+ plan(&tempplan, &cache_data, &planned_dive);
+ free_dps(tempplan.dp);
+}
-static gboolean gas_focus_out_cb(GtkWidget *entry, gpointer data)
+static gboolean gas_focus_out_cb(GtkWidget *entry, GdkEvent *event, gpointer data)
{
char *gastext;
int o2, he;
+ int idx = data - NULL;
gastext = strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
- if (validate_gas(gastext, &o2, &he))
+ if (validate_gas(gastext, &o2, &he)) {
add_string_list_entry(gastext, gas_model);
+ add_gas_to_nth_dp(&diveplan, idx, o2, he);
+ show_planned_dive();
+ } else {
+ /* we need to instead change the color of the input field or something */
+ printf("invalid gas for row %d\n",idx);
+ }
free(gastext);
return FALSE;
}
+static gboolean depth_focus_out_cb(GtkWidget *entry, GdkEvent *event, gpointer data)
+{
+ char *depthtext;
+ int depth;
+ int idx = data - NULL;
+
+ depthtext = strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
+ if (validate_depth(depthtext, &depth)) {
+ add_depth_to_nth_dp(&diveplan, idx, depth);
+ show_planned_dive();
+ } else {
+ /* we need to instead change the color of the input field or something */
+ printf("invalid depth for row %d\n", idx);
+ }
+ free(depthtext);
+ return FALSE;
+}
+
+static gboolean duration_focus_out_cb(GtkWidget *entry, GdkEvent * event, gpointer data)
+{
+ char *durationtext;
+ int duration, is_rel;
+ int idx = data - NULL;
+
+ durationtext = strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
+ if (validate_time(durationtext, &duration, &is_rel)) {
+ add_duration_to_nth_dp(&diveplan, idx, duration);
+ show_planned_dive();
+ } else {
+ /* we need to instead change the color of the input field or something */
+ printf("invalid duration for row %d\n", idx);
+ }
+ free(durationtext);
+ return FALSE;
+}
+
+static gboolean starttime_focus_out_cb(GtkWidget *entry, GdkEvent * event, gpointer data)
+{
+ char *starttimetext;
+ int starttime, is_rel;
+
+ starttimetext = strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
+ if (validate_time(starttimetext, &starttime, &is_rel)) {
+ /* we alway make this relative for now */
+ diveplan.when = time(NULL) + starttime;
+ } else {
+ /* we need to instead change the color of the input field or something */
+ printf("invalid starttime\n");
+ }
+ free(starttimetext);
+ return FALSE;
+}
+
static GtkWidget *add_gas_combobox_to_box(GtkWidget *box, const char *label)
{
GtkWidget *frame, *combo;
@@ -1386,6 +1473,10 @@ static void add_waypoint_widgets(GtkWidget *box, int idx)
entry_duration[idx] = add_entry_to_box(hbox, NULL);
entry_gas[idx] = add_gas_combobox_to_box(hbox, NULL);
}
+ gtk_widget_add_events(entry_depth[idx], GDK_FOCUS_CHANGE_MASK);
+ g_signal_connect(entry_depth[idx], "focus-out-event", G_CALLBACK(depth_focus_out_cb), NULL + idx);
+ gtk_widget_add_events(entry_duration[idx], GDK_FOCUS_CHANGE_MASK);
+ g_signal_connect(entry_duration[idx], "focus-out-event", G_CALLBACK(duration_focus_out_cb), NULL + idx);
}
static void add_waypoint_cb(GtkButton *button, gpointer _data)
@@ -1407,8 +1498,12 @@ void input_plan()
{
GtkWidget *planner, *content, *vbox, *outervbox, *add_row, *deltat;
int lasttime = 0;
- struct diveplan diveplan = {};
+ char starttimebuf[64] = "+60:00";
+ if (diveplan.dp)
+ free_dps(diveplan.dp);
+ memset(&diveplan, 0, sizeof(diveplan));
+ planned_dive = NULL;
planner = gtk_dialog_new_with_buttons(_("Dive Plan - THIS IS JUST A SIMULATION; DO NOT USE FOR DIVING"),
GTK_WINDOW(main_window),
GTK_DIALOG_DESTROY_WITH_PARENT,
@@ -1422,6 +1517,11 @@ void input_plan()
vbox = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(outervbox), vbox, TRUE, TRUE, 0);
deltat = add_entry_to_box(vbox, _("Dive starts in how many minutes?"));
+ gtk_entry_set_max_length(GTK_ENTRY(deltat), 12);
+ gtk_entry_set_text(GTK_ENTRY(deltat), starttimebuf);
+ gtk_widget_add_events(deltat, GDK_FOCUS_CHANGE_MASK);
+ g_signal_connect(deltat, "focus-out-event", G_CALLBACK(starttime_focus_out_cb), NULL);
+ diveplan.when = time(NULL) + 3600;
nr_waypoints = 4;
add_waypoint_widgets(vbox, 0);
add_waypoint_widgets(vbox, 1);
@@ -1437,6 +1537,8 @@ void input_plan()
deltattext = gtk_entry_get_text(GTK_ENTRY(deltat));
diveplan.when = time(NULL) + 60 * atoi(deltattext);
+ free_dps(diveplan.dp);
+ diveplan.dp = 0;
for (i = 0; i < nr_waypoints; i++) {
char *depthtext, *durationtext, *gastext;
int depth, duration, o2, he, is_rel;
@@ -1477,7 +1579,7 @@ void input_plan()
free(gastext);
}
}
- plan(&diveplan);
+ show_planned_dive();
gtk_widget_destroy(planner);
}
diff --git a/planner.c b/planner.c
index 9d20d376f..13a36e62b 100644
--- a/planner.c
+++ b/planner.c
@@ -8,7 +8,7 @@
#include "dive.h"
#include "divelist.h"
-int stoplevels[] = { 3000, 6000, 9000, 12000, 15000, 21000, 30000, 42000, 60000, 90000 };
+int stoplevels[] = { 0, 3000, 6000, 9000, 12000, 15000, 21000, 30000, 42000, 60000, 90000 };
/* returns the tissue tolerance at the end of this (partial) dive */
double tissue_at_end(struct dive *dive, char **cached_datap)
@@ -108,7 +108,7 @@ struct dive *create_dive_from_plan(struct diveplan *diveplan)
dc = &dive->dc;
dc->model = "Simulated Dive";
dp = diveplan->dp;
- while (dp) {
+ while (dp && dp->time) {
int i, depth;
if (dp->o2 != dive->cylinder[gasused].gasmix.o2.permille ||
@@ -132,9 +132,23 @@ struct dive *create_dive_from_plan(struct diveplan *diveplan)
dp = dp->next;
dc->samples++;
}
+ if (dc->samples == 0) {
+ /* not enough there yet to create a dive - most likely the first time is missing */
+ free(dive);
+ dive = NULL;
+ }
return dive;
}
+void free_dps(struct divedatapoint *dp)
+{
+ while (dp) {
+ struct divedatapoint *ndp = dp->next;
+ free(dp);
+ dp = ndp;
+ }
+}
+
struct divedatapoint *create_dp(int time_incr, int depth, int o2, int he)
{
struct divedatapoint *dp;
@@ -148,6 +162,41 @@ struct divedatapoint *create_dp(int time_incr, int depth, int o2, int he)
return dp;
}
+struct divedatapoint *get_nth_dp(struct diveplan *diveplan, int idx)
+{
+ struct divedatapoint **ldpp, *dp = diveplan->dp;
+ int i = 0;
+ ldpp = &diveplan->dp;
+
+ while (dp && i++ < idx) {
+ ldpp = &dp->next;
+ dp = dp->next;
+ }
+ while (i++ <= idx) {
+ *ldpp = dp = create_dp(0, 0, 0, 0);
+ ldpp = &((*ldpp)->next);
+ }
+ return dp;
+}
+
+void add_duration_to_nth_dp(struct diveplan *diveplan, int idx, int duration)
+{
+ struct divedatapoint *dp = get_nth_dp(diveplan, idx);
+ dp->time = duration;
+}
+
+void add_depth_to_nth_dp(struct diveplan *diveplan, int idx, int depth)
+{
+ struct divedatapoint *dp = get_nth_dp(diveplan, idx);
+ dp->depth = depth;
+}
+
+void add_gas_to_nth_dp(struct diveplan *diveplan, int idx, int o2, int he)
+{
+ struct divedatapoint *dp = get_nth_dp(diveplan, idx);
+ dp->o2 = o2;
+ dp->he = he;
+}
void add_to_end_of_diveplan(struct diveplan *diveplan, struct divedatapoint *dp)
{
struct divedatapoint **lastdp = &diveplan->dp;
@@ -167,7 +216,7 @@ void plan_add_segment(struct diveplan *diveplan, int duration, int depth, int o2
add_to_end_of_diveplan(diveplan, dp);
}
-void plan(struct diveplan *diveplan)
+void plan(struct diveplan *diveplan, char **cached_datap, struct dive **divep)
{
struct dive *dive;
struct sample *sample;
@@ -175,11 +224,12 @@ void plan(struct diveplan *diveplan)
int ceiling, depth, transitiontime;
int stopidx;
double tissue_tolerance;
- char *cached_data = NULL;
if (!diveplan->surface_pressure)
diveplan->surface_pressure = 1013;
- dive = create_dive_from_plan(diveplan);
+ if (*divep)
+ delete_single_dive(dive_table.nr - 1);
+ *divep = dive = create_dive_from_plan(diveplan);
if (!dive)
return;
record_dive(dive);
@@ -188,42 +238,44 @@ void plan(struct diveplan *diveplan)
o2 = dive->cylinder[sample->sensor].gasmix.o2.permille;
he = dive->cylinder[sample->sensor].gasmix.he.permille;
- tissue_tolerance = tissue_at_end(dive, &cached_data);
+ tissue_tolerance = tissue_at_end(dive, cached_datap);
ceiling = deco_allowed_depth(tissue_tolerance, diveplan->surface_pressure / 1000.0, dive, 1);
- for (stopidx = 0; stopidx < sizeof(stoplevels) / sizeof(int); stopidx++)
+ for (stopidx = 1; stopidx < sizeof(stoplevels) / sizeof(int); stopidx++)
if (stoplevels[stopidx] >= ceiling)
break;
- while (stopidx >= 0) {
+ while (stopidx > 0) {
depth = dive->dc.sample[dive->dc.samples - 1].depth.mm;
if (depth > stoplevels[stopidx]) {
transitiontime = (depth - stoplevels[stopidx]) / 150;
plan_add_segment(diveplan, transitiontime, stoplevels[stopidx], o2, he);
/* re-create the dive */
delete_single_dive(dive_table.nr - 1);
- dive = create_dive_from_plan(diveplan);
+ *divep = dive = create_dive_from_plan(diveplan);
record_dive(dive);
}
- wait_time = time_at_last_depth(dive, stoplevels[stopidx - 1], &cached_data);
+ wait_time = time_at_last_depth(dive, stoplevels[stopidx - 1], cached_datap);
if (wait_time)
plan_add_segment(diveplan, wait_time, stoplevels[stopidx], o2, he);
transitiontime = (stoplevels[stopidx] - stoplevels[stopidx - 1]) / 150;
plan_add_segment(diveplan, transitiontime, stoplevels[stopidx - 1], o2, he);
/* re-create the dive */
delete_single_dive(dive_table.nr - 1);
- dive = create_dive_from_plan(diveplan);
+ *divep = dive = create_dive_from_plan(diveplan);
record_dive(dive);
stopidx--;
}
/* now make the dive visible as last dive of the dive list */
- free(cached_data);
report_dives(FALSE, FALSE);
+ select_last_dive();
}
void test_planner()
{
+ struct dive *dive = NULL;
struct diveplan diveplan = {};
+ char *cache_data;
int end_of_last_dive = dive_table.dives[dive_table.nr - 1]->when + dive_table.dives[dive_table.nr -1]->duration.seconds;
diveplan.when = end_of_last_dive + 50 * 3600; /* don't take previous dives into account for deco calculation */
diveplan.surface_pressure = 1013;
@@ -232,5 +284,7 @@ void test_planner()
plan_add_segment(&diveplan, 59, 27000, 209, 0);
plan_add_segment(&diveplan, 1, 27000, 400, 0);
- plan(&diveplan);
+ plan(&diveplan, &cache_data, &dive);
+ /* we are not rerunning the plan, so free the cache right away */
+ free(cache_data);
}