diff --git a/dive.h b/dive.h index 11b003f68..24f2f37e8 100644 --- a/dive.h +++ b/dive.h @@ -28,6 +28,18 @@ #define SEAWATER_SALINITY 10300 #define FRESHWATER_SALINITY 10000 +/* Dive types definition */ +#define DTYPE_INVALID 1 +#define DTYPE_BOAT 2 +#define DTYPE_SHORE 4 +#define DTYPE_DRIFT 8 +#define DTYPE_DEEP 16 +#define DTYPE_CAVERN 32 +#define DTYPE_ICE 64 +#define DTYPE_WRECK 128 +#define DTYPE_CAVE 256 +#define DTYPE_ALTITUDE 512 +#define DTYPE_POOL 1024 /* * Some silly typedefs to make our units very explicit. @@ -342,6 +354,7 @@ struct dive { pressure_t surface_pressure; duration_t duration; int salinity; // kg per 10000 l + int dive_tags; struct divecomputer dc; }; diff --git a/divelist-gtk.c b/divelist-gtk.c index dc441881c..c8ad1a6ca 100644 --- a/divelist-gtk.c +++ b/divelist-gtk.c @@ -715,7 +715,10 @@ static void fill_dive_list(void) i = dive_table.nr; while (--i >= 0) { struct dive *dive = get_dive(i); - dive_trip_t *trip = dive->divetrip; + dive_trip_t *trip; + if ((dive->dive_tags & DTYPE_INVALID) && !prefs.display_invalid_dives) + continue; + trip = dive->divetrip; if (!trip) { parent_ptr = NULL; @@ -1061,6 +1064,42 @@ static void save_as_cb(GtkWidget *menuitem, struct dive *dive) } } +static void invalid_dives_cb(GtkWidget *menuitem, GtkTreePath *path) +{ + int i; + int changed = 0; + struct dive *dive; + + if (!amount_selected) + return; + /* walk the dive list in chronological order */ + for_each_dive(i, dive) { + dive = get_dive(i); + if (!dive) + continue; + if (!dive->selected) + continue; + /* now swap the invalid tag if just 1 dive was selected + * otherwise set all to invalid */ + if(amount_selected == 1) { + if (dive->dive_tags & DTYPE_INVALID) + dive->dive_tags &= ~DTYPE_INVALID; + else + dive->dive_tags |= DTYPE_INVALID; + changed = 1; + } else { + if (! dive->dive_tags & DTYPE_INVALID) { + dive->dive_tags |= DTYPE_INVALID; + changed = 1; + } + } + } + if (changed) { + dive_list_update_dives(); + mark_divelist_changed(TRUE); + } +} + static void expand_all_cb(GtkWidget *menuitem, GtkTreeView *tree_view) { gtk_tree_view_expand_all(tree_view); @@ -1626,7 +1665,7 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); } else { dive = get_dive(idx); - /* if we right click on selected dive(s), edit or delete those */ + /* if we right click on selected dive(s), edit, delete or tag them as invalid */ if (dive->selected) { if (amount_selected == 1) { deletelabel = _(deletesinglelabel); @@ -1642,6 +1681,17 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int g_signal_connect(menuitem, "activate", G_CALLBACK(save_as_cb), dive); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + if (amount_selected == 1) { + if (dive->dive_tags & DTYPE_INVALID) + menuitem = gtk_menu_item_new_with_label(_("Mark valid")); + else + menuitem = gtk_menu_item_new_with_label(_("Mark invalid")); + } else { + menuitem = gtk_menu_item_new_with_label(_("Mark invalid")); + } + g_signal_connect(menuitem, "activate", G_CALLBACK(invalid_dives_cb), path); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + menuitem = gtk_menu_item_new_with_label(deletelabel); g_signal_connect(menuitem, "activate", G_CALLBACK(delete_selected_dives_cb), path); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); diff --git a/gtk-gui.c b/gtk-gui.c index c7714e5fe..81497436a 100644 --- a/gtk-gui.c +++ b/gtk-gui.c @@ -626,6 +626,7 @@ OPTIONCALLBACK(maxcns_toggle, prefs.visible_cols.maxcns) OPTIONCALLBACK(sac_toggle, prefs.visible_cols.sac) OPTIONCALLBACK(nitrox_toggle, prefs.visible_cols.nitrox) OPTIONCALLBACK(temperature_toggle, prefs.visible_cols.temperature) +OPTIONCALLBACK(display_invalid_dives_toggle, prefs.display_invalid_dives) OPTIONCALLBACK(totalweight_toggle, prefs.visible_cols.totalweight) OPTIONCALLBACK(suit_toggle, prefs.visible_cols.suit) OPTIONCALLBACK(cylinder_toggle, prefs.visible_cols.cylinder) @@ -852,6 +853,11 @@ static void preferences_dialog(GtkWidget *w, gpointer data) box = gtk_hbox_new(FALSE, 6); gtk_container_add(GTK_CONTAINER(frame), box); + button = gtk_check_button_new_with_label(_("Display invalid dives")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.display_invalid_dives); + gtk_box_pack_end(GTK_BOX(box), button, FALSE, FALSE, 6); + g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(display_invalid_dives_toggle), NULL); + frame = gtk_frame_new(_("Default XML Data File")); gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5); hbox = gtk_hbox_new(FALSE, 6); @@ -1073,6 +1079,7 @@ static void preferences_dialog(GtkWidget *w, gpointer data) free((void *)provider); #endif save_preferences(); + dive_list_update_dives(); } else if (result == GTK_RESPONSE_CANCEL) { prefs = oldprefs; set_gf(prefs.gflow, prefs.gfhigh); diff --git a/info.c b/info.c index 455fbea1a..26a3f471a 100644 --- a/info.c +++ b/info.c @@ -606,6 +606,10 @@ static void save_dive_info_changes(struct dive *dive, struct dive *master, struc if (old_text) g_free(old_text); } + if (dive->dive_tags != master->dive_tags) { + changed = 1; + dive->dive_tags = master->dive_tags; + } if (changed) { mark_divelist_changed(TRUE); update_dive(dive); @@ -793,9 +797,18 @@ static gboolean base_data_cb(GtkWidget *w, GdkEvent *event, gpointer _data) return FALSE; } +void divetag_toggle_cb(GtkWidget *widget, gpointer data) +{ + int DT = GPOINTER_TO_INT (data); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) + edit_dive.dive_tags |= DT; + else + edit_dive.dive_tags &= ~DT; +} + static void dive_info_widget(GtkWidget *obox, struct dive *dive, struct dive_info *info, gboolean multi) { - GtkWidget *hbox, *frame, *equipment, *ibox, *box; + GtkWidget *hbox, *frame, *equipment, *ibox, *box, *button, *sbox, *framebox; #if HAVE_OSM_GPS_MAP GtkWidget *image; #endif @@ -870,6 +883,66 @@ static void dive_info_widget(GtkWidget *obox, struct dive *dive, struct dive_inf airtemp[0] = '\0'; info->airtemp = single_text_entry(hbox, buffer, airtemp); + frame = gtk_frame_new(_("Dive Type")); + gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 0); + + framebox = gtk_vbox_new(FALSE, 3); + gtk_container_add(GTK_CONTAINER(frame), framebox); + + sbox = gtk_hbox_new(FALSE, 6); + gtk_box_pack_start(GTK_BOX(framebox), sbox, TRUE, FALSE, 3); +/* 1st line */ + button = gtk_check_button_new_with_label(_("Boat Dive")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_BOAT); + gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6); + g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_BOAT)); + + button = gtk_check_button_new_with_label(_("Shore Dive")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_SHORE); + gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6); + g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_SHORE)); + + button = gtk_check_button_new_with_label(_("Pool Dive")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_POOL); + gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6); + g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_POOL)); + + sbox = gtk_hbox_new(FALSE, 6); + gtk_box_pack_start(GTK_BOX(framebox), sbox, TRUE, FALSE, 3); +/* 2nd line */ + button = gtk_check_button_new_with_label(_("Drift Dive")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_DRIFT); + gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6); + g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_DRIFT)); + + button = gtk_check_button_new_with_label(_("Deep Dive")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_DEEP); + gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6); + g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_DEEP)); + + button = gtk_check_button_new_with_label(_("Cavern Dive")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_CAVERN); + gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6); + g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_CAVERN)); + + sbox = gtk_hbox_new(FALSE, 6); + gtk_box_pack_start(GTK_BOX(framebox), sbox, TRUE, FALSE, 3); +/* 3rd line */ + button = gtk_check_button_new_with_label(_("Ice Dive")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_ICE); + gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6); + g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_ICE)); + + button = gtk_check_button_new_with_label(_("Wreck Dive")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_WRECK); + gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6); + g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_WRECK)); + + button = gtk_check_button_new_with_label(_("Cave Dive")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_CAVE); + gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6); + g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_CAVE)); + /* only show notes if editing a single dive */ if (multi) { info->notes = NULL; diff --git a/parse-xml.c b/parse-xml.c index 4701a173a..431cd376d 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -1033,6 +1033,8 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) if (MATCH(".number", get_index, &dive->number)) return; + if (MATCH(".tags", get_index, &dive->dive_tags)) + return; if (MATCH(".tripflag", get_tripflag, &dive->tripflag)) return; if (MATCH(".date", divedate, &dive->when)) diff --git a/pref.h b/pref.h index 60fe1104c..3c6b43c70 100644 --- a/pref.h +++ b/pref.h @@ -36,6 +36,7 @@ struct preferences { int map_provider; const char *divelist_font; const char *default_filename; + short display_invalid_dives; }; extern struct preferences prefs, default_prefs; diff --git a/prefs.c b/prefs.c index 7d41c0cf6..d1073c88f 100644 --- a/prefs.c +++ b/prefs.c @@ -113,6 +113,7 @@ void save_preferences(void) SAVE_STRING("default_filename", default_filename); SAVE_INT("map_provider", map_provider); + SAVE_INT("display_invalid_dives", display_invalid_dives); /* Flush the changes out to the system */ subsurface_flush_conf(); @@ -204,6 +205,10 @@ void load_preferences(void) prefs.default_filename = conf_value; int_value = subsurface_get_conf_int("map_provider"); - if(int_value >= 0) + if (int_value >= 0) prefs.map_provider = int_value; + + int_value = subsurface_get_conf_int("display_invalid_dives"); + if (int_value >= 0) + prefs.display_invalid_dives = int_value; } diff --git a/save-xml.c b/save-xml.c index 7ae71dd57..d7ac878c5 100644 --- a/save-xml.c +++ b/save-xml.c @@ -451,6 +451,8 @@ void save_dive(FILE *f, struct dive *dive) fprintf(f, " rating='%d'", dive->rating); if (dive->visibility) fprintf(f, " visibility='%d'", dive->visibility); + if (dive->dive_tags) + fprintf(f, " tags='%d'", dive->dive_tags); show_date(f, dive->when); fprintf(f, " duration='%u:%02u min'>\n", FRACTION(dive->dc.duration.seconds, 60)); diff --git a/statistics.c b/statistics.c index 502c06cb4..552694563 100644 --- a/statistics.c +++ b/statistics.c @@ -28,7 +28,8 @@ typedef struct { *sac, *otu, *o2he, - *gas_used; + *gas_used, + *dive_type; } single_stat_widget_t; static single_stat_widget_t single_w; @@ -631,6 +632,38 @@ static void show_single_dive_stats(struct dive *dive) } else { set_label(single_w.gas_used, ""); } + /* Dive type */ + if (dive->dive_tags) { + buf[0]=0; + if(dive->dive_tags & DTYPE_INVALID) + strcat(buf, " Invalid,"); + if(dive->dive_tags & DTYPE_BOAT) + strcat(buf, " Boat,"); + if(dive->dive_tags & DTYPE_SHORE) + strcat(buf, " Shore,"); + if(dive->dive_tags & DTYPE_DRIFT) + strcat(buf, " Drift,"); + if(dive->dive_tags & DTYPE_DEEP) + strcat(buf, " Deep,"); + if(dive->dive_tags & DTYPE_CAVERN) + strcat(buf, " Cavern,"); + if(dive->dive_tags & DTYPE_ICE) + strcat(buf, " Ice,"); + if(dive->dive_tags & DTYPE_WRECK) + strcat(buf, " Wreck,"); + if(dive->dive_tags & DTYPE_CAVE) + strcat(buf, " Cave,"); + if(dive->dive_tags & DTYPE_ALTITUDE) + strcat(buf, " Altitude,"); + if(dive->dive_tags & DTYPE_POOL) + strcat(buf, " Pool,"); + if(strlen(buf) > 1) + buf[strlen(buf)-1] = 0; + } + else { + buf[0] = 0; + } + set_label(single_w.dive_type, buf); } /* this gets called when at least two but not all dives are selected */ @@ -865,6 +898,12 @@ GtkWidget *single_stats_widget(void) single_w.o2he = new_info_label_in_frame(hbox, "O" UTF8_SUBSCRIPT_2 " / He"); single_w.gas_used = new_info_label_in_frame(hbox, C_("Amount","Gas Used")); + /* fifth row */ + hbox = gtk_hbox_new(FALSE, 3); + gtk_box_pack_start(GTK_BOX(framebox), hbox, TRUE, FALSE, 3); + + single_w.dive_type = new_info_label_in_frame(hbox, _("Dive Type")); + return vbox; } @@ -884,6 +923,7 @@ void clear_stats_widgets(void) set_label(single_w.otu, ""); set_label(single_w.o2he, ""); set_label(single_w.gas_used, ""); + set_label(single_w.dive_type, ""); set_label(stats_w.total_time,""); set_label(stats_w.avg_time,""); set_label(stats_w.shortest_time,"");