diff options
-rw-r--r-- | dive.h | 6 | ||||
-rw-r--r-- | divelist.c | 24 | ||||
-rw-r--r-- | divelist.h | 1 | ||||
-rw-r--r-- | gtk-gui.c | 110 | ||||
-rw-r--r-- | planner.c | 80 |
5 files changed, 203 insertions, 18 deletions
@@ -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 @@ -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); } @@ -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); } |