X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=equipment.c;h=75a89a35f2d173c7e3e78622f637c69212c41634;hb=c49d2439e85e0aafc353aeda35fb5a14721a49a7;hp=1d3003bf25efdc9b1992a2e438b0911056dba7b3;hpb=a4c9cc110feeb71451614a8105657ed954fdced8;p=ext%2Fsubsurface.git diff --git a/equipment.c b/equipment.c index 1d3003b..75a89a3 100644 --- a/equipment.c +++ b/equipment.c @@ -1,3 +1,13 @@ +/* equipment.c */ +/* creates the UI for the equipment page - + * controlled through the following interfaces: + * + * void show_dive_equipment(struct dive *dive) + * void flush_dive_equipment_changes(struct dive *dive) + * + * called from gtk-ui: + * GtkWidget *equipment_widget(void) + */ #include #include #include @@ -6,11 +16,35 @@ #include "dive.h" #include "display.h" +#include "display-gtk.h" #include "divelist.h" +GtkListStore *cylinder_model; + +enum { + CYL_INDEX, + CYL_DESC, + CYL_SIZE, + CYL_WORKP, + CYL_STARTP, + CYL_ENDP, + CYL_O2, + CYL_HE, + CYL_COLUMNS +}; + +static struct { + int max_index; + GtkListStore *model; + GtkWidget *tree_view; + GtkWidget *edit, *add, *del; + GtkTreeViewColumn *desc, *size, *workp, *startp, *endp, *o2, *he; +} cylinder_list; + struct cylinder_widget { int index, changed; const char *name; + GtkWidget *hbox; GtkComboBox *description; GtkSpinButton *size, *pressure; GtkWidget *o2, *gasmix_button; @@ -18,8 +52,25 @@ struct cylinder_widget { static struct cylinder_widget gtk_cylinder[MAX_CYLINDERS]; -static void set_cylinder_spinbuttons(struct cylinder_widget *cylinder, int ml, int mbar) +static int convert_pressure(int mbar, double *p) { + int decimals = 1; + double pressure; + + pressure = mbar / 1000.0; + if (mbar) { + if (output_units.pressure == PSI) { + pressure *= 14.5037738; /* Bar to PSI */ + decimals = 0; + } + } + *p = pressure; + return decimals; +} + +static int convert_volume_pressure(int ml, int mbar, double *v, double *p) +{ + int decimals = 1; double volume, pressure; volume = ml / 1000.0; @@ -31,9 +82,19 @@ static void set_cylinder_spinbuttons(struct cylinder_widget *cylinder, int ml, i } if (output_units.pressure == PSI) { pressure *= 14.5037738; /* Bar to PSI */ + decimals = 0; } } + *v = volume; + *p = pressure; + return decimals; +} + +static void set_cylinder_spinbuttons(struct cylinder_widget *cylinder, int ml, int mbar) +{ + double volume, pressure; + convert_volume_pressure(ml, mbar, &volume, &pressure); gtk_spin_button_set_value(cylinder->size, volume); gtk_spin_button_set_value(cylinder->pressure, pressure); } @@ -121,17 +182,19 @@ static void add_cylinder(struct cylinder_widget *cylinder, const char *desc, int } } -void show_dive_equipment(struct dive *dive) +static void show_cylinder(cylinder_t *cyl, struct cylinder_widget *cylinder) { - cylinder_t *cyl = &dive->cylinder[0]; - const char *desc = cyl->type.description; - struct cylinder_widget *cylinder = >k_cylinder[0]; + const char *desc; int ml, mbar; double o2; + /* Don't show uninitialized cylinder widgets */ + if (!cylinder->description) + return; + + desc = cyl->type.description; if (!desc) desc = ""; - ml = cyl->type.size.mliter; mbar = cyl->type.workingpressure.mbar; add_cylinder(cylinder, desc, ml, mbar); @@ -145,6 +208,56 @@ void show_dive_equipment(struct dive *dive) gtk_spin_button_set_value(GTK_SPIN_BUTTON(cylinder->o2), o2); } +static int cyl_nothing(cylinder_t *cyl) +{ + return !cyl->type.size.mliter && + !cyl->type.workingpressure.mbar && + !cyl->type.description && + !cyl->gasmix.o2.permille && + !cyl->gasmix.he.permille && + !cyl->start.mbar && + !cyl->end.mbar; +} + +void show_dive_equipment(struct dive *dive) +{ + int i, max; + GtkTreeIter iter; + GtkListStore *model; + + model = cylinder_list.model; + gtk_list_store_clear(model); + max = MAX_CYLINDERS; + do { + cylinder_t *cyl = &dive->cylinder[max-1]; + + if (!cyl_nothing(cyl)) + break; + } while (--max); + + cylinder_list.max_index = max; + + gtk_widget_set_sensitive(cylinder_list.edit, 0); + gtk_widget_set_sensitive(cylinder_list.del, 0); + gtk_widget_set_sensitive(cylinder_list.add, max < MAX_CYLINDERS); + + for (i = 0; i < max; i++) { + cylinder_t *cyl = dive->cylinder+i; + + gtk_list_store_append(model, &iter); + gtk_list_store_set(model, &iter, + CYL_INDEX, i, + CYL_DESC, cyl->type.description ? : "", + CYL_SIZE, cyl->type.size.mliter, + CYL_WORKP, cyl->type.workingpressure.mbar, + CYL_STARTP, cyl->start.mbar, + CYL_ENDP, cyl->end.mbar, + CYL_O2, cyl->gasmix.o2.permille, + CYL_HE, cyl->gasmix.he.permille, + -1); + } +} + static GtkWidget *create_spinbutton(GtkWidget *vbox, const char *name, double min, double max, double incr) { GtkWidget *frame, *hbox, *button; @@ -191,26 +304,54 @@ static void fill_cylinder_info(struct cylinder_widget *cylinder, cylinder_t *cyl add_cylinder(cylinder, desc, ml, mbar); } -static void record_cylinder_changes(struct dive *dive) +static void record_cylinder_changes(cylinder_t *cyl, struct cylinder_widget *cylinder) { const gchar *desc; - struct cylinder_widget *cylinder = >k_cylinder[0]; - GtkComboBox *box = cylinder->description; + GtkComboBox *box; double volume, pressure; int o2; + /* Ignore uninitialized cylinder widgets */ + box = cylinder->description; + if (!box) + return; + desc = gtk_combo_box_get_active_text(box); volume = gtk_spin_button_get_value(cylinder->size); pressure = gtk_spin_button_get_value(cylinder->pressure); o2 = gtk_spin_button_get_value(GTK_SPIN_BUTTON(cylinder->o2))*10 + 0.5; if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cylinder->gasmix_button))) o2 = 0; - fill_cylinder_info(cylinder, dive->cylinder+0, desc, volume, pressure, o2); + fill_cylinder_info(cylinder, cyl, desc, volume, pressure, o2); } void flush_dive_equipment_changes(struct dive *dive) { - record_cylinder_changes(dive); + /* We do nothing: we require the "Ok" button press */ +} + +static void apply_cb(GtkButton *button, gpointer data) +{ + int i; + struct dive *dive = current_dive; + + if (!dive) + return; + + for (i = 0; i < MAX_CYLINDERS; i++) + record_cylinder_changes(dive->cylinder+i, gtk_cylinder+i); + mark_divelist_changed(TRUE); + flush_divelist(dive); +} + +static void cancel_cb(GtkButton *button, gpointer data) +{ + struct dive *dive = current_dive; + + if (!dive) + return; + + show_dive_equipment(current_dive); } /* @@ -293,7 +434,7 @@ static void nitrox_cb(GtkToggleButton *button, gpointer data) gtk_widget_set_sensitive(cylinder->o2, state); } -static void cylinder_widget(GtkWidget *box, int nr, GtkListStore *model) +static void cylinder_widget(int nr, GtkListStore *model) { struct cylinder_widget *cylinder; GtkWidget *frame, *hbox, *hbox2; @@ -304,7 +445,7 @@ static void cylinder_widget(GtkWidget *box, int nr, GtkListStore *model) cylinder->index = nr; hbox = gtk_hbox_new(FALSE, 3); - gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0); + cylinder->hbox = hbox; snprintf(buffer, sizeof(buffer), "Cylinder %d", nr+1); frame = gtk_frame_new(buffer); @@ -319,7 +460,7 @@ static void cylinder_widget(GtkWidget *box, int nr, GtkListStore *model) cylinder->description = GTK_COMBO_BOX(widget); g_signal_connect(widget, "changed", G_CALLBACK(cylinder_cb), cylinder); - widget = create_spinbutton(hbox, "Size", 0, 200, 0.1); + widget = create_spinbutton(hbox, "Size", 0, 300, 0.1); cylinder->size = GTK_SPIN_BUTTON(widget); widget = create_spinbutton(hbox, "Pressure", 0, 5000, 1); @@ -335,6 +476,43 @@ static void cylinder_widget(GtkWidget *box, int nr, GtkListStore *model) gtk_spin_button_set_range(GTK_SPIN_BUTTON(cylinder->o2), 21.0, 100.0); } +static void edit_dive_dialog(int index, GtkListStore *model, GtkTreeIter *iter) +{ +} + +static void edit_cb(GtkButton *button, gpointer data) +{ + int index; + GtkTreeIter iter; + GtkListStore *model = cylinder_list.model; + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cylinder_list.tree_view)); + + /* Nothing selected? This shouldn't happen, since the button should be inactive */ + if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) + return; + + gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CYL_INDEX, &index, -1); + edit_dive_dialog(index, model, &iter); +} + +static void add_cb(GtkButton *button, gpointer data) +{ + int index = cylinder_list.max_index; + GtkTreeIter iter; + GtkListStore *model = cylinder_list.model; + + gtk_list_store_append(model, &iter); + edit_dive_dialog(index, model, &iter); + cylinder_list.max_index++; + gtk_widget_set_sensitive(cylinder_list.add, cylinder_list.max_index < MAX_CYLINDERS); +} + +static void del_cb(GtkButton *button, gpointer data) +{ +} + static GtkListStore *create_tank_size_model(void) { GtkListStore *model; @@ -349,15 +527,155 @@ static GtkListStore *create_tank_size_model(void) return model; } -GtkWidget *equipment_widget(void) +static void size_data_func(GtkTreeViewColumn *col, + GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + int ml, mbar; + double size, pressure; + char buffer[10]; + + gtk_tree_model_get(model, iter, CYL_SIZE, &ml, CYL_WORKP, &mbar, -1); + convert_volume_pressure(ml, mbar, &size, &pressure); + if (size) + snprintf(buffer, sizeof(buffer), "%.1f", size); + else + strcpy(buffer, "unkn"); + g_object_set(renderer, "text", buffer, NULL); +} + +static void pressure_data_func(GtkTreeViewColumn *col, + GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + int index = (long)data; + int mbar, decimals; + double pressure; + char buffer[10]; + + gtk_tree_model_get(model, iter, index, &mbar, -1); + decimals = convert_pressure(mbar, &pressure); + if (mbar) + snprintf(buffer, sizeof(buffer), "%.*f", decimals, pressure); + else + *buffer = 0; + g_object_set(renderer, "text", buffer, NULL); +} + +static void percentage_data_func(GtkTreeViewColumn *col, + GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + int index = (long)data; + int permille; + char buffer[10]; + + gtk_tree_model_get(model, iter, index, &permille, -1); + if (permille) + snprintf(buffer, sizeof(buffer), "%.1f%%", permille / 10.0); + else + *buffer = 0; + g_object_set(renderer, "text", buffer, NULL); +} + +static void selection_cb(GtkTreeSelection *selection, GtkTreeModel *model) +{ + GtkTreeIter iter; + int selected; + + selected = gtk_tree_selection_get_selected(selection, NULL, &iter); + gtk_widget_set_sensitive(cylinder_list.edit, selected); + gtk_widget_set_sensitive(cylinder_list.del, selected); +} + +static GtkWidget *cylinder_list_create(void) { - GtkWidget *vbox; + GtkWidget *tree_view; + GtkTreeSelection *selection; GtkListStore *model; + model = gtk_list_store_new(CYL_COLUMNS, + G_TYPE_INT, /* CYL_INDEX */ + G_TYPE_STRING, /* CYL_DESC: utf8 */ + G_TYPE_INT, /* CYL_SIZE: mliter */ + G_TYPE_INT, /* CYL_WORKP: mbar */ + G_TYPE_INT, /* CYL_STARTP: mbar */ + G_TYPE_INT, /* CYL_ENDP: mbar */ + G_TYPE_INT, /* CYL_O2: permille */ + G_TYPE_INT /* CYL_HE: permille */ + ); + cylinder_list.model = model; + tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); + gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE); + g_signal_connect(selection, "changed", G_CALLBACK(selection_cb), model); + + cylinder_list.desc = tree_view_column(tree_view, CYL_DESC, "Type", NULL, PANGO_ALIGN_LEFT, TRUE); + cylinder_list.size = tree_view_column(tree_view, CYL_SIZE, "Size", size_data_func, PANGO_ALIGN_RIGHT, TRUE); + cylinder_list.workp = tree_view_column(tree_view, CYL_WORKP, "MaxPress", pressure_data_func, PANGO_ALIGN_RIGHT, TRUE); + cylinder_list.startp = tree_view_column(tree_view, CYL_STARTP, "Start", pressure_data_func, PANGO_ALIGN_RIGHT, TRUE); + cylinder_list.endp = tree_view_column(tree_view, CYL_ENDP, "End", pressure_data_func, PANGO_ALIGN_RIGHT, TRUE); + cylinder_list.o2 = tree_view_column(tree_view, CYL_O2, "O" UTF8_SUBSCRIPT_2 "%", percentage_data_func, PANGO_ALIGN_RIGHT, TRUE); + cylinder_list.he = tree_view_column(tree_view, CYL_HE, "He%", percentage_data_func, PANGO_ALIGN_RIGHT, TRUE); + return tree_view; +} + +GtkWidget *equipment_widget(void) +{ + GtkWidget *vbox, *hbox, *frame, *framebox; + GtkWidget *add, *del, *edit; + vbox = gtk_vbox_new(FALSE, 3); - model = create_tank_size_model(); - cylinder_widget(vbox, 0, model); + /* + * We create the cylinder size model at startup, since + * we're going to share it across all cylinders and all + * dives. So if you add a new cylinder type in one dive, + * it will show up when you edit the cylinder types for + * another dive. + */ + cylinder_model = create_tank_size_model(); + + cylinder_list.tree_view = cylinder_list_create(); + + hbox = gtk_hbox_new(FALSE, 3); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); + + frame = gtk_frame_new("Cylinders"); + gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, FALSE, 3); + + framebox = gtk_vbox_new(FALSE, 3); + gtk_container_add(GTK_CONTAINER(frame), framebox); + + hbox = gtk_hbox_new(FALSE, 3); + gtk_box_pack_start(GTK_BOX(framebox), hbox, TRUE, FALSE, 3); + + gtk_box_pack_start(GTK_BOX(hbox), cylinder_list.tree_view, TRUE, FALSE, 3); + + hbox = gtk_hbox_new(TRUE, 3); + gtk_box_pack_start(GTK_BOX(framebox), hbox, TRUE, FALSE, 3); + + edit = gtk_button_new_from_stock(GTK_STOCK_EDIT); + add = gtk_button_new_from_stock(GTK_STOCK_ADD); + del = gtk_button_new_from_stock(GTK_STOCK_DELETE); + gtk_box_pack_start(GTK_BOX(hbox), edit, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), add, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), del, FALSE, FALSE, 0); + + cylinder_list.edit = edit; + cylinder_list.add = add; + cylinder_list.del = del; + + g_signal_connect(edit, "clicked", G_CALLBACK(edit_cb), NULL); + g_signal_connect(add, "clicked", G_CALLBACK(add_cb), NULL); + g_signal_connect(del, "clicked", G_CALLBACK(del_cb), NULL); return vbox; }