diff options
-rw-r--r-- | display-gtk.h | 16 | ||||
-rw-r--r-- | display.h | 4 | ||||
-rw-r--r-- | dive.c | 15 | ||||
-rw-r--r-- | dive.h | 25 | ||||
-rw-r--r-- | divelist.c | 87 | ||||
-rw-r--r-- | equipment.c | 16 | ||||
-rw-r--r-- | gtk-gui.c | 217 | ||||
-rw-r--r-- | info.c | 70 | ||||
-rw-r--r-- | macos.c | 4 | ||||
-rw-r--r-- | parse-xml.c | 25 | ||||
-rw-r--r-- | print.c | 151 | ||||
-rw-r--r-- | profile.c | 159 | ||||
-rw-r--r-- | statistics.c | 4 |
13 files changed, 520 insertions, 273 deletions
diff --git a/display-gtk.h b/display-gtk.h index f52b75639..b2903d7e9 100644 --- a/display-gtk.h +++ b/display-gtk.h @@ -31,11 +31,16 @@ typedef struct { double phe_threshold; } partial_pressure_graphs_t; -extern visible_cols_t visible_cols; -extern partial_pressure_graphs_t partial_pressure_graphs; -extern gboolean profile_red_ceiling; +struct preferences { + struct units output_units; + visible_cols_t visible_cols; + partial_pressure_graphs_t pp_graphs; + gboolean profile_red_ceiling; +}; -#define GRAPHS_ENABLED (partial_pressure_graphs.po2 || partial_pressure_graphs.pn2 || partial_pressure_graphs.phe) +extern struct preferences prefs; + +#define PP_GRAPHS_ENABLED (prefs.pp_graphs.po2 || prefs.pp_graphs.pn2 || prefs.pp_graphs.phe) typedef enum { PREF_BOOL, @@ -66,6 +71,7 @@ extern const char *subsurface_icon_name(void); extern void subsurface_ui_setup(GtkSettings *settings, GtkWidget *menubar, GtkWidget *vbox, GtkUIManager *ui_manager); extern void quit(GtkWidget *w, gpointer data); +extern gboolean on_delete(GtkWidget* w, gpointer data); extern int is_default_dive_computer_device(const char *name); @@ -80,6 +86,8 @@ extern int process_ui_events(void); extern void update_progressbar(progressbar_t *progress, double value); extern void update_progressbar_text(progressbar_t *progress, const char *text); +extern GtkWidget *create_date_time_widget(struct tm *time, GtkWidget **cal, GtkWidget **h, GtkWidget **m); + extern GtkWidget *dive_profile_widget(void); extern GtkWidget *dive_info_frame(void); extern GtkWidget *extended_dive_info_widget(void); @@ -16,8 +16,8 @@ struct plot_info { int nr; int maxtime; int meandepth, maxdepth; - int endpressure, maxpressure; - int mintemp, maxtemp, endtemp; + int minpressure, maxpressure; + int mintemp, maxtemp; double endtempcoord; double maxpp; gboolean has_ndl; @@ -34,8 +34,9 @@ int get_pressure_units(unsigned int mb, const char **units) { int pressure; const char* unit; + struct units *output_units_p = get_output_units(); - switch (output_units.pressure) { + switch (output_units_p->pressure) { case PASCAL: pressure = mb * 100; unit = _("pascal"); @@ -58,8 +59,9 @@ double get_temp_units(unsigned int mk, const char **units) { double deg; const char *unit; + struct units *output_units_p = get_output_units(); - if (output_units.temperature == FAHRENHEIT) { + if (output_units_p->temperature == FAHRENHEIT) { deg = mkelvin_to_F(mk); unit = UTF8_DEGREE "F"; } else { @@ -76,8 +78,9 @@ double get_volume_units(unsigned int ml, int *frac, const char **units) int decimals; double vol; const char *unit; + struct units *output_units_p = get_output_units(); - switch (output_units.volume) { + switch (output_units_p->volume) { case LITER: vol = ml / 1000.0; unit = _("l"); @@ -101,8 +104,9 @@ double get_depth_units(unsigned int mm, int *frac, const char **units) int decimals; double d; const char *unit; + struct units *output_units_p = get_output_units(); - switch (output_units.length) { + switch (output_units_p->length) { case METERS: d = mm / 1000.0; unit = _("m"); @@ -126,8 +130,9 @@ double get_weight_units(unsigned int grams, int *frac, const char **units) int decimals; double value; const char* unit; + struct units *output_units_p = get_output_units(); - if (output_units.weight == LBS) { + if (output_units_p->weight == LBS) { value = grams_to_lbs(grams); unit = _("lbs"); decimals = 0; @@ -392,9 +392,32 @@ struct units { enum { KG, LBS } weight; }; +/* + * We're going to default to SI units for input. Yes, + * technically the SI unit for pressure is Pascal, but + * we default to bar (10^5 pascal), which people + * actually use. Similarly, C instead of Kelvin. + * And kg instead of g. + */ +#define SI_UNITS { \ + .length = METERS, \ + .volume = LITER, \ + .pressure = BAR, \ + .temperature = CELSIUS, \ + .weight = KG \ +} + +#define IMPERIAL_UNITS { \ + .length = FEET, \ + .volume = CUFT, \ + .pressure = PSI, \ + .temperature = FAHRENHEIT, \ + .weight = LBS \ +} extern const struct units SI_units, IMPERIAL_units; -extern struct units input_units, output_units; +extern struct units input_units; +extern struct units *get_output_units(void); extern int verbose; struct dive_table { diff --git a/divelist.c b/divelist.c index d157849fd..a917889c4 100644 --- a/divelist.c +++ b/divelist.c @@ -402,7 +402,7 @@ static void depth_data_func(GtkTreeViewColumn *col, if (idx < 0) { *buffer = '\0'; } else { - switch (output_units.length) { + switch (prefs.output_units.length) { case METERS: /* To tenths of meters */ depth = (depth + 49) / 100; @@ -461,7 +461,7 @@ static void temperature_data_func(GtkTreeViewColumn *col, *buffer = 0; if (idx >= 0 && value) { double deg; - switch (output_units.temperature) { + switch (prefs.output_units.temperature) { case CELSIUS: deg = mkelvin_to_C(value); break; @@ -658,7 +658,7 @@ static void sac_data_func(GtkTreeViewColumn *col, } sac = value / 1000.0; - switch (output_units.volume) { + switch (prefs.output_units.volume) { case LITER: fmt = "%4.1f"; break; @@ -935,14 +935,14 @@ void update_dive_list_units(void) void update_dive_list_col_visibility(void) { - gtk_tree_view_column_set_visible(dive_list.cylinder, visible_cols.cylinder); - gtk_tree_view_column_set_visible(dive_list.temperature, visible_cols.temperature); - gtk_tree_view_column_set_visible(dive_list.totalweight, visible_cols.totalweight); - gtk_tree_view_column_set_visible(dive_list.suit, visible_cols.suit); - gtk_tree_view_column_set_visible(dive_list.nitrox, visible_cols.nitrox); - gtk_tree_view_column_set_visible(dive_list.sac, visible_cols.sac); - gtk_tree_view_column_set_visible(dive_list.otu, visible_cols.otu); - gtk_tree_view_column_set_visible(dive_list.maxcns, visible_cols.maxcns); + gtk_tree_view_column_set_visible(dive_list.cylinder, prefs.visible_cols.cylinder); + gtk_tree_view_column_set_visible(dive_list.temperature, prefs.visible_cols.temperature); + gtk_tree_view_column_set_visible(dive_list.totalweight, prefs.visible_cols.totalweight); + gtk_tree_view_column_set_visible(dive_list.suit, prefs.visible_cols.suit); + gtk_tree_view_column_set_visible(dive_list.nitrox, prefs.visible_cols.nitrox); + gtk_tree_view_column_set_visible(dive_list.sac, prefs.visible_cols.sac); + gtk_tree_view_column_set_visible(dive_list.otu, prefs.visible_cols.otu); + gtk_tree_view_column_set_visible(dive_list.maxcns, prefs.visible_cols.maxcns); return; } @@ -1289,14 +1289,14 @@ static struct divelist_column { [DIVE_RATING] = { UTF8_BLACKSTAR, star_data_func, NULL, ALIGN_LEFT }, [DIVE_DEPTH] = { N_("ft"), depth_data_func, NULL, ALIGN_RIGHT }, [DIVE_DURATION] = { N_("min"), duration_data_func, NULL, ALIGN_RIGHT }, - [DIVE_TEMPERATURE] = { UTF8_DEGREE "F", temperature_data_func, NULL, ALIGN_RIGHT, &visible_cols.temperature }, - [DIVE_TOTALWEIGHT] = { N_("lbs"), weight_data_func, NULL, ALIGN_RIGHT, &visible_cols.totalweight }, - [DIVE_SUIT] = { N_("Suit"), NULL, NULL, ALIGN_LEFT, &visible_cols.suit }, - [DIVE_CYLINDER] = { N_("Cyl"), NULL, NULL, 0, &visible_cols.cylinder }, - [DIVE_NITROX] = { "O" UTF8_SUBSCRIPT_2 "%", nitrox_data_func, nitrox_sort_func, 0, &visible_cols.nitrox }, - [DIVE_SAC] = { N_("SAC"), sac_data_func, NULL, 0, &visible_cols.sac }, - [DIVE_OTU] = { N_("OTU"), otu_data_func, NULL, 0, &visible_cols.otu }, - [DIVE_MAXCNS] = { N_("maxCNS"), cns_data_func, NULL, 0, &visible_cols.maxcns }, + [DIVE_TEMPERATURE] = { UTF8_DEGREE "F", temperature_data_func, NULL, ALIGN_RIGHT, &prefs.visible_cols.temperature }, + [DIVE_TOTALWEIGHT] = { N_("lbs"), weight_data_func, NULL, ALIGN_RIGHT, &prefs.visible_cols.totalweight }, + [DIVE_SUIT] = { N_("Suit"), NULL, NULL, ALIGN_LEFT, &prefs.visible_cols.suit }, + [DIVE_CYLINDER] = { N_("Cyl"), NULL, NULL, 0, &prefs.visible_cols.cylinder }, + [DIVE_NITROX] = { "O" UTF8_SUBSCRIPT_2 "%", nitrox_data_func, nitrox_sort_func, 0, &prefs.visible_cols.nitrox }, + [DIVE_SAC] = { N_("SAC"), sac_data_func, NULL, 0, &prefs.visible_cols.sac }, + [DIVE_OTU] = { N_("OTU"), otu_data_func, NULL, 0, &prefs.visible_cols.otu }, + [DIVE_MAXCNS] = { N_("maxCNS"), cns_data_func, NULL, 0, &prefs.visible_cols.maxcns }, [DIVE_LOCATION] = { N_("Location"), NULL, NULL, ALIGN_LEFT }, }; @@ -1408,6 +1408,48 @@ void edit_dive_from_path_cb(GtkWidget *menuitem, GtkTreePath *path) edit_multi_dive_info(dive); } +void edit_dive_when_cb(GtkWidget *menuitem, struct dive *dive) +{ + GtkWidget *dialog, *cal, *h, *m; + timestamp_t when; + + guint yval, mval, dval; + int success; + struct tm tm; + + if (!dive) + return; + + when = dive->when; + utc_mkdate(when, &tm); + dialog = create_date_time_widget(&tm, &cal, &h, &m); + + gtk_widget_show_all(dialog); + success = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT; + if (!success) { + gtk_widget_destroy(dialog); + return; + } + memset(&tm, 0, sizeof(tm)); + gtk_calendar_get_date(GTK_CALENDAR(cal), &yval, &mval, &dval); + tm.tm_year = yval; + tm.tm_mon = mval; + tm.tm_mday = dval; + tm.tm_hour = gtk_spin_button_get_value(GTK_SPIN_BUTTON(h)); + tm.tm_min = gtk_spin_button_get_value(GTK_SPIN_BUTTON(m)); + + gtk_widget_destroy(dialog); + when = utc_mktime(&tm); + if (dive->when != when) { + dive->when = when; + mark_divelist_changed(TRUE); + remember_tree_state(); + report_dives(FALSE, FALSE); + dive_list_update_dives(); + restore_tree_state(); + } +} + static void expand_all_cb(GtkWidget *menuitem, GtkTreeView *tree_view) { gtk_tree_view_expand_all(tree_view); @@ -2167,6 +2209,9 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int if (amount_selected == 1) { deletelabel = _(deletesinglelabel); editlabel = _(editsinglelabel); + menuitem = gtk_menu_item_new_with_label(_("Edit dive date/time")); + g_signal_connect(menuitem, "activate", G_CALLBACK(edit_dive_when_cb), dive); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); } else { deletelabel = _(deleteplurallabel); editlabel = _(editplurallabel); @@ -2183,6 +2228,10 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int if (amount_selected == 2) add_dive_merge_label(idx, GTK_MENU_SHELL(menu)); } else { + menuitem = gtk_menu_item_new_with_label(_("Edit dive date/time")); + g_signal_connect(menuitem, "activate", G_CALLBACK(edit_dive_when_cb), dive); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + deletelabel = _(deletesinglelabel); menuitem = gtk_menu_item_new_with_label(deletelabel); g_signal_connect(menuitem, "activate", G_CALLBACK(delete_dive_cb), path); diff --git a/equipment.c b/equipment.c index 8bfb7a7a8..232764676 100644 --- a/equipment.c +++ b/equipment.c @@ -75,7 +75,7 @@ static int convert_pressure(int mbar, double *p) int decimals = 1; double pressure; - if (output_units.pressure == PSI) { + if (prefs.output_units.pressure == PSI) { pressure = mbar_to_PSI(mbar); decimals = 0; } else { @@ -92,12 +92,12 @@ static void convert_volume_pressure(int ml, int mbar, double *v, double *p) volume = ml / 1000.0; if (mbar) { - if (output_units.volume == CUFT) { + if (prefs.output_units.volume == CUFT) { volume = ml_to_cuft(ml); volume *= bar_to_atm(mbar / 1000.0); } - if (output_units.pressure == PSI) + if (prefs.output_units.pressure == PSI) pressure = mbar_to_PSI(mbar); else pressure = mbar / 1000.0; @@ -111,7 +111,7 @@ static int convert_weight(int grams, double *m) int decimals = 1; /* not sure - do people do less than whole lbs/kg ? */ double weight; - if (output_units.weight == LBS) + if (prefs.output_units.weight == LBS) weight = grams_to_lbs(grams); else weight = grams / 1000.0; @@ -631,14 +631,14 @@ static void fill_cylinder_info(struct cylinder_widget *cylinder, cylinder_t *cyl { int mbar, ml; - if (output_units.pressure == PSI) { + if (prefs.output_units.pressure == PSI) { pressure = psi_to_bar(pressure); start = psi_to_bar(start); end = psi_to_bar(end); } mbar = pressure * 1000 + 0.5; - if (mbar && output_units.volume == CUFT) { + if (mbar && prefs.output_units.volume == CUFT) { volume = cuft_to_l(volume); volume /= bar_to_atm(pressure); } @@ -714,7 +714,7 @@ static void record_weightsystem_changes(weightsystem_t *ws, struct ws_widget *we desc = gtk_combo_box_get_active_text(box); value = gtk_spin_button_get_value(weightsystem_widget->weight); - if (output_units.weight == LBS) + if (prefs.output_units.weight == LBS) grams = lbs_to_grams(value); else grams = value * 1000; @@ -1041,7 +1041,7 @@ static void ws_widget(GtkWidget *vbox, struct ws_widget *ws_widget, GtkListStore gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 0); - if ( output_units.weight == KG) + if ( prefs.output_units.weight == KG) widget = create_spinbutton(hbox, _("kg"), 0, 50, 0.5); else widget = create_spinbutton(hbox, _("lbs"), 0, 110, 1); @@ -32,20 +32,25 @@ const char *existing_filename; const char *divelist_font; const char *default_filename; -struct units output_units; +struct preferences prefs = { + SI_UNITS, + { TRUE, FALSE, }, + { FALSE, FALSE, FALSE, 1.6, 4.0, 13.0}, + FALSE +}; static GtkWidget *dive_profile; - -visible_cols_t visible_cols = {TRUE, FALSE, }; -partial_pressure_graphs_t partial_pressure_graphs = { FALSE, FALSE, FALSE, 1.6, 4.0, 10.0}; -gboolean profile_red_ceiling = FALSE; - static const char *default_dive_computer_vendor; static const char *default_dive_computer_product; static const char *default_dive_computer_device; static gboolean force_download; static gboolean prefer_downloaded; +struct units *get_output_units() +{ + return &prefs.output_units; +} + static int is_default_dive_computer(const char *vendor, const char *product) { return default_dive_computer_vendor && !strcmp(vendor, default_dive_computer_vendor) && @@ -331,7 +336,7 @@ static void file_open(GtkWidget *w, gpointer data) gtk_widget_destroy(dialog); } -static gboolean on_delete(GtkWidget* w, gpointer data) +gboolean on_delete(GtkWidget* w, gpointer data) { /* Make sure to flush any modified dive data */ update_dive(NULL); @@ -446,15 +451,21 @@ static void create_radio(GtkWidget *vbox, const char *w_name, ...) va_end(args); } +static void update_screen() +{ + update_dive_list_units(); + repaint_dive(); + update_dive_list_col_visibility(); +} + #define UNITCALLBACK(name, type, value) \ static void name(GtkWidget *w, gpointer data) \ { \ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) \ - menu_units.type = value; \ + prefs.output_units.type = value; \ + update_screen(); \ } -static struct units menu_units; - UNITCALLBACK(set_meter, length, METERS) UNITCALLBACK(set_feet, length, FEET) UNITCALLBACK(set_bar, pressure, BAR) @@ -471,24 +482,24 @@ static void name(GtkWidget *w, gpointer data) \ { \ GtkWidget **entry = data; \ option = GTK_TOGGLE_BUTTON(w)->active; \ - dive_list_update_dives(); \ + update_screen(); \ if (entry) \ gtk_widget_set_sensitive(*entry, option);\ } -OPTIONCALLBACK(otu_toggle, visible_cols.otu) -OPTIONCALLBACK(maxcns_toggle, visible_cols.maxcns) -OPTIONCALLBACK(sac_toggle, visible_cols.sac) -OPTIONCALLBACK(nitrox_toggle, visible_cols.nitrox) -OPTIONCALLBACK(temperature_toggle, visible_cols.temperature) -OPTIONCALLBACK(totalweight_toggle, visible_cols.totalweight) -OPTIONCALLBACK(suit_toggle, visible_cols.suit) -OPTIONCALLBACK(cylinder_toggle, visible_cols.cylinder) +OPTIONCALLBACK(otu_toggle, prefs.visible_cols.otu) +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(totalweight_toggle, prefs.visible_cols.totalweight) +OPTIONCALLBACK(suit_toggle, prefs.visible_cols.suit) +OPTIONCALLBACK(cylinder_toggle, prefs.visible_cols.cylinder) OPTIONCALLBACK(autogroup_toggle, autogroup) -OPTIONCALLBACK(po2_toggle, partial_pressure_graphs.po2) -OPTIONCALLBACK(pn2_toggle, partial_pressure_graphs.pn2) -OPTIONCALLBACK(phe_toggle, partial_pressure_graphs.phe) -OPTIONCALLBACK(red_ceiling_toggle, profile_red_ceiling) +OPTIONCALLBACK(po2_toggle, prefs.pp_graphs.po2) +OPTIONCALLBACK(pn2_toggle, prefs.pp_graphs.pn2) +OPTIONCALLBACK(phe_toggle, prefs.pp_graphs.phe) +OPTIONCALLBACK(red_ceiling_toggle, prefs.profile_red_ceiling) OPTIONCALLBACK(force_toggle, force_download) OPTIONCALLBACK(prefer_dl_toggle, prefer_downloaded) @@ -556,14 +567,13 @@ static void preferences_dialog(GtkWidget *w, gpointer data) GtkWidget *entry_po2, *entry_pn2, *entry_phe; const char *current_default, *new_default; char threshold_text[10]; - - menu_units = output_units; + struct preferences oldprefs = prefs; dialog = gtk_dialog_new_with_buttons(_("Preferences"), GTK_WINDOW(main_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); /* create the notebook for the preferences and attach it to dialog */ @@ -581,28 +591,28 @@ static void preferences_dialog(GtkWidget *w, gpointer data) gtk_container_add(GTK_CONTAINER(frame), box); create_radio(box, _("Depth:"), - _("Meter"), set_meter, (output_units.length == METERS), - _("Feet"), set_feet, (output_units.length == FEET), + _("Meter"), set_meter, (prefs.output_units.length == METERS), + _("Feet"), set_feet, (prefs.output_units.length == FEET), NULL); create_radio(box, _("Pressure:"), - _("Bar"), set_bar, (output_units.pressure == BAR), - _("PSI"), set_psi, (output_units.pressure == PSI), + _("Bar"), set_bar, (prefs.output_units.pressure == BAR), + _("PSI"), set_psi, (prefs.output_units.pressure == PSI), NULL); create_radio(box, _("Volume:"), - _("Liter"), set_liter, (output_units.volume == LITER), - _("CuFt"), set_cuft, (output_units.volume == CUFT), + _("Liter"), set_liter, (prefs.output_units.volume == LITER), + _("CuFt"), set_cuft, (prefs.output_units.volume == CUFT), NULL); create_radio(box, _("Temperature:"), - _("Celsius"), set_celsius, (output_units.temperature == CELSIUS), - _("Fahrenheit"), set_fahrenheit, (output_units.temperature == FAHRENHEIT), + _("Celsius"), set_celsius, (prefs.output_units.temperature == CELSIUS), + _("Fahrenheit"), set_fahrenheit, (prefs.output_units.temperature == FAHRENHEIT), NULL); create_radio(box, _("Weight:"), - _("kg"), set_kg, (output_units.weight == KG), - _("lbs"), set_lbs, (output_units.weight == LBS), + _("kg"), set_kg, (prefs.output_units.weight == KG), + _("lbs"), set_lbs, (prefs.output_units.weight == LBS), NULL); frame = gtk_frame_new(_("Show Columns")); @@ -612,32 +622,32 @@ static void preferences_dialog(GtkWidget *w, gpointer data) gtk_container_add(GTK_CONTAINER(frame), box); button = gtk_check_button_new_with_label(_("Temp")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.temperature); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.visible_cols.temperature); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(temperature_toggle), NULL); button = gtk_check_button_new_with_label(_("Cyl")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.cylinder); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.visible_cols.cylinder); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(cylinder_toggle), NULL); button = gtk_check_button_new_with_label("O" UTF8_SUBSCRIPT_2 "%"); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.nitrox); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.visible_cols.nitrox); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(nitrox_toggle), NULL); button = gtk_check_button_new_with_label(_("SAC")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.sac); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.visible_cols.sac); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(sac_toggle), NULL); button = gtk_check_button_new_with_label(_("Weight")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.totalweight); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.visible_cols.totalweight); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(totalweight_toggle), NULL); button = gtk_check_button_new_with_label(_("Suit")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.suit); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.visible_cols.suit); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(suit_toggle), NULL); @@ -680,12 +690,12 @@ static void preferences_dialog(GtkWidget *w, gpointer data) gtk_container_add(GTK_CONTAINER(frame), box); button = gtk_check_button_new_with_label(_("OTU")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.otu); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.visible_cols.otu); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(otu_toggle), NULL); button = gtk_check_button_new_with_label(_("maxCNS")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.maxcns); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.visible_cols.maxcns); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(maxcns_toggle), NULL); @@ -698,7 +708,7 @@ static void preferences_dialog(GtkWidget *w, gpointer data) gtk_container_add(GTK_CONTAINER(vbox), box); button = gtk_check_button_new_with_label(_("Show pO" UTF8_SUBSCRIPT_2 " graph")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), partial_pressure_graphs.po2); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.pp_graphs.po2); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(po2_toggle), &entry_po2); @@ -706,16 +716,16 @@ static void preferences_dialog(GtkWidget *w, gpointer data) gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 6); entry_po2 = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(entry_po2), 4); - snprintf(threshold_text, sizeof(threshold_text), "%.1f", partial_pressure_graphs.po2_threshold); + snprintf(threshold_text, sizeof(threshold_text), "%.1f", prefs.pp_graphs.po2_threshold); gtk_entry_set_text(GTK_ENTRY(entry_po2), threshold_text); - gtk_widget_set_sensitive(entry_po2, partial_pressure_graphs.po2); + gtk_widget_set_sensitive(entry_po2, prefs.pp_graphs.po2); gtk_container_add(GTK_CONTAINER(frame), entry_po2); box = gtk_hbox_new(FALSE, 6); gtk_container_add(GTK_CONTAINER(vbox), box); button = gtk_check_button_new_with_label(_("Show pN" UTF8_SUBSCRIPT_2 " graph")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), partial_pressure_graphs.pn2); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.pp_graphs.pn2); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(pn2_toggle), &entry_pn2); @@ -723,16 +733,16 @@ static void preferences_dialog(GtkWidget *w, gpointer data) gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 6); entry_pn2 = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(entry_pn2), 4); - snprintf(threshold_text, sizeof(threshold_text), "%.1f", partial_pressure_graphs.pn2_threshold); + snprintf(threshold_text, sizeof(threshold_text), "%.1f", prefs.pp_graphs.pn2_threshold); gtk_entry_set_text(GTK_ENTRY(entry_pn2), threshold_text); - gtk_widget_set_sensitive(entry_pn2, partial_pressure_graphs.pn2); + gtk_widget_set_sensitive(entry_pn2, prefs.pp_graphs.pn2); gtk_container_add(GTK_CONTAINER(frame), entry_pn2); box = gtk_hbox_new(FALSE, 6); gtk_container_add(GTK_CONTAINER(vbox), box); button = gtk_check_button_new_with_label(_("Show pHe graph")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), partial_pressure_graphs.phe); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.pp_graphs.phe); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(phe_toggle), &entry_phe); @@ -740,16 +750,16 @@ static void preferences_dialog(GtkWidget *w, gpointer data) gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 6); entry_phe = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(entry_phe), 4); - snprintf(threshold_text, sizeof(threshold_text), "%.1f", partial_pressure_graphs.phe_threshold); + snprintf(threshold_text, sizeof(threshold_text), "%.1f", prefs.pp_graphs.phe_threshold); gtk_entry_set_text(GTK_ENTRY(entry_phe), threshold_text); - gtk_widget_set_sensitive(entry_phe, partial_pressure_graphs.phe); + gtk_widget_set_sensitive(entry_phe, prefs.pp_graphs.phe); gtk_container_add(GTK_CONTAINER(frame), entry_phe); box = gtk_hbox_new(FALSE, 6); gtk_container_add(GTK_CONTAINER(vbox), box); button = gtk_check_button_new_with_label(_("Show ceiling in red")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), profile_red_ceiling); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.profile_red_ceiling); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(red_ceiling_toggle), NULL); @@ -765,41 +775,39 @@ static void preferences_dialog(GtkWidget *w, gpointer data) divelist_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font))); set_divelist_font(divelist_font); po2_threshold_text = gtk_entry_get_text(GTK_ENTRY(entry_po2)); - sscanf(po2_threshold_text, "%lf", &partial_pressure_graphs.po2_threshold); + sscanf(po2_threshold_text, "%lf", &prefs.pp_graphs.po2_threshold); pn2_threshold_text = gtk_entry_get_text(GTK_ENTRY(entry_pn2)); - sscanf(pn2_threshold_text, "%lf", &partial_pressure_graphs.pn2_threshold); + sscanf(pn2_threshold_text, "%lf", &prefs.pp_graphs.pn2_threshold); phe_threshold_text = gtk_entry_get_text(GTK_ENTRY(entry_phe)); - sscanf(phe_threshold_text, "%lf", &partial_pressure_graphs.phe_threshold); - output_units = menu_units; - update_dive_list_units(); - repaint_dive(); - update_dive_list_col_visibility(); - - subsurface_set_conf("feet", PREF_BOOL, BOOL_TO_PTR(output_units.length == FEET)); - subsurface_set_conf("psi", PREF_BOOL, BOOL_TO_PTR(output_units.pressure == PSI)); - subsurface_set_conf("cuft", PREF_BOOL, BOOL_TO_PTR(output_units.volume == CUFT)); - subsurface_set_conf("fahrenheit", PREF_BOOL, BOOL_TO_PTR(output_units.temperature == FAHRENHEIT)); - subsurface_set_conf("lbs", PREF_BOOL, BOOL_TO_PTR(output_units.weight == LBS)); - - subsurface_set_conf("TEMPERATURE", PREF_BOOL, BOOL_TO_PTR(visible_cols.temperature)); - subsurface_set_conf("TOTALWEIGHT", PREF_BOOL, BOOL_TO_PTR(visible_cols.totalweight)); - subsurface_set_conf("SUIT", PREF_BOOL, BOOL_TO_PTR(visible_cols.suit)); - subsurface_set_conf("CYLINDER", PREF_BOOL, BOOL_TO_PTR(visible_cols.cylinder)); - subsurface_set_conf("NITROX", PREF_BOOL, BOOL_TO_PTR(visible_cols.nitrox)); - subsurface_set_conf("SAC", PREF_BOOL, BOOL_TO_PTR(visible_cols.sac)); - subsurface_set_conf("OTU", PREF_BOOL, BOOL_TO_PTR(visible_cols.otu)); - subsurface_set_conf("MAXCNS", PREF_BOOL, BOOL_TO_PTR(visible_cols.maxcns)); + sscanf(phe_threshold_text, "%lf", &prefs.pp_graphs.phe_threshold); + + update_screen(); + + subsurface_set_conf("feet", PREF_BOOL, BOOL_TO_PTR(prefs.output_units.length == FEET)); + subsurface_set_conf("psi", PREF_BOOL, BOOL_TO_PTR(prefs.output_units.pressure == PSI)); + subsurface_set_conf("cuft", PREF_BOOL, BOOL_TO_PTR(prefs.output_units.volume == CUFT)); + subsurface_set_conf("fahrenheit", PREF_BOOL, BOOL_TO_PTR(prefs.output_units.temperature == FAHRENHEIT)); + subsurface_set_conf("lbs", PREF_BOOL, BOOL_TO_PTR(prefs.output_units.weight == LBS)); + + subsurface_set_conf("TEMPERATURE", PREF_BOOL, BOOL_TO_PTR(prefs.visible_cols.temperature)); + subsurface_set_conf("TOTALWEIGHT", PREF_BOOL, BOOL_TO_PTR(prefs.visible_cols.totalweight)); + subsurface_set_conf("SUIT", PREF_BOOL, BOOL_TO_PTR(prefs.visible_cols.suit)); + subsurface_set_conf("CYLINDER", PREF_BOOL, BOOL_TO_PTR(prefs.visible_cols.cylinder)); + subsurface_set_conf("NITROX", PREF_BOOL, BOOL_TO_PTR(prefs.visible_cols.nitrox)); + subsurface_set_conf("SAC", PREF_BOOL, BOOL_TO_PTR(prefs.visible_cols.sac)); + subsurface_set_conf("OTU", PREF_BOOL, BOOL_TO_PTR(prefs.visible_cols.otu)); + subsurface_set_conf("MAXCNS", PREF_BOOL, BOOL_TO_PTR(prefs.visible_cols.maxcns)); subsurface_set_conf("divelist_font", PREF_STRING, divelist_font); subsurface_set_conf("autogroup", PREF_BOOL, BOOL_TO_PTR(autogroup)); - subsurface_set_conf("po2graph", PREF_BOOL, BOOL_TO_PTR(partial_pressure_graphs.po2)); - subsurface_set_conf("pn2graph", PREF_BOOL, BOOL_TO_PTR(partial_pressure_graphs.pn2)); - subsurface_set_conf("phegraph", PREF_BOOL, BOOL_TO_PTR(partial_pressure_graphs.phe)); + subsurface_set_conf("po2graph", PREF_BOOL, BOOL_TO_PTR(prefs.pp_graphs.po2)); + subsurface_set_conf("pn2graph", PREF_BOOL, BOOL_TO_PTR(prefs.pp_graphs.pn2)); + subsurface_set_conf("phegraph", PREF_BOOL, BOOL_TO_PTR(prefs.pp_graphs.phe)); subsurface_set_conf("po2threshold", PREF_STRING, po2_threshold_text); subsurface_set_conf("pn2threshold", PREF_STRING, pn2_threshold_text); subsurface_set_conf("phethreshold", PREF_STRING, phe_threshold_text); - subsurface_set_conf("redceiling", PREF_BOOL, BOOL_TO_PTR(profile_red_ceiling)); + subsurface_set_conf("redceiling", PREF_BOOL, BOOL_TO_PTR(prefs.profile_red_ceiling)); new_default = strdup(gtk_button_get_label(GTK_BUTTON(xmlfile_button))); @@ -820,6 +828,8 @@ static void preferences_dialog(GtkWidget *w, gpointer data) /* Flush the changes out to the system */ subsurface_flush_conf(); + } else if (result == GTK_RESPONSE_CANCEL) { + prefs = oldprefs; } free((void *)current_default); gtk_widget_destroy(dialog); @@ -1130,38 +1140,37 @@ void init_ui(int *argcp, char ***argvp) subsurface_open_conf(); if (subsurface_get_conf("feet", PREF_BOOL)) - output_units.length = FEET; + prefs.output_units.length = FEET; if (subsurface_get_conf("psi", PREF_BOOL)) - output_units.pressure = PSI; + prefs.output_units.pressure = PSI; if (subsurface_get_conf("cuft", PREF_BOOL)) - output_units.volume = CUFT; + prefs.output_units.volume = CUFT; if (subsurface_get_conf("fahrenheit", PREF_BOOL)) - output_units.temperature = FAHRENHEIT; + prefs.output_units.temperature = FAHRENHEIT; if (subsurface_get_conf("lbs", PREF_BOOL)) - output_units.weight = LBS; + prefs.output_units.weight = LBS; /* an unset key is FALSE - all these are hidden by default */ - visible_cols.cylinder = PTR_TO_BOOL(subsurface_get_conf("CYLINDER", PREF_BOOL)); - visible_cols.temperature = PTR_TO_BOOL(subsurface_get_conf("TEMPERATURE", PREF_BOOL)); - visible_cols.totalweight = PTR_TO_BOOL(subsurface_get_conf("TOTALWEIGHT", PREF_BOOL)); - visible_cols.suit = PTR_TO_BOOL(subsurface_get_conf("SUIT", PREF_BOOL)); - visible_cols.nitrox = PTR_TO_BOOL(subsurface_get_conf("NITROX", PREF_BOOL)); - visible_cols.otu = PTR_TO_BOOL(subsurface_get_conf("OTU", PREF_BOOL)); - visible_cols.maxcns = PTR_TO_BOOL(subsurface_get_conf("MAXCNS", PREF_BOOL)); - visible_cols.sac = PTR_TO_BOOL(subsurface_get_conf("SAC", PREF_BOOL)); - - partial_pressure_graphs.po2 = PTR_TO_BOOL(subsurface_get_conf("po2graph", PREF_BOOL)); - partial_pressure_graphs.pn2 = PTR_TO_BOOL(subsurface_get_conf("pn2graph", PREF_BOOL)); - partial_pressure_graphs.phe = PTR_TO_BOOL(subsurface_get_conf("phegraph", PREF_BOOL)); + prefs.visible_cols.cylinder = PTR_TO_BOOL(subsurface_get_conf("CYLINDER", PREF_BOOL)); + prefs.visible_cols.temperature = PTR_TO_BOOL(subsurface_get_conf("TEMPERATURE", PREF_BOOL)); + prefs.visible_cols.totalweight = PTR_TO_BOOL(subsurface_get_conf("TOTALWEIGHT", PREF_BOOL)); + prefs.visible_cols.suit = PTR_TO_BOOL(subsurface_get_conf("SUIT", PREF_BOOL)); + prefs.visible_cols.nitrox = PTR_TO_BOOL(subsurface_get_conf("NITROX", PREF_BOOL)); + prefs.visible_cols.otu = PTR_TO_BOOL(subsurface_get_conf("OTU", PREF_BOOL)); + prefs.visible_cols.maxcns = PTR_TO_BOOL(subsurface_get_conf("MAXCNS", PREF_BOOL)); + prefs.visible_cols.sac = PTR_TO_BOOL(subsurface_get_conf("SAC", PREF_BOOL)); + prefs.pp_graphs.po2 = PTR_TO_BOOL(subsurface_get_conf("po2graph", PREF_BOOL)); + prefs.pp_graphs.pn2 = PTR_TO_BOOL(subsurface_get_conf("pn2graph", PREF_BOOL)); + prefs.pp_graphs.phe = PTR_TO_BOOL(subsurface_get_conf("phegraph", PREF_BOOL)); conf_value = subsurface_get_conf("po2threshold", PREF_STRING); if (conf_value) - sscanf(conf_value, "%lf", &partial_pressure_graphs.po2_threshold); + sscanf(conf_value, "%lf", &prefs.pp_graphs.po2_threshold); conf_value = subsurface_get_conf("pn2threshold", PREF_STRING); if (conf_value) - sscanf(conf_value, "%lf", &partial_pressure_graphs.pn2_threshold); + sscanf(conf_value, "%lf", &prefs.pp_graphs.pn2_threshold); conf_value = subsurface_get_conf("phethreshold", PREF_STRING); if (conf_value) - sscanf(conf_value, "%lf", &partial_pressure_graphs.phe_threshold); - profile_red_ceiling = PTR_TO_BOOL(subsurface_get_conf("redceiling", PREF_BOOL)); + sscanf(conf_value, "%lf", &prefs.pp_graphs.phe_threshold); + prefs.profile_red_ceiling = PTR_TO_BOOL(subsurface_get_conf("redceiling", PREF_BOOL)); divelist_font = subsurface_get_conf("divelist_font", PREF_STRING); autogroup = PTR_TO_BOOL(subsurface_get_conf("autogroup", PREF_BOOL)); default_filename = subsurface_get_conf("default_filename", PREF_STRING); @@ -1301,6 +1310,10 @@ static gboolean profile_tooltip (GtkWidget *widget, gint x, gint y, if (tx < 0 || ty < 0) return FALSE; + /* don't draw a tooltip if nothing is there */ + if (gc->pi.nr == 0) + return FALSE; + width = drawing_area->width - 2*drawing_area->x; height = drawing_area->height - 2*drawing_area->y; if (width <= 0 || height <= 0) @@ -1672,7 +1685,7 @@ static GtkComboBox *dive_computer_selector(GtkWidget *vbox) gtk_container_add(GTK_CONTAINER(frame), hbox); vendor_combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(vendor_model)); - product_combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(product_model[product_default_index])); + product_combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(product_model[vendor_default_index])); g_signal_connect(G_OBJECT(vendor_combo_box), "changed", G_CALLBACK(dive_computer_vendor_changed), product_combo_box); g_signal_connect(G_OBJECT(product_combo_box), "changed", G_CALLBACK(dive_computer_selector_changed), NULL); @@ -455,7 +455,7 @@ static void save_dive_info_changes(struct dive *dive, struct dive *master, struc new_text = (char *)gtk_entry_get_text(info->airtemp); if(sscanf(new_text, "%lf", &newtemp) == 1) { unsigned long mkelvin; - switch (output_units.temperature) { + switch (prefs.output_units.temperature) { case CELSIUS: mkelvin = C_to_mkelvin(newtemp); break; @@ -817,18 +817,11 @@ static GtkWidget *frame_box(GtkWidget *vbox, const char *fmt, ...) return hbox; } -/* Fixme - should do at least depths too - a dive without a depth is kind of pointless */ -static timestamp_t dive_time_widget(struct dive *dive) +GtkWidget *create_date_time_widget(struct tm *time, GtkWidget **cal, GtkWidget **h, GtkWidget **m) { GtkWidget *dialog; - GtkWidget *cal, *hbox, *vbox, *box; - GtkWidget *h, *m; - GtkWidget *duration, *depth; + GtkWidget *hbox, *vbox; GtkWidget *label; - guint yval, mval, dval; - struct tm tm, *time; - int success; - double depthinterval, val; dialog = gtk_dialog_new_with_buttons(_("Date and Time"), GTK_WINDOW(main_window), @@ -841,14 +834,42 @@ static timestamp_t dive_time_widget(struct dive *dive) /* Calendar hbox */ hbox = frame_box(vbox, _("Date:")); - cal = gtk_calendar_new(); - gtk_box_pack_start(GTK_BOX(hbox), cal, FALSE, TRUE, 0); + *cal = gtk_calendar_new(); + gtk_box_pack_start(GTK_BOX(hbox), *cal, FALSE, TRUE, 0); /* Time hbox */ hbox = frame_box(vbox, _("Time")); - h = gtk_spin_button_new_with_range (0.0, 23.0, 1.0); - m = gtk_spin_button_new_with_range (0.0, 59.0, 1.0); + *h = gtk_spin_button_new_with_range (0.0, 23.0, 1.0); + *m = gtk_spin_button_new_with_range (0.0, 59.0, 1.0); + + + gtk_calendar_select_month(GTK_CALENDAR(*cal), time->tm_mon, time->tm_year + 1900); + gtk_calendar_select_day(GTK_CALENDAR(*cal), time->tm_mday); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(*h), time->tm_hour); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(*m), (time->tm_min / 5)*5); + + gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(*h), TRUE); + gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(*m), TRUE); + + gtk_box_pack_end(GTK_BOX(hbox), *m, FALSE, FALSE, 0); + label = gtk_label_new(":"); + gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(hbox), *h, FALSE, FALSE, 0); + + return dialog; +} + +static timestamp_t dive_time_widget(struct dive *dive) +{ + GtkWidget *dialog; + GtkWidget *cal, *vbox, *hbox, *box; + GtkWidget *h, *m; + GtkWidget *duration, *depth; + guint yval, mval, dval; + struct tm tm, *time; + int success; + double depthinterval, val; /* * If we have a dive selected, 'add dive' will default @@ -868,19 +889,8 @@ static timestamp_t dive_time_widget(struct dive *dive) now = tv.tv_sec; time = localtime(&now); } - gtk_calendar_select_month(GTK_CALENDAR(cal), time->tm_mon, time->tm_year + 1900); - gtk_calendar_select_day(GTK_CALENDAR(cal), time->tm_mday); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(h), time->tm_hour); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(m), (time->tm_min / 5)*5); - - gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(h), TRUE); - gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(m), TRUE); - - gtk_box_pack_end(GTK_BOX(hbox), m, FALSE, FALSE, 0); - label = gtk_label_new(":"); - gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_box_pack_end(GTK_BOX(hbox), h, FALSE, FALSE, 0); - + dialog = create_date_time_widget(time, &cal, &h, &m); + vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); hbox = gtk_hbox_new(TRUE, 3); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); @@ -890,8 +900,8 @@ static timestamp_t dive_time_widget(struct dive *dive) gtk_box_pack_end(GTK_BOX(box), duration, FALSE, FALSE, 0); /* Depth box */ - box = frame_box(hbox, _("Depth (%s):"), output_units.length == FEET ? _("ft") : _("m")); - if (output_units.length == FEET) { + box = frame_box(hbox, _("Depth (%s):"), prefs.output_units.length == FEET ? _("ft") : _("m")); + if (prefs.output_units.length == FEET) { depthinterval = 1.0; } else { depthinterval = 0.1; @@ -917,7 +927,7 @@ static timestamp_t dive_time_widget(struct dive *dive) tm.tm_min = gtk_spin_button_get_value(GTK_SPIN_BUTTON(m)); val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(depth)); - if (output_units.length == FEET) { + if (prefs.output_units.length == FEET) { dive->maxdepth.mm = feet_to_mm(val); } else { dive->maxdepth.mm = val * 1000 + 0.5; @@ -79,8 +79,6 @@ int subsurface_fill_device_list(GtkListStore *store) GtkTreeIter iter; GDir *dev; const char *name; - char *buffer; - gsize length; dev = g_dir_open("/dev", 0, NULL); while (dev && (name = g_dir_read_name(dev)) != NULL) { @@ -206,7 +204,7 @@ void subsurface_ui_setup(GtkSettings *settings, GtkWidget *menubar, gtk_osxapplication_set_use_quartz_accelerators(osx_app, TRUE); g_signal_connect(osx_app,"NSApplicationDidBecomeActive",G_CALLBACK(show_main_window),NULL); - g_signal_connect(osx_app,"NSApplicationWillTerminate",G_CALLBACK(quit),NULL); + g_signal_connect(osx_app, "NSApplicationBlockTermination", G_CALLBACK(on_delete), NULL); gtk_osxapplication_ready(osx_app); } diff --git a/parse-xml.c b/parse-xml.c index f88d4ef7f..916a780d1 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -129,29 +129,8 @@ static int match(const char *pattern, int plen, struct units input_units; - -/* - * We're going to default to SI units for input. Yes, - * technically the SI unit for pressure is Pascal, but - * we default to bar (10^5 pascal), which people - * actually use. Similarly, C instead of Kelvin. - * And kg instead of g. - */ -const struct units SI_units = { - .length = METERS, - .volume = LITER, - .pressure = BAR, - .temperature = CELSIUS, - .weight = KG -}; - -const struct units IMPERIAL_units = { - .length = FEET, - .volume = CUFT, - .pressure = PSI, - .temperature = FAHRENHEIT, - .weight = LBS -}; +const struct units SI_units = SI_UNITS; +const struct units IMPERIAL_units = IMPERIAL_UNITS; /* * Dive info as it is being built up.. @@ -45,7 +45,11 @@ static void set_font(PangoLayout *layout, PangoFontDescription *font, * You know what? Maybe somebody can do a real Pango layout thing. * This is hacky. */ -static void show_dive_text(struct dive *dive, cairo_t *cr, double w, + +/* + * Show a header for the dive containing minimal data + */ +static void show_dive_header(struct dive *dive, cairo_t *cr, double w, double h, PangoFontDescription *font) { double depth; @@ -126,22 +130,25 @@ static void show_dive_text(struct dive *dive, cairo_t *cr, double w, set_font(layout, font, FONT_NORMAL, PANGO_ALIGN_LEFT); } pango_layout_set_text(layout, dive->location ? : " ", -1); - cairo_move_to(cr, 0, 0); pango_cairo_show_layout(cr, layout); + g_object_unref(layout); + /* If we have translations get back the coordinates to original*/ + cairo_translate(cr,0, - ((h * PANGO_SCALE * 0.9) - maxheight) / PANGO_SCALE); +} +/* + * Show the dive notes + */ +static void show_dive_notes(struct dive *dive, cairo_t *cr, double w, + double h, PangoFontDescription *font) +{ + int maxwidth, maxheight; + PangoLayout *layout; - pango_layout_get_size(layout, &width, &height); - - /* - * Show the dive notes - */ + maxwidth = w * PANGO_SCALE; + maxheight = h * PANGO_SCALE * 0.9; + layout = pango_cairo_create_layout(cr); if (dive->notes) { - /* Move down by the size of the location (x2) */ - height = height * 2; - cairo_translate(cr, 0, height / (double) PANGO_SCALE); - maxheight -= height; - - /* Use the full width and remaining height for notes */ pango_layout_set_height(layout, maxheight); pango_layout_set_width(layout, maxwidth); if (print_options.type == ONEPERPAGE){ @@ -159,6 +166,117 @@ static void show_dive_text(struct dive *dive, cairo_t *cr, double w, g_object_unref(layout); } +/* + * Show the tanks used in the dive, the mix, and the gas consumed + * as pressures are shown in the plot + */ +static void show_dive_tanks(struct dive *dive, cairo_t *cr, double w, + double h, PangoFontDescription *font) +{ + int maxwidth, maxheight, curwidth, height, decimals, n, i, z, + cyl_wp, cyl_press, cyl_end; + double cyl_cap, cyl_cons_gas; + const char *unit_vol, *unit_press; + char buffer[80], dataheader1[3][80]= { N_("Cylinder"), N_("Gasmix"), N_("Gas Used")}; + PangoLayout *layout; + + /*Create a frame to separate tank area, note the scaling*/ + cairo_rectangle(cr, 0, 0 + h*0.05, w, h*0.9); + cairo_set_line_width(cr, 0.01); + cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); + cairo_stroke(cr); + + maxwidth = w * PANGO_SCALE; + maxheight = h * PANGO_SCALE * 0.9; + + /* We need to know how many cylinders we used*/ + for (z = 0; z < MAX_CYLINDERS; z++ ){ + if (dive->cylinder[z].start.mbar == 0) { + break; + } + } + + /* to determine the distance between lines*/ + if (z == 0){ + height = maxheight / 1; + } else { + height = maxheight / (z + 1); + } + + /* Then create the layout. + * First a header */ + cairo_translate (cr, 0, height / (6 * (double) PANGO_SCALE)); + maxheight -= height / 6; + curwidth = 0; + for (i = 0; i < 3; i++) { + cairo_move_to(cr, curwidth / (double) PANGO_SCALE, 0); + layout = pango_cairo_create_layout(cr); + pango_layout_set_height(layout,maxheight); + pango_layout_set_width(layout, maxwidth / 3); + pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); + set_font(layout, font, FONT_SMALL * 0.10 *(11-z), PANGO_ALIGN_CENTER); + pango_layout_set_text(layout, _(dataheader1[i]), -1); + pango_layout_set_justify(layout, 0); + pango_cairo_show_layout(cr, layout); + curwidth = curwidth + maxwidth/ 3; + } + + /* Now the relevant info*/ + for (n = 0; n < z; n++) { + cairo_translate (cr, 0, height / (double) PANGO_SCALE); + cairo_move_to(cr, 0, 0); + + cyl_cap = get_volume_units(dive->cylinder[n].type.size.mliter, &decimals, &unit_vol); + cyl_wp = get_pressure_units(dive->cylinder[n].type.workingpressure.mbar, &unit_press); + cyl_press= get_pressure_units(dive->cylinder[n].start.mbar, &unit_press); + cyl_end= get_pressure_units(dive->cylinder[n].end.mbar, &unit_press); + cyl_cons_gas = (cyl_press - cyl_end) * cyl_cap; + + curwidth = 0; + i = 0; + while ( i < 3 ) { + cairo_move_to(cr, curwidth / (double) PANGO_SCALE, 0); + switch(i) { + case 0 : if (prefs.output_units.volume == CUFT) { + cyl_cap *= cyl_wp / 14.7 ; + } + snprintf(buffer, sizeof(buffer), _("%.*f %s"), + decimals, + cyl_cap, + unit_vol); + break; + case 1 : cairo_move_to(cr, curwidth / (double) PANGO_SCALE, 0); + if (dive->cylinder[n].gasmix.o2.permille == 0){ + snprintf(buffer, sizeof(buffer), _("air")); + + } else { + snprintf(buffer, sizeof(buffer), _("%d/%d"), + dive->cylinder[n].gasmix.o2.permille /10, + dive->cylinder[n].gasmix.he.permille /10); + } + break; + case 2 : cairo_move_to(cr, curwidth / (double) PANGO_SCALE, 0); + if (prefs.output_units.volume == CUFT) { + cyl_cons_gas /= 14.7 ; + } + snprintf(buffer, sizeof(buffer), _("%.*f %s\n"), + decimals, + cyl_cons_gas, + unit_vol); + break; + default : snprintf(buffer, sizeof(buffer),"Error"); + } + pango_layout_set_text(layout, buffer, -1); + pango_cairo_show_layout(cr, layout); + curwidth += (maxwidth/ 3); + i += 1; + } + maxheight -= height; + } + cairo_translate(cr,0, - ((h * PANGO_SCALE * 0.9) - maxheight) / PANGO_SCALE); + g_object_unref(layout); +} + static void show_table_header(cairo_t *cr, double w, double h, PangoFontDescription *font) { @@ -339,8 +457,13 @@ static void print(int divenr, cairo_t *cr, double x, double y, double w, /* Dive information in the lower third */ cairo_translate(cr, 0, h*1.33); + show_dive_header(dive, cr, w*2, h*0.15, font); + + cairo_translate(cr, 0, h*0.15); + show_dive_tanks (dive, cr, w*1, h*0.20, font); - show_dive_text(dive, cr, w*2, h*0.67, font); + cairo_translate(cr, 0, h*0.20); + show_dive_notes(dive, cr, w*2, h*0.32, font); cairo_restore(cr); } @@ -243,7 +243,7 @@ static int get_maxdepth(struct plot_info *pi) /* Minimum 30m, rounded up to 10m, with at least 3m to spare */ md = MAX(30000, ROUND_UP(mm+3000, 10000)); } - if (GRAPHS_ENABLED) { + if (PP_GRAPHS_ENABLED) { if (md <= 20000) md += 10000; else @@ -512,7 +512,7 @@ static void plot_depth_scale(struct graphics_context *gc, struct plot_info *pi) maxdepth = get_maxdepth(pi); gc->topy = 0; gc->bottomy = maxdepth; - switch (output_units.length) { + switch (prefs.output_units.length) { case METERS: marker = 10000; break; case FEET: marker = 9144; break; /* 30 ft */ } @@ -545,7 +545,6 @@ static void plot_pp_text(struct graphics_context *gc, struct plot_info *pi) static const text_render_options_t tro = {11, PP_LINES, LEFT, MIDDLE}; setup_pp_limits(gc, pi); - pp = floor(pi->maxpp * 10.0) / 10.0 + 0.2; dpp = floor(2.0 * pp) / 10.0; hpos = pi->entry[pi->nr - 1].sec; @@ -565,13 +564,13 @@ static void plot_pp_gas_profile(struct graphics_context *gc, struct plot_info *p setup_pp_limits(gc, pi); - if (partial_pressure_graphs.pn2) { + if (prefs.pp_graphs.pn2) { set_source_rgba(gc, PN2); entry = pi->entry; move_to(gc, entry->sec, entry->pn2); for (i = 1; i < pi->nr; i++) { entry++; - if (entry->pn2 < partial_pressure_graphs.pn2_threshold) + if (entry->pn2 < prefs.pp_graphs.pn2_threshold) line_to(gc, entry->sec, entry->pn2); else move_to(gc, entry->sec, entry->pn2); @@ -583,20 +582,20 @@ static void plot_pp_gas_profile(struct graphics_context *gc, struct plot_info *p move_to(gc, entry->sec, entry->pn2); for (i = 1; i < pi->nr; i++) { entry++; - if (entry->pn2 >= partial_pressure_graphs.pn2_threshold) + if (entry->pn2 >= prefs.pp_graphs.pn2_threshold) line_to(gc, entry->sec, entry->pn2); else move_to(gc, entry->sec, entry->pn2); } cairo_stroke(gc->cr); } - if (partial_pressure_graphs.phe) { + if (prefs.pp_graphs.phe) { set_source_rgba(gc, PHE); entry = pi->entry; move_to(gc, entry->sec, entry->phe); for (i = 1; i < pi->nr; i++) { entry++; - if (entry->phe < partial_pressure_graphs.phe_threshold) + if (entry->phe < prefs.pp_graphs.phe_threshold) line_to(gc, entry->sec, entry->phe); else move_to(gc, entry->sec, entry->phe); @@ -608,20 +607,20 @@ static void plot_pp_gas_profile(struct graphics_context *gc, struct plot_info *p move_to(gc, entry->sec, entry->phe); for (i = 1; i < pi->nr; i++) { entry++; - if (entry->phe >= partial_pressure_graphs.phe_threshold) + if (entry->phe >= prefs.pp_graphs.phe_threshold) line_to(gc, entry->sec, entry->phe); else move_to(gc, entry->sec, entry->phe); } cairo_stroke(gc->cr); } - if (partial_pressure_graphs.po2) { + if (prefs.pp_graphs.po2) { set_source_rgba(gc, PO2); entry = pi->entry; move_to(gc, entry->sec, entry->po2); for (i = 1; i < pi->nr; i++) { entry++; - if (entry->po2 < partial_pressure_graphs.po2_threshold) + if (entry->po2 < prefs.pp_graphs.po2_threshold) line_to(gc, entry->sec, entry->po2); else move_to(gc, entry->sec, entry->po2); @@ -633,7 +632,7 @@ static void plot_pp_gas_profile(struct graphics_context *gc, struct plot_info *p move_to(gc, entry->sec, entry->po2); for (i = 1; i < pi->nr; i++) { entry++; - if (entry->po2 >= partial_pressure_graphs.po2_threshold) + if (entry->po2 >= prefs.pp_graphs.po2_threshold) line_to(gc, entry->sec, entry->po2); else move_to(gc, entry->sec, entry->po2); @@ -696,7 +695,7 @@ static void plot_depth_profile(struct graphics_context *gc, struct plot_info *pi /* Depth markers: every 30 ft or 10 m*/ gc->leftx = 0; gc->rightx = 1.0; gc->topy = 0; gc->bottomy = maxdepth; - switch (output_units.length) { + switch (prefs.output_units.length) { case METERS: marker = 10000; break; case FEET: marker = 9144; break; /* 30 ft */ } @@ -761,7 +760,7 @@ static void plot_depth_profile(struct graphics_context *gc, struct plot_info *pi /* if the user wants the deco ceiling more visible, do that here (this * basically draws over the background that we had allowed to shine * through so far) */ - if (profile_red_ceiling) { + if (prefs.profile_red_ceiling) { pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, 256.0 * plot_scale); pattern_add_color_stop_rgba (gc, pat, 0, CEILING_SHALLOW); pattern_add_color_stop_rgba (gc, pat, 1, CEILING_DEEP); @@ -837,12 +836,12 @@ static int setup_temperature_limits(struct graphics_context *gc, struct plot_inf delta = 3000; gc->topy = maxtemp + delta*2; - if (GRAPHS_ENABLED) + if (PP_GRAPHS_ENABLED) gc->bottomy = mintemp - delta * 2; else gc->bottomy = mintemp - delta / 3; - pi->endtempcoord = SCALEY(gc, pi->endtemp); + pi->endtempcoord = SCALEY(gc, pi->mintemp); return maxtemp > mintemp; } @@ -929,7 +928,7 @@ static int get_cylinder_pressure_range(struct graphics_context *gc, struct plot_ gc->leftx = 0; gc->rightx = get_maxtime(pi); - if (GRAPHS_ENABLED) + if (PP_GRAPHS_ENABLED) gc->bottomy = -pi->maxpressure * 0.75; else gc->bottomy = 0; @@ -937,7 +936,7 @@ static int get_cylinder_pressure_range(struct graphics_context *gc, struct plot_ if (!pi->maxpressure) return FALSE; - while (pi->endtempcoord <= SCALEY(gc, pi->endpressure - (gc->topy) * 0.1)) + while (pi->endtempcoord <= SCALEY(gc, pi->minpressure - (gc->topy) * 0.1)) gc->bottomy -= gc->topy * 0.1; return TRUE; @@ -1175,27 +1174,6 @@ static struct plot_info *analyze_plot_info(struct plot_info *pi) int i; int nr = pi->nr; - /* Do pressure min/max based on the non-surface data */ - for (i = 0; i < nr; i++) { - struct plot_data *entry = pi->entry+i; - int pressure = GET_PRESSURE(entry); - int temperature = entry->temperature; - - if (pressure) { - if (pressure > pi->maxpressure) - pi->maxpressure = pressure; - pi->endpressure = pressure; - } - - if (temperature) { - if (!pi->mintemp || temperature < pi->mintemp) - pi->mintemp = temperature; - if (temperature > pi->maxtemp) - pi->maxtemp = temperature; - pi->endtemp = temperature; - } - } - /* Smoothing function: 5-point triangular smooth */ for (i = 2; i < nr; i++) { struct plot_data *entry = pi->entry+i; @@ -1450,6 +1428,73 @@ static int count_gas_change_events(struct divecomputer *dc) return count; } +static void calculate_max_limits(struct dive *dive, struct graphics_context *gc) +{ + struct divecomputer *dc; + struct plot_info *pi; + int maxdepth = 0; + int maxtime = 0; + int maxpressure = 0, minpressure = INT_MAX; + int mintemp = 0, maxtemp = 0; + int cyl; + + /* The plot-info is embedded in the graphics context */ + pi = &gc->pi; + memset(pi, 0, sizeof(*pi)); + + /* This should probably have been per-dive-computer */ + maxdepth = dive->maxdepth.mm; + mintemp = maxtemp = dive->watertemp.mkelvin; + + /* Get the per-cylinder maximum pressure if they are manual */ + for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) { + unsigned int mbar = dive->cylinder[cyl].start.mbar; + if (mbar > maxpressure) + maxpressure = mbar; + } + + /* Then do all the samples from all the dive computers */ + dc = &dive->dc; + do { + int i = dc->samples; + int lastdepth = 0; + struct sample *s = dc->sample; + + while (--i >= 0) { + int depth = s->depth.mm; + int pressure = s->cylinderpressure.mbar; + int temperature = s->temperature.mkelvin; + + if (!mintemp && temperature < mintemp) + mintemp = temperature; + if (temperature > maxtemp) + maxtemp = temperature; + + if (pressure && pressure < minpressure) + minpressure = pressure; + if (pressure > maxpressure) + maxpressure = pressure; + + if (depth > maxdepth) + maxdepth = s->depth.mm; + if ((depth || lastdepth) && s->time.seconds > maxtime) + maxtime = s->time.seconds; + lastdepth = depth; + s++; + } + } while ((dc = dc->next) != NULL); + + if (minpressure > maxpressure) + minpressure = 0; + + pi->maxdepth = maxdepth; + pi->maxtime = maxtime; + pi->maxpressure = maxpressure; + pi->minpressure = minpressure; + pi->mintemp = mintemp; + pi->maxtemp = maxtemp; +} + /* * Create a plot-info with smoothing and ranged min/max * @@ -1472,7 +1517,6 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer /* The plot-info is embedded in the graphics context */ pi = &gc->pi; - memset(pi, 0, sizeof(*pi)); /* we want to potentially add synthetic plot_info elements for the gas changes */ nr = dc->samples + 4 + 2 * count_gas_change_events(dc); @@ -1576,8 +1620,6 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer lastindex = i + pi_idx; lastdepth = depth; - if (depth > pi->maxdepth) - pi->maxdepth = depth; } entry = pi->entry + i + pi_idx; /* are there still unprocessed gas changes? that would be very strange */ @@ -1699,17 +1741,6 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer pi->nr = lastindex+1; while (pi->nr <= i+2 && pi->entry[pi->nr-1].depth > 0) pi->nr++; - pi->maxtime = pi->entry[lastindex].sec; - - /* Analyze_plot_info() will do the sample max pressures, - * this handles the manual pressures - */ - pi->maxpressure = 0; - for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) { - unsigned int mbar = dive->cylinder[cyl].start.mbar; - if (mbar > pi->maxpressure) - pi->maxpressure = mbar; - } pi->meandepth = dive->meandepth.mm; @@ -1767,7 +1798,11 @@ void plot(struct graphics_context *gc, struct dive *dive, scale_mode_t scale) dc = &fakedc; } - pi = create_plot_info(dive, dc, gc); + /* + * Set up limits that are independent of + * the dive computer + */ + calculate_max_limits(dive, gc); /* shift the drawing area so we have a nice margin around it */ cairo_translate(gc->cr, drawing_area->x, drawing_area->y); @@ -1785,6 +1820,9 @@ void plot(struct graphics_context *gc, struct dive *dive, scale_mode_t scale) gc->maxx = (drawing_area->width - 2*drawing_area->x); gc->maxy = (drawing_area->height - 2*drawing_area->y); + /* This is per-dive-computer. Right now we just do the first one */ + pi = create_plot_info(dive, dc, gc); + /* Depth profile */ plot_depth_profile(gc, pi); plot_events(gc, pi, dc); @@ -1819,7 +1857,7 @@ void plot(struct graphics_context *gc, struct dive *dive, scale_mode_t scale) plot_text(gc, &computer, 0, 1, "%s", dc->model); } - if (GRAPHS_ENABLED) { + if (PP_GRAPHS_ENABLED) { plot_pp_gas_profile(gc, pi); plot_pp_text(gc, pi); } @@ -1884,15 +1922,15 @@ static void plot_string(struct plot_data *entry, char *buf, size_t bufsize, memcpy(buf2, buf, bufsize); snprintf(buf, bufsize, "%s\nNDL:%umin", buf2, entry->ndl / 60); } - if (partial_pressure_graphs.po2) { + if (prefs.pp_graphs.po2) { memcpy(buf2, buf, bufsize); snprintf(buf, bufsize, "%s\npO" UTF8_SUBSCRIPT_2 ":%.2f", buf2, entry->po2); } - if (partial_pressure_graphs.pn2) { + if (prefs.pp_graphs.pn2) { memcpy(buf2, buf, bufsize); snprintf(buf, bufsize, "%s\npN" UTF8_SUBSCRIPT_2 ":%.2f", buf2, entry->pn2); } - if (partial_pressure_graphs.phe) { + if (prefs.pp_graphs.phe) { memcpy(buf2, buf, bufsize); snprintf(buf, bufsize, "%s\npHe:%.2f", buf2, entry->phe); } @@ -1903,7 +1941,7 @@ void get_plot_details(struct graphics_context *gc, int time, char *buf, size_t b { struct plot_info *pi = &gc->pi; int pressure = 0, temp = 0; - struct plot_data *entry; + struct plot_data *entry = NULL; int i; for (i = 0; i < pi->nr; i++) { @@ -1915,5 +1953,6 @@ void get_plot_details(struct graphics_context *gc, int time, char *buf, size_t b if (entry->sec >= time) break; } - plot_string(entry, buf, bufsize, entry->depth, pressure, temp, pi->has_ndl); + if (entry) + plot_string(entry, buf, bufsize, entry->depth, pressure, temp, pi->has_ndl); } diff --git a/statistics.c b/statistics.c index a946d500b..63079a51c 100644 --- a/statistics.c +++ b/statistics.c @@ -317,7 +317,7 @@ void clear_statistics() yearly_tree = NULL; } -static gboolean on_delete(GtkWidget *window, GdkEvent *event, gpointer data) +static gboolean stat_on_delete(GtkWidget *window, GdkEvent *event, gpointer data) { clear_statistics(); gtk_widget_destroy(window); @@ -382,7 +382,7 @@ void show_yearly_stats() update_yearly_stats(); g_signal_connect (G_OBJECT (window), "key_press_event", G_CALLBACK (key_press_event), NULL); - g_signal_connect (G_OBJECT (window), "delete-event", G_CALLBACK (on_delete), NULL); + g_signal_connect (G_OBJECT (window), "delete-event", G_CALLBACK (stat_on_delete), NULL); gtk_widget_show_all(window); } |