2011-09-20 19:40:34 +00:00
|
|
|
/* equipment.c */
|
|
|
|
/* creates the UI for the equipment page -
|
|
|
|
* controlled through the following interfaces:
|
2011-10-02 20:13:27 +00:00
|
|
|
*
|
2011-09-20 19:40:34 +00:00
|
|
|
* void show_dive_equipment(struct dive *dive)
|
|
|
|
*
|
|
|
|
* called from gtk-ui:
|
|
|
|
* GtkWidget *equipment_widget(void)
|
|
|
|
*/
|
2011-09-09 15:38:48 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#include "dive.h"
|
|
|
|
#include "display.h"
|
2011-09-20 19:40:34 +00:00
|
|
|
#include "display-gtk.h"
|
2011-09-09 15:38:48 +00:00
|
|
|
#include "divelist.h"
|
|
|
|
|
2011-10-22 15:12:30 +00:00
|
|
|
static GtkListStore *cylinder_model;
|
2011-10-02 20:13:27 +00:00
|
|
|
|
|
|
|
enum {
|
|
|
|
CYL_DESC,
|
|
|
|
CYL_SIZE,
|
|
|
|
CYL_WORKP,
|
|
|
|
CYL_STARTP,
|
|
|
|
CYL_ENDP,
|
|
|
|
CYL_O2,
|
|
|
|
CYL_HE,
|
|
|
|
CYL_COLUMNS
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct {
|
2011-10-02 20:42:51 +00:00
|
|
|
int max_index;
|
2011-10-02 20:13:27 +00:00
|
|
|
GtkListStore *model;
|
|
|
|
GtkWidget *edit, *add, *del;
|
|
|
|
} cylinder_list;
|
|
|
|
|
2011-09-13 19:58:53 +00:00
|
|
|
struct cylinder_widget {
|
2011-09-13 20:15:31 +00:00
|
|
|
int index, changed;
|
|
|
|
const char *name;
|
2011-09-13 20:50:03 +00:00
|
|
|
GtkWidget *hbox;
|
2011-09-13 19:58:53 +00:00
|
|
|
GtkComboBox *description;
|
2011-11-09 16:37:49 +00:00
|
|
|
GtkSpinButton *size, *pressure;
|
2011-11-09 16:51:20 +00:00
|
|
|
GtkWidget *start, *end, *pressure_button;
|
2011-12-11 19:09:37 +00:00
|
|
|
GtkWidget *o2, *he, *gasmix_button;
|
2011-09-13 19:58:53 +00:00
|
|
|
};
|
|
|
|
|
2011-11-02 04:00:46 +00:00
|
|
|
/* we want bar - so let's not use our unit functions */
|
2011-10-02 20:13:27 +00:00
|
|
|
static int convert_pressure(int mbar, double *p)
|
2011-09-10 22:27:23 +00:00
|
|
|
{
|
2011-10-02 20:13:27 +00:00
|
|
|
int decimals = 1;
|
|
|
|
double pressure;
|
|
|
|
|
2011-11-02 04:00:46 +00:00
|
|
|
if (output_units.pressure == PSI) {
|
|
|
|
pressure = mbar_to_PSI(mbar);
|
|
|
|
decimals = 0;
|
|
|
|
} else {
|
|
|
|
pressure = mbar / 1000.0;
|
2011-10-02 20:13:27 +00:00
|
|
|
}
|
2011-11-02 04:00:46 +00:00
|
|
|
|
2011-10-02 20:13:27 +00:00
|
|
|
*p = pressure;
|
|
|
|
return decimals;
|
|
|
|
}
|
|
|
|
|
2011-12-27 00:46:06 +00:00
|
|
|
static void convert_volume_pressure(int ml, int mbar, double *v, double *p)
|
2011-10-02 20:13:27 +00:00
|
|
|
{
|
2011-09-10 22:27:23 +00:00
|
|
|
double volume, pressure;
|
|
|
|
|
2011-11-09 15:56:07 +00:00
|
|
|
volume = ml / 1000.0;
|
2011-09-10 22:27:23 +00:00
|
|
|
if (mbar) {
|
|
|
|
if (output_units.volume == CUFT) {
|
2011-11-02 04:00:46 +00:00
|
|
|
volume = ml_to_cuft(ml);
|
|
|
|
volume *= bar_to_atm(mbar / 1000.0);
|
2011-11-09 15:56:07 +00:00
|
|
|
}
|
2011-11-02 04:00:46 +00:00
|
|
|
|
2011-09-10 22:27:23 +00:00
|
|
|
if (output_units.pressure == PSI) {
|
2011-11-02 04:00:46 +00:00
|
|
|
pressure = mbar_to_PSI(mbar);
|
|
|
|
} else
|
|
|
|
pressure = mbar / 1000.0;
|
2011-09-10 22:27:23 +00:00
|
|
|
}
|
2011-10-02 20:13:27 +00:00
|
|
|
*v = volume;
|
|
|
|
*p = pressure;
|
|
|
|
}
|
2011-09-10 22:27:23 +00:00
|
|
|
|
2011-10-22 14:18:58 +00:00
|
|
|
static void set_cylinder_type_spinbuttons(struct cylinder_widget *cylinder, int ml, int mbar)
|
2011-10-02 20:13:27 +00:00
|
|
|
{
|
|
|
|
double volume, pressure;
|
|
|
|
|
|
|
|
convert_volume_pressure(ml, mbar, &volume, &pressure);
|
2011-09-13 20:15:31 +00:00
|
|
|
gtk_spin_button_set_value(cylinder->size, volume);
|
|
|
|
gtk_spin_button_set_value(cylinder->pressure, pressure);
|
2011-10-22 14:18:58 +00:00
|
|
|
}
|
|
|
|
|
2011-11-09 16:33:13 +00:00
|
|
|
static void set_cylinder_pressure_spinbuttons(struct cylinder_widget *cylinder, cylinder_t *cyl)
|
2011-10-22 14:18:58 +00:00
|
|
|
{
|
2011-11-09 16:51:20 +00:00
|
|
|
int set;
|
|
|
|
unsigned int start, end;
|
2011-10-22 14:18:58 +00:00
|
|
|
double pressure;
|
2011-10-17 18:12:11 +00:00
|
|
|
|
2011-11-09 16:51:20 +00:00
|
|
|
start = cyl->start.mbar;
|
|
|
|
end = cyl->end.mbar;
|
|
|
|
set = start || end;
|
|
|
|
if (!set) {
|
|
|
|
start = cyl->sample_start.mbar;
|
|
|
|
end = cyl->sample_end.mbar;
|
|
|
|
}
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cylinder->pressure_button), set);
|
|
|
|
gtk_widget_set_sensitive(cylinder->start, set);
|
|
|
|
gtk_widget_set_sensitive(cylinder->end, set);
|
|
|
|
|
|
|
|
convert_pressure(start, &pressure);
|
2011-11-09 16:37:49 +00:00
|
|
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(cylinder->start), pressure);
|
2011-11-09 16:51:20 +00:00
|
|
|
convert_pressure(end, &pressure);
|
2011-11-09 16:37:49 +00:00
|
|
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(cylinder->end), pressure);
|
2011-09-10 22:27:23 +00:00
|
|
|
}
|
|
|
|
|
2011-10-23 06:45:35 +00:00
|
|
|
/*
|
|
|
|
* The gtk_tree_model_foreach() interface is bad. It could have
|
|
|
|
* returned whether the callback ever returned true
|
|
|
|
*/
|
|
|
|
static GtkTreeIter *found_match = NULL;
|
|
|
|
static GtkTreeIter match_iter;
|
|
|
|
|
|
|
|
static gboolean match_cylinder(GtkTreeModel *model,
|
|
|
|
GtkTreePath *path,
|
|
|
|
GtkTreeIter *iter,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
int match;
|
|
|
|
gchar *name;
|
|
|
|
const char *desc = data;
|
|
|
|
|
|
|
|
gtk_tree_model_get(model, iter, 0, &name, -1);
|
|
|
|
match = !strcmp(desc, name);
|
|
|
|
g_free(name);
|
|
|
|
if (match) {
|
|
|
|
match_iter = *iter;
|
|
|
|
found_match = &match_iter;
|
|
|
|
}
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_active_cylinder(GtkComboBox *combo_box, GtkTreeIter *iter)
|
|
|
|
{
|
|
|
|
char *desc;
|
|
|
|
|
|
|
|
if (gtk_combo_box_get_active_iter(combo_box, iter))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
desc = gtk_combo_box_get_active_text(combo_box);
|
|
|
|
|
|
|
|
found_match = NULL;
|
|
|
|
gtk_tree_model_foreach(GTK_TREE_MODEL(cylinder_model), match_cylinder, (void *)desc);
|
|
|
|
|
|
|
|
g_free(desc);
|
|
|
|
if (!found_match)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
*iter = *found_match;
|
|
|
|
gtk_combo_box_set_active_iter(combo_box, iter);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-09-10 04:39:54 +00:00
|
|
|
static void cylinder_cb(GtkComboBox *combo_box, gpointer data)
|
|
|
|
{
|
|
|
|
GtkTreeIter iter;
|
|
|
|
GtkTreeModel *model = gtk_combo_box_get_model(combo_box);
|
2011-10-22 14:18:58 +00:00
|
|
|
int ml, mbar;
|
2011-09-13 20:15:31 +00:00
|
|
|
struct cylinder_widget *cylinder = data;
|
|
|
|
cylinder_t *cyl = current_dive->cylinder + cylinder->index;
|
2011-09-10 04:39:54 +00:00
|
|
|
|
2011-09-10 18:09:39 +00:00
|
|
|
/* Did the user set it to some non-standard value? */
|
2011-10-23 06:45:35 +00:00
|
|
|
if (!get_active_cylinder(combo_box, &iter)) {
|
2011-09-13 20:15:31 +00:00
|
|
|
cylinder->changed = 1;
|
2011-09-10 04:39:54 +00:00
|
|
|
return;
|
2011-09-10 18:09:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We get "change" signal callbacks just because we set
|
|
|
|
* the description by hand. Whatever. So ignore them if
|
|
|
|
* they are no-ops.
|
|
|
|
*/
|
2011-09-13 20:15:31 +00:00
|
|
|
if (!cylinder->changed && cyl->type.description) {
|
2011-09-10 18:09:39 +00:00
|
|
|
int same;
|
|
|
|
char *desc = gtk_combo_box_get_active_text(combo_box);
|
|
|
|
|
|
|
|
same = !strcmp(desc, cyl->type.description);
|
|
|
|
g_free(desc);
|
|
|
|
if (same)
|
|
|
|
return;
|
|
|
|
}
|
2011-09-13 20:15:31 +00:00
|
|
|
cylinder->changed = 1;
|
2011-09-10 04:39:54 +00:00
|
|
|
|
2011-10-17 18:12:11 +00:00
|
|
|
gtk_tree_model_get(model, &iter,
|
|
|
|
CYL_SIZE, &ml,
|
|
|
|
CYL_WORKP, &mbar,
|
|
|
|
-1);
|
2011-09-10 04:39:54 +00:00
|
|
|
|
2011-10-22 14:18:58 +00:00
|
|
|
set_cylinder_type_spinbuttons(cylinder, ml, mbar);
|
2011-09-10 04:39:54 +00:00
|
|
|
}
|
2011-09-10 02:46:53 +00:00
|
|
|
|
2011-10-22 15:12:30 +00:00
|
|
|
static GtkTreeIter *add_cylinder_type(const char *desc, int ml, int mbar, GtkTreeIter *iter)
|
2011-09-11 00:14:07 +00:00
|
|
|
{
|
|
|
|
GtkTreeModel *model;
|
|
|
|
|
2011-10-22 15:12:30 +00:00
|
|
|
/* Don't even bother adding stuff without a size */
|
|
|
|
if (!ml)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
found_match = NULL;
|
|
|
|
model = GTK_TREE_MODEL(cylinder_model);
|
|
|
|
gtk_tree_model_foreach(model, match_cylinder, (void *)desc);
|
2011-09-11 00:14:07 +00:00
|
|
|
|
|
|
|
if (!found_match) {
|
|
|
|
GtkListStore *store = GTK_LIST_STORE(model);
|
|
|
|
|
2011-10-22 15:12:30 +00:00
|
|
|
gtk_list_store_append(store, iter);
|
|
|
|
gtk_list_store_set(store, iter,
|
2011-09-11 00:14:07 +00:00
|
|
|
0, desc,
|
|
|
|
1, ml,
|
|
|
|
2, mbar,
|
|
|
|
-1);
|
2011-10-22 15:12:30 +00:00
|
|
|
return iter;
|
2011-09-11 00:14:07 +00:00
|
|
|
}
|
2011-10-22 15:12:30 +00:00
|
|
|
return found_match;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When adding a dive, we'll add all the pre-existing cylinder
|
|
|
|
* information from that dive to our cylinder model.
|
|
|
|
*/
|
|
|
|
void add_cylinder_description(cylinder_type_t *type)
|
|
|
|
{
|
|
|
|
GtkTreeIter iter;
|
|
|
|
const char *desc;
|
|
|
|
unsigned int size, workp;
|
|
|
|
|
|
|
|
desc = type->description;
|
|
|
|
if (!desc)
|
|
|
|
return;
|
|
|
|
size = type->size.mliter;
|
|
|
|
workp = type->workingpressure.mbar;
|
|
|
|
add_cylinder_type(desc, size, workp, &iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_cylinder(struct cylinder_widget *cylinder, const char *desc, int ml, int mbar)
|
|
|
|
{
|
|
|
|
GtkTreeIter iter, *match;
|
|
|
|
|
|
|
|
cylinder->name = desc;
|
|
|
|
match = add_cylinder_type(desc, ml, mbar, &iter);
|
|
|
|
if (match)
|
|
|
|
gtk_combo_box_set_active_iter(cylinder->description, match);
|
2011-09-11 00:14:07 +00:00
|
|
|
}
|
|
|
|
|
2011-09-13 20:25:06 +00:00
|
|
|
static void show_cylinder(cylinder_t *cyl, struct cylinder_widget *cylinder)
|
2011-09-10 00:10:17 +00:00
|
|
|
{
|
2011-09-13 20:25:06 +00:00
|
|
|
const char *desc;
|
2011-09-11 00:14:07 +00:00
|
|
|
int ml, mbar;
|
2011-12-11 19:09:37 +00:00
|
|
|
int gasmix;
|
|
|
|
double o2, he;
|
2011-09-10 04:39:54 +00:00
|
|
|
|
2011-09-13 20:25:06 +00:00
|
|
|
/* Don't show uninitialized cylinder widgets */
|
|
|
|
if (!cylinder->description)
|
|
|
|
return;
|
|
|
|
|
|
|
|
desc = cyl->type.description;
|
2011-09-10 23:27:19 +00:00
|
|
|
if (!desc)
|
|
|
|
desc = "";
|
2011-09-11 00:14:07 +00:00
|
|
|
ml = cyl->type.size.mliter;
|
|
|
|
mbar = cyl->type.workingpressure.mbar;
|
2011-09-13 20:15:31 +00:00
|
|
|
add_cylinder(cylinder, desc, ml, mbar);
|
2011-09-10 22:27:23 +00:00
|
|
|
|
2011-10-22 14:18:58 +00:00
|
|
|
set_cylinder_type_spinbuttons(cylinder,
|
|
|
|
cyl->type.size.mliter, cyl->type.workingpressure.mbar);
|
2011-11-09 16:33:13 +00:00
|
|
|
set_cylinder_pressure_spinbuttons(cylinder, cyl);
|
2011-12-11 19:09:37 +00:00
|
|
|
|
|
|
|
gasmix = cyl->gasmix.o2.permille || cyl->gasmix.he.permille;
|
|
|
|
gtk_widget_set_sensitive(cylinder->o2, gasmix);
|
|
|
|
gtk_widget_set_sensitive(cylinder->he, gasmix);
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cylinder->gasmix_button), gasmix);
|
|
|
|
|
2011-09-10 18:09:39 +00:00
|
|
|
o2 = cyl->gasmix.o2.permille / 10.0;
|
2011-12-11 19:09:37 +00:00
|
|
|
he = cyl->gasmix.he.permille / 10.0;
|
2011-09-10 18:09:39 +00:00
|
|
|
if (!o2)
|
|
|
|
o2 = 21.0;
|
2011-09-13 20:15:31 +00:00
|
|
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(cylinder->o2), o2);
|
2011-12-11 19:09:37 +00:00
|
|
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(cylinder->he), he);
|
2011-09-10 02:46:53 +00:00
|
|
|
}
|
|
|
|
|
2011-12-09 17:52:59 +00:00
|
|
|
int cylinder_none(cylinder_t *cyl)
|
2011-10-02 20:13:27 +00:00
|
|
|
{
|
|
|
|
return !cyl->type.size.mliter &&
|
|
|
|
!cyl->type.workingpressure.mbar &&
|
|
|
|
!cyl->type.description &&
|
|
|
|
!cyl->gasmix.o2.permille &&
|
|
|
|
!cyl->gasmix.he.permille &&
|
2011-11-09 16:21:48 +00:00
|
|
|
!cyl->sample_start.mbar &&
|
|
|
|
!cyl->sample_end.mbar &&
|
2011-10-02 20:13:27 +00:00
|
|
|
!cyl->start.mbar &&
|
|
|
|
!cyl->end.mbar;
|
|
|
|
}
|
|
|
|
|
2011-10-02 23:41:17 +00:00
|
|
|
static void set_one_cylinder(int index, cylinder_t *cyl, GtkListStore *model, GtkTreeIter *iter)
|
|
|
|
{
|
2011-11-09 16:21:48 +00:00
|
|
|
unsigned int start, end;
|
|
|
|
|
|
|
|
start = cyl->start.mbar ? : cyl->sample_start.mbar;
|
|
|
|
end = cyl->end.mbar ? : cyl->sample_end.mbar;
|
2011-10-02 23:41:17 +00:00
|
|
|
gtk_list_store_set(model, iter,
|
|
|
|
CYL_DESC, cyl->type.description ? : "",
|
|
|
|
CYL_SIZE, cyl->type.size.mliter,
|
|
|
|
CYL_WORKP, cyl->type.workingpressure.mbar,
|
2011-11-09 16:21:48 +00:00
|
|
|
CYL_STARTP, start,
|
|
|
|
CYL_ENDP, end,
|
2011-10-02 23:41:17 +00:00
|
|
|
CYL_O2, cyl->gasmix.o2.permille,
|
|
|
|
CYL_HE, cyl->gasmix.he.permille,
|
|
|
|
-1);
|
|
|
|
}
|
|
|
|
|
2011-09-13 20:25:06 +00:00
|
|
|
void show_dive_equipment(struct dive *dive)
|
|
|
|
{
|
2011-10-02 20:13:27 +00:00
|
|
|
int i, max;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
GtkListStore *model;
|
2011-09-13 20:25:06 +00:00
|
|
|
|
2011-10-02 20:13:27 +00:00
|
|
|
model = cylinder_list.model;
|
|
|
|
gtk_list_store_clear(model);
|
|
|
|
max = MAX_CYLINDERS;
|
|
|
|
do {
|
|
|
|
cylinder_t *cyl = &dive->cylinder[max-1];
|
|
|
|
|
2011-12-09 17:52:59 +00:00
|
|
|
if (!cylinder_none(cyl))
|
2011-10-02 20:13:27 +00:00
|
|
|
break;
|
|
|
|
} while (--max);
|
|
|
|
|
2011-10-02 20:42:51 +00:00
|
|
|
cylinder_list.max_index = max;
|
|
|
|
|
2011-10-02 20:27:03 +00:00
|
|
|
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);
|
|
|
|
|
2011-10-02 20:13:27 +00:00
|
|
|
for (i = 0; i < max; i++) {
|
|
|
|
cylinder_t *cyl = dive->cylinder+i;
|
|
|
|
|
|
|
|
gtk_list_store_append(model, &iter);
|
2011-10-02 23:41:17 +00:00
|
|
|
set_one_cylinder(i, cyl, model, &iter);
|
2011-10-02 20:13:27 +00:00
|
|
|
}
|
2011-09-13 20:25:06 +00:00
|
|
|
}
|
|
|
|
|
2011-09-10 18:09:39 +00:00
|
|
|
static GtkWidget *create_spinbutton(GtkWidget *vbox, const char *name, double min, double max, double incr)
|
2011-09-10 02:46:53 +00:00
|
|
|
{
|
2011-09-11 22:37:56 +00:00
|
|
|
GtkWidget *frame, *hbox, *button;
|
2011-09-10 02:46:53 +00:00
|
|
|
|
|
|
|
frame = gtk_frame_new(name);
|
2011-10-17 18:12:11 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, FALSE, 0);
|
2011-09-11 22:37:56 +00:00
|
|
|
|
|
|
|
hbox = gtk_hbox_new(FALSE, 3);
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
2011-09-10 02:46:53 +00:00
|
|
|
|
2011-09-10 18:09:39 +00:00
|
|
|
button = gtk_spin_button_new_with_range(min, max, incr);
|
2011-10-17 18:12:11 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 0);
|
2011-09-10 02:46:53 +00:00
|
|
|
|
2011-09-10 18:09:39 +00:00
|
|
|
gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
|
|
|
|
|
2011-09-10 02:46:53 +00:00
|
|
|
return button;
|
|
|
|
}
|
|
|
|
|
2011-10-17 18:12:11 +00:00
|
|
|
static void fill_cylinder_info(struct cylinder_widget *cylinder, cylinder_t *cyl, const char *desc,
|
2011-12-11 19:09:37 +00:00
|
|
|
double volume, double pressure, double start, double end, int o2, int he)
|
2011-09-10 02:46:53 +00:00
|
|
|
{
|
2011-09-10 22:27:23 +00:00
|
|
|
int mbar, ml;
|
|
|
|
|
2011-10-17 18:12:11 +00:00
|
|
|
if (output_units.pressure == PSI) {
|
2011-11-02 04:00:46 +00:00
|
|
|
pressure = psi_to_bar(pressure);
|
|
|
|
start = psi_to_bar(start);
|
|
|
|
end = psi_to_bar(end);
|
2011-10-17 18:12:11 +00:00
|
|
|
}
|
2011-09-10 22:27:23 +00:00
|
|
|
|
|
|
|
if (pressure && output_units.volume == CUFT) {
|
2011-11-02 04:12:21 +00:00
|
|
|
volume = cuft_to_l(volume);
|
2011-11-02 04:00:46 +00:00
|
|
|
volume /= bar_to_atm(pressure);
|
2011-09-10 22:27:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ml = volume * 1000 + 0.5;
|
|
|
|
mbar = pressure * 1000 + 0.5;
|
|
|
|
|
2011-12-11 19:09:37 +00:00
|
|
|
/* Ignore obviously crazy He values */
|
|
|
|
if (o2 + he > 1000)
|
|
|
|
he = 0;
|
|
|
|
|
|
|
|
/* We have a rule that normal air is all zeroes */
|
|
|
|
if (!he && o2 > 208 && o2 < 211)
|
2011-09-10 18:09:39 +00:00
|
|
|
o2 = 0;
|
2011-12-11 19:09:37 +00:00
|
|
|
|
2011-09-10 02:46:53 +00:00
|
|
|
cyl->type.description = desc;
|
2011-09-10 22:27:23 +00:00
|
|
|
cyl->type.size.mliter = ml;
|
2011-09-10 02:46:53 +00:00
|
|
|
cyl->type.workingpressure.mbar = mbar;
|
2011-10-17 18:12:11 +00:00
|
|
|
cyl->start.mbar = start * 1000 + 0.5;
|
|
|
|
cyl->end.mbar = end * 1000 + 0.5;
|
2011-09-10 18:09:39 +00:00
|
|
|
cyl->gasmix.o2.permille = o2;
|
2011-12-11 19:09:37 +00:00
|
|
|
cyl->gasmix.he.permille = he;
|
2011-09-10 23:27:19 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Also, insert it into the model if it doesn't already exist
|
|
|
|
*/
|
2011-09-13 20:15:31 +00:00
|
|
|
add_cylinder(cylinder, desc, ml, mbar);
|
2011-09-10 00:10:17 +00:00
|
|
|
}
|
|
|
|
|
2011-09-13 20:25:06 +00:00
|
|
|
static void record_cylinder_changes(cylinder_t *cyl, struct cylinder_widget *cylinder)
|
2011-09-10 00:10:17 +00:00
|
|
|
{
|
2011-09-10 02:46:53 +00:00
|
|
|
const gchar *desc;
|
2011-09-13 20:25:06 +00:00
|
|
|
GtkComboBox *box;
|
2011-10-17 18:12:11 +00:00
|
|
|
double volume, pressure, start, end;
|
2011-12-11 19:09:37 +00:00
|
|
|
int o2, he;
|
2011-09-10 02:46:53 +00:00
|
|
|
|
2011-09-13 20:25:06 +00:00
|
|
|
/* Ignore uninitialized cylinder widgets */
|
|
|
|
box = cylinder->description;
|
|
|
|
if (!box)
|
|
|
|
return;
|
|
|
|
|
2011-09-10 04:39:54 +00:00
|
|
|
desc = gtk_combo_box_get_active_text(box);
|
2011-09-13 20:15:31 +00:00
|
|
|
volume = gtk_spin_button_get_value(cylinder->size);
|
|
|
|
pressure = gtk_spin_button_get_value(cylinder->pressure);
|
2011-11-13 17:29:07 +00:00
|
|
|
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cylinder->pressure_button))) {
|
|
|
|
start = gtk_spin_button_get_value(GTK_SPIN_BUTTON(cylinder->start));
|
|
|
|
end = gtk_spin_button_get_value(GTK_SPIN_BUTTON(cylinder->end));
|
2011-11-13 17:51:34 +00:00
|
|
|
} else {
|
2011-11-09 16:51:20 +00:00
|
|
|
start = end = 0;
|
2011-11-13 17:51:34 +00:00
|
|
|
}
|
2011-12-11 19:09:37 +00:00
|
|
|
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cylinder->gasmix_button))) {
|
2011-11-13 17:29:07 +00:00
|
|
|
o2 = gtk_spin_button_get_value(GTK_SPIN_BUTTON(cylinder->o2))*10 + 0.5;
|
2011-12-11 19:09:37 +00:00
|
|
|
he = gtk_spin_button_get_value(GTK_SPIN_BUTTON(cylinder->he))*10 + 0.5;
|
|
|
|
} else {
|
2011-09-13 18:47:20 +00:00
|
|
|
o2 = 0;
|
2011-12-11 19:09:37 +00:00
|
|
|
he = 0;
|
|
|
|
}
|
|
|
|
fill_cylinder_info(cylinder, cyl, desc, volume, pressure, start, end, o2, he);
|
2011-09-10 04:39:54 +00:00
|
|
|
}
|
|
|
|
|
2011-09-11 00:14:07 +00:00
|
|
|
/*
|
|
|
|
* We hardcode the most common standard cylinders,
|
|
|
|
* we should pick up any other names from the dive
|
|
|
|
* logs directly.
|
|
|
|
*/
|
2011-09-09 15:38:48 +00:00
|
|
|
static struct tank_info {
|
|
|
|
const char *name;
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
int cuft, ml, psi, bar;
|
2011-09-11 00:14:07 +00:00
|
|
|
} tank_info[100] = {
|
|
|
|
/* Need an empty entry for the no-cylinder case */
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
{ "", },
|
2011-09-11 00:14:07 +00:00
|
|
|
|
|
|
|
/* Size-only metric cylinders */
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
{ "10.0 l", .ml = 10000 },
|
|
|
|
{ "11.1 l", .ml = 11100 },
|
2011-09-11 00:14:07 +00:00
|
|
|
|
|
|
|
/* Most common AL cylinders */
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
{ "AL50", .cuft = 50, .psi = 3000 },
|
|
|
|
{ "AL63", .cuft = 63, .psi = 3000 },
|
|
|
|
{ "AL72", .cuft = 72, .psi = 3000 },
|
|
|
|
{ "AL80", .cuft = 80, .psi = 3000 },
|
|
|
|
{ "AL100", .cuft = 100, .psi = 3300 },
|
2011-09-11 00:14:07 +00:00
|
|
|
|
|
|
|
/* Somewhat common LP steel cylinders */
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
{ "LP85", .cuft = 85, 2640 },
|
|
|
|
{ "LP95", .cuft = 95, 2640 },
|
|
|
|
{ "LP108", .cuft = 108, 2640 },
|
|
|
|
{ "LP121", .cuft = 121, 2640 },
|
2011-09-11 00:14:07 +00:00
|
|
|
|
|
|
|
/* Somewhat common HP steel cylinders */
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
{ "HP65", .cuft = 65, .psi = 3442 },
|
|
|
|
{ "HP80", .cuft = 80, .psi = 3442 },
|
|
|
|
{ "HP100", .cuft = 100, .psi = 3442 },
|
|
|
|
{ "HP119", .cuft = 119, .psi = 3442 },
|
|
|
|
{ "HP130", .cuft = 130, .psi = 3442 },
|
2011-09-11 00:14:07 +00:00
|
|
|
|
2011-12-11 20:03:55 +00:00
|
|
|
/* Common European steel cylinders */
|
|
|
|
{ "10L 300 bar", .ml = 10000, .bar = 300 },
|
|
|
|
{ "12L 200 bar", .ml = 12000, .bar = 200 },
|
|
|
|
{ "12L 232 bar", .ml = 12000, .bar = 232 },
|
|
|
|
{ "12L 300 bar", .ml = 12000, .bar = 300 },
|
|
|
|
{ "15L 200 bar", .ml = 15000, .bar = 200 },
|
|
|
|
{ "15L 232 bar", .ml = 15000, .bar = 232 },
|
|
|
|
{ "D7 300 bar", .ml = 14000, .bar = 300 },
|
|
|
|
{ "D8.5 232 bar", .ml = 17000, .bar = 232 },
|
|
|
|
{ "D12 232 bar", .ml = 24000, .bar = 232 },
|
|
|
|
|
2011-09-11 00:14:07 +00:00
|
|
|
/* We'll fill in more from the dive log dynamically */
|
2011-09-09 15:38:48 +00:00
|
|
|
{ NULL, }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void fill_tank_list(GtkListStore *store)
|
|
|
|
{
|
|
|
|
GtkTreeIter iter;
|
|
|
|
struct tank_info *info = tank_info;
|
|
|
|
|
|
|
|
while (info->name) {
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
int ml = info->ml;
|
|
|
|
int cuft = info->cuft;
|
2011-09-09 15:38:48 +00:00
|
|
|
int psi = info->psi;
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
int mbar;
|
|
|
|
double bar = info->bar;
|
2011-09-09 15:38:48 +00:00
|
|
|
|
|
|
|
/* Is it in cuft and psi? */
|
|
|
|
if (psi) {
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
bar = psi_to_bar(psi);
|
2011-09-09 15:38:48 +00:00
|
|
|
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
if (cuft) {
|
|
|
|
double airvolume = cuft_to_l(cuft) * 1000.0;
|
|
|
|
double atm = bar_to_atm(bar);
|
|
|
|
|
|
|
|
ml = airvolume / atm + 0.5;
|
|
|
|
}
|
2011-09-09 15:38:48 +00:00
|
|
|
}
|
|
|
|
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
mbar = bar * 1000 + 0.5;
|
|
|
|
|
2011-09-09 15:38:48 +00:00
|
|
|
gtk_list_store_append(store, &iter);
|
|
|
|
gtk_list_store_set(store, &iter,
|
|
|
|
0, info->name,
|
|
|
|
1, ml,
|
|
|
|
2, mbar,
|
|
|
|
-1);
|
|
|
|
info++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-11 19:09:37 +00:00
|
|
|
static void gasmix_cb(GtkToggleButton *button, gpointer data)
|
2011-09-13 18:47:20 +00:00
|
|
|
{
|
2011-09-13 20:15:31 +00:00
|
|
|
struct cylinder_widget *cylinder = data;
|
2011-09-13 18:47:20 +00:00
|
|
|
int state;
|
|
|
|
|
|
|
|
state = gtk_toggle_button_get_active(button);
|
2011-09-13 20:15:31 +00:00
|
|
|
gtk_widget_set_sensitive(cylinder->o2, state);
|
2011-12-11 19:09:37 +00:00
|
|
|
gtk_widget_set_sensitive(cylinder->he, state);
|
2011-09-13 18:47:20 +00:00
|
|
|
}
|
|
|
|
|
2011-11-09 16:51:20 +00:00
|
|
|
static void pressure_cb(GtkToggleButton *button, gpointer data)
|
|
|
|
{
|
|
|
|
struct cylinder_widget *cylinder = data;
|
|
|
|
int state;
|
|
|
|
|
|
|
|
state = gtk_toggle_button_get_active(button);
|
|
|
|
gtk_widget_set_sensitive(cylinder->start, state);
|
|
|
|
gtk_widget_set_sensitive(cylinder->end, state);
|
|
|
|
}
|
|
|
|
|
2011-10-22 16:39:03 +00:00
|
|
|
static gboolean completion_cb(GtkEntryCompletion *widget, GtkTreeModel *model, GtkTreeIter *iter, struct cylinder_widget *cylinder)
|
|
|
|
{
|
|
|
|
const char *desc;
|
|
|
|
unsigned int ml, mbar;
|
|
|
|
|
|
|
|
gtk_tree_model_get(model, iter, CYL_DESC, &desc, CYL_SIZE, &ml, CYL_WORKP, &mbar, -1);
|
|
|
|
add_cylinder(cylinder, desc, ml, mbar);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-10-23 06:45:35 +00:00
|
|
|
static void cylinder_activate_cb(GtkComboBox *combo_box, gpointer data)
|
|
|
|
{
|
|
|
|
struct cylinder_widget *cylinder = data;
|
|
|
|
cylinder_cb(cylinder->description, data);
|
|
|
|
}
|
|
|
|
|
2011-12-11 19:09:37 +00:00
|
|
|
/* Return a frame containing a hbox inside a hbox */
|
|
|
|
static GtkWidget *frame_box(const char *title, GtkWidget *vbox)
|
|
|
|
{
|
|
|
|
GtkWidget *hbox, *frame;
|
|
|
|
|
|
|
|
hbox = gtk_hbox_new(FALSE, 10);
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, FALSE, 0);
|
|
|
|
|
|
|
|
frame = gtk_frame_new(title);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, FALSE, 0);
|
|
|
|
|
|
|
|
hbox = gtk_hbox_new(FALSE, 10);
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
|
|
|
|
|
|
|
return hbox;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget *labeled_spinbutton(GtkWidget *box, const char *name, double min, double max, double incr)
|
|
|
|
{
|
|
|
|
GtkWidget *hbox, *label, *button;
|
|
|
|
|
|
|
|
hbox = gtk_hbox_new(FALSE, 0);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, FALSE, 0);
|
|
|
|
|
|
|
|
label = gtk_label_new(name);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, FALSE, 0);
|
|
|
|
|
|
|
|
button = gtk_spin_button_new_with_range(min, max, incr);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 0);
|
|
|
|
|
|
|
|
gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
|
|
|
|
|
|
|
|
return button;
|
|
|
|
}
|
|
|
|
|
2011-10-02 23:16:08 +00:00
|
|
|
static void cylinder_widget(GtkWidget *vbox, struct cylinder_widget *cylinder, GtkListStore *model)
|
2011-09-09 15:38:48 +00:00
|
|
|
{
|
2011-10-02 23:16:08 +00:00
|
|
|
GtkWidget *frame, *hbox;
|
2011-10-22 16:39:03 +00:00
|
|
|
GtkEntry *entry;
|
|
|
|
GtkEntryCompletion *completion;
|
2011-09-10 18:09:39 +00:00
|
|
|
GtkWidget *widget;
|
2011-09-09 15:38:48 +00:00
|
|
|
|
2011-10-17 18:12:11 +00:00
|
|
|
/*
|
|
|
|
* Cylinder type: description, size and
|
|
|
|
* working pressure
|
|
|
|
*/
|
2011-10-02 23:16:08 +00:00
|
|
|
frame = gtk_frame_new("Cylinder");
|
2011-09-13 20:15:31 +00:00
|
|
|
|
2011-09-11 22:37:56 +00:00
|
|
|
hbox = gtk_hbox_new(FALSE, 3);
|
2011-10-02 23:16:08 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
2011-09-10 04:39:54 +00:00
|
|
|
|
2011-09-10 18:09:39 +00:00
|
|
|
widget = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(model), 0);
|
2011-10-02 23:16:08 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
|
2011-09-10 18:09:39 +00:00
|
|
|
|
2011-09-13 20:15:31 +00:00
|
|
|
cylinder->description = GTK_COMBO_BOX(widget);
|
|
|
|
g_signal_connect(widget, "changed", G_CALLBACK(cylinder_cb), cylinder);
|
2011-09-10 04:39:54 +00:00
|
|
|
|
2011-10-22 16:39:03 +00:00
|
|
|
entry = GTK_ENTRY(GTK_BIN(widget)->child);
|
2011-10-23 06:45:35 +00:00
|
|
|
g_signal_connect(entry, "activate", G_CALLBACK(cylinder_activate_cb), cylinder);
|
|
|
|
|
2011-10-22 16:39:03 +00:00
|
|
|
completion = gtk_entry_completion_new();
|
|
|
|
gtk_entry_completion_set_text_column(completion, 0);
|
|
|
|
gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(model));
|
|
|
|
g_signal_connect(completion, "match-selected", G_CALLBACK(completion_cb), cylinder);
|
|
|
|
gtk_entry_set_completion(entry, completion);
|
|
|
|
|
2011-10-02 23:16:08 +00:00
|
|
|
hbox = gtk_hbox_new(FALSE, 3);
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 0);
|
|
|
|
|
2011-09-30 00:42:58 +00:00
|
|
|
widget = create_spinbutton(hbox, "Size", 0, 300, 0.1);
|
2011-09-13 20:15:31 +00:00
|
|
|
cylinder->size = GTK_SPIN_BUTTON(widget);
|
2011-09-10 04:39:54 +00:00
|
|
|
|
2011-09-11 22:37:56 +00:00
|
|
|
widget = create_spinbutton(hbox, "Pressure", 0, 5000, 1);
|
2011-09-13 20:15:31 +00:00
|
|
|
cylinder->pressure = GTK_SPIN_BUTTON(widget);
|
2011-09-10 02:46:53 +00:00
|
|
|
|
2011-10-17 18:12:11 +00:00
|
|
|
/*
|
|
|
|
* Cylinder start/end pressures
|
|
|
|
*/
|
2011-12-11 19:09:37 +00:00
|
|
|
hbox = frame_box("Pressure", vbox);
|
2011-10-17 18:12:11 +00:00
|
|
|
|
2011-12-11 19:09:37 +00:00
|
|
|
widget = labeled_spinbutton(hbox, "Start", 0, 5000, 1);
|
2011-11-09 16:37:49 +00:00
|
|
|
cylinder->start = widget;
|
2011-10-17 18:12:11 +00:00
|
|
|
|
2011-12-11 19:09:37 +00:00
|
|
|
widget = labeled_spinbutton(hbox, "End", 0, 5000, 1);
|
2011-11-09 16:37:49 +00:00
|
|
|
cylinder->end = widget;
|
2011-10-17 18:12:11 +00:00
|
|
|
|
2011-12-11 19:09:37 +00:00
|
|
|
cylinder->pressure_button = gtk_check_button_new();
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), cylinder->pressure_button, FALSE, FALSE, 3);
|
|
|
|
g_signal_connect(cylinder->pressure_button, "toggled", G_CALLBACK(pressure_cb), cylinder);
|
|
|
|
|
2011-10-17 18:12:11 +00:00
|
|
|
/*
|
|
|
|
* Cylinder gas mix: Air, Nitrox or Trimix
|
|
|
|
*/
|
2011-12-11 19:09:37 +00:00
|
|
|
hbox = frame_box("Gasmix", vbox);
|
2011-10-17 18:12:11 +00:00
|
|
|
|
2011-12-11 19:09:37 +00:00
|
|
|
widget = labeled_spinbutton(hbox, "O"UTF8_SUBSCRIPT_2 "%", 1, 100, 0.1);
|
2011-09-13 20:15:31 +00:00
|
|
|
cylinder->o2 = widget;
|
2011-12-11 19:09:37 +00:00
|
|
|
widget = labeled_spinbutton(hbox, "He%", 0, 100, 0.1);
|
|
|
|
cylinder->he = widget;
|
2011-09-13 20:15:31 +00:00
|
|
|
cylinder->gasmix_button = gtk_check_button_new();
|
2011-12-11 19:09:37 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), cylinder->gasmix_button, FALSE, FALSE, 3);
|
|
|
|
g_signal_connect(cylinder->gasmix_button, "toggled", G_CALLBACK(gasmix_cb), cylinder);
|
2011-09-09 15:38:48 +00:00
|
|
|
}
|
|
|
|
|
2011-10-03 00:16:50 +00:00
|
|
|
static int edit_cylinder_dialog(int index, cylinder_t *cyl)
|
2011-10-02 20:42:51 +00:00
|
|
|
{
|
2011-10-03 00:16:50 +00:00
|
|
|
int success;
|
2011-10-02 23:41:17 +00:00
|
|
|
GtkWidget *dialog, *vbox;
|
2011-10-03 00:16:50 +00:00
|
|
|
struct cylinder_widget cylinder;
|
2011-10-02 23:41:17 +00:00
|
|
|
struct dive *dive;
|
|
|
|
|
|
|
|
cylinder.index = index;
|
|
|
|
cylinder.changed = 0;
|
2011-10-02 23:16:08 +00:00
|
|
|
|
2011-10-03 00:16:50 +00:00
|
|
|
dive = current_dive;
|
|
|
|
if (!dive)
|
|
|
|
return 0;
|
|
|
|
*cyl = dive->cylinder[index];
|
|
|
|
|
2011-10-02 23:16:08 +00:00
|
|
|
dialog = gtk_dialog_new_with_buttons("Cylinder",
|
|
|
|
GTK_WINDOW(main_window),
|
|
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
|
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
2011-10-02 23:41:17 +00:00
|
|
|
cylinder_widget(vbox, &cylinder, cylinder_model);
|
|
|
|
|
|
|
|
show_cylinder(cyl, &cylinder);
|
2011-10-02 23:16:08 +00:00
|
|
|
|
|
|
|
gtk_widget_show_all(dialog);
|
2011-10-03 00:16:50 +00:00
|
|
|
success = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT;
|
|
|
|
if (success) {
|
2011-10-02 23:41:17 +00:00
|
|
|
record_cylinder_changes(cyl, &cylinder);
|
2011-10-03 00:16:50 +00:00
|
|
|
dive->cylinder[index] = *cyl;
|
2011-10-02 23:41:17 +00:00
|
|
|
mark_divelist_changed(TRUE);
|
2011-11-13 17:29:07 +00:00
|
|
|
update_cylinder_related_info(dive);
|
2011-10-02 23:41:17 +00:00
|
|
|
flush_divelist(dive);
|
2011-10-02 23:16:08 +00:00
|
|
|
}
|
2011-10-03 00:16:50 +00:00
|
|
|
|
2011-10-02 23:16:08 +00:00
|
|
|
gtk_widget_destroy(dialog);
|
2011-10-03 00:16:50 +00:00
|
|
|
|
|
|
|
return success;
|
2011-10-02 20:42:51 +00:00
|
|
|
}
|
|
|
|
|
2011-10-03 02:14:00 +00:00
|
|
|
static int get_model_index(GtkListStore *model, GtkTreeIter *iter)
|
|
|
|
{
|
|
|
|
int *p, index;
|
|
|
|
GtkTreePath *path;
|
|
|
|
|
|
|
|
path = gtk_tree_model_get_path(GTK_TREE_MODEL(model), iter);
|
|
|
|
p = gtk_tree_path_get_indices(path);
|
|
|
|
index = p ? *p : 0;
|
|
|
|
gtk_tree_path_free(path);
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
2011-11-19 19:47:04 +00:00
|
|
|
static void edit_cb(GtkButton *button, GtkTreeView *tree_view)
|
2011-10-02 20:13:27 +00:00
|
|
|
{
|
2011-10-02 20:42:51 +00:00
|
|
|
int index;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
GtkListStore *model = cylinder_list.model;
|
|
|
|
GtkTreeSelection *selection;
|
2011-10-03 00:16:50 +00:00
|
|
|
cylinder_t cyl;
|
2011-10-02 20:42:51 +00:00
|
|
|
|
2011-11-19 19:47:04 +00:00
|
|
|
selection = gtk_tree_view_get_selection(tree_view);
|
2011-10-02 20:42:51 +00:00
|
|
|
|
|
|
|
/* Nothing selected? This shouldn't happen, since the button should be inactive */
|
|
|
|
if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
|
|
|
|
return;
|
|
|
|
|
2011-10-03 02:14:00 +00:00
|
|
|
index = get_model_index(model, &iter);
|
2011-10-03 00:16:50 +00:00
|
|
|
if (!edit_cylinder_dialog(index, &cyl))
|
|
|
|
return;
|
|
|
|
|
|
|
|
set_one_cylinder(index, &cyl, model, &iter);
|
2011-10-21 13:14:45 +00:00
|
|
|
repaint_dive();
|
2011-10-02 20:13:27 +00:00
|
|
|
}
|
|
|
|
|
2011-11-19 19:47:04 +00:00
|
|
|
static void add_cb(GtkButton *button, GtkTreeView *tree_view)
|
2011-10-02 20:13:27 +00:00
|
|
|
{
|
2011-10-02 20:42:51 +00:00
|
|
|
int index = cylinder_list.max_index;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
GtkListStore *model = cylinder_list.model;
|
2011-10-02 23:16:08 +00:00
|
|
|
GtkTreeSelection *selection;
|
2011-10-03 00:16:50 +00:00
|
|
|
cylinder_t cyl;
|
|
|
|
|
|
|
|
if (!edit_cylinder_dialog(index, &cyl))
|
|
|
|
return;
|
2011-10-02 20:42:51 +00:00
|
|
|
|
|
|
|
gtk_list_store_append(model, &iter);
|
2011-10-03 00:16:50 +00:00
|
|
|
set_one_cylinder(index, &cyl, model, &iter);
|
2011-10-02 23:16:08 +00:00
|
|
|
|
2011-11-19 19:47:04 +00:00
|
|
|
selection = gtk_tree_view_get_selection(tree_view);
|
2011-10-02 23:16:08 +00:00
|
|
|
gtk_tree_selection_select_iter(selection, &iter);
|
|
|
|
|
2011-10-02 20:42:51 +00:00
|
|
|
cylinder_list.max_index++;
|
|
|
|
gtk_widget_set_sensitive(cylinder_list.add, cylinder_list.max_index < MAX_CYLINDERS);
|
2011-10-02 20:13:27 +00:00
|
|
|
}
|
|
|
|
|
2011-11-19 19:47:04 +00:00
|
|
|
static void del_cb(GtkButton *button, GtkTreeView *tree_view)
|
2011-10-02 20:13:27 +00:00
|
|
|
{
|
2011-10-02 23:58:53 +00:00
|
|
|
int index, nr;
|
2011-10-02 23:16:08 +00:00
|
|
|
GtkTreeIter iter;
|
|
|
|
GtkListStore *model = cylinder_list.model;
|
|
|
|
GtkTreeSelection *selection;
|
2011-10-02 23:58:53 +00:00
|
|
|
struct dive *dive;
|
|
|
|
cylinder_t *cyl;
|
2011-10-02 23:16:08 +00:00
|
|
|
|
2011-11-19 19:47:04 +00:00
|
|
|
selection = gtk_tree_view_get_selection(tree_view);
|
2011-10-02 23:16:08 +00:00
|
|
|
|
|
|
|
/* Nothing selected? This shouldn't happen, since the button should be inactive */
|
|
|
|
if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
|
|
|
|
return;
|
|
|
|
|
2011-10-03 02:14:00 +00:00
|
|
|
index = get_model_index(model, &iter);
|
2011-10-02 23:58:53 +00:00
|
|
|
|
|
|
|
dive = current_dive;
|
|
|
|
if (!dive)
|
|
|
|
return;
|
|
|
|
cyl = dive->cylinder + index;
|
|
|
|
nr = cylinder_list.max_index - index - 1;
|
|
|
|
|
2011-10-03 02:14:00 +00:00
|
|
|
gtk_list_store_remove(model, &iter);
|
2011-10-02 23:16:08 +00:00
|
|
|
|
|
|
|
cylinder_list.max_index--;
|
2011-10-02 23:58:53 +00:00
|
|
|
memmove(cyl, cyl+1, nr*sizeof(*cyl));
|
|
|
|
memset(cyl+nr, 0, sizeof(*cyl));
|
|
|
|
|
|
|
|
mark_divelist_changed(TRUE);
|
|
|
|
flush_divelist(dive);
|
|
|
|
|
2011-10-02 23:16:08 +00:00
|
|
|
gtk_widget_set_sensitive(cylinder_list.edit, 0);
|
|
|
|
gtk_widget_set_sensitive(cylinder_list.del, 0);
|
|
|
|
gtk_widget_set_sensitive(cylinder_list.add, 1);
|
2011-10-02 20:13:27 +00:00
|
|
|
}
|
|
|
|
|
2011-09-09 15:38:48 +00:00
|
|
|
static GtkListStore *create_tank_size_model(void)
|
|
|
|
{
|
|
|
|
GtkListStore *model;
|
|
|
|
|
|
|
|
model = gtk_list_store_new(3,
|
|
|
|
G_TYPE_STRING, /* Tank name */
|
|
|
|
G_TYPE_INT, /* Tank size in mliter */
|
|
|
|
G_TYPE_INT, /* Tank working pressure in mbar */
|
|
|
|
-1);
|
|
|
|
|
|
|
|
fill_tank_list(model);
|
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
2011-10-02 20:13:27 +00:00
|
|
|
static void size_data_func(GtkTreeViewColumn *col,
|
|
|
|
GtkCellRenderer *renderer,
|
|
|
|
GtkTreeModel *model,
|
|
|
|
GtkTreeIter *iter,
|
|
|
|
gpointer data)
|
2011-09-09 15:38:48 +00:00
|
|
|
{
|
2011-10-02 20:13:27 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-10-02 20:27:03 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-10-03 02:03:46 +00:00
|
|
|
static void row_activated_cb(GtkTreeView *tree_view,
|
|
|
|
GtkTreePath *path,
|
|
|
|
GtkTreeViewColumn *column,
|
|
|
|
GtkTreeModel *model)
|
|
|
|
{
|
2011-11-19 19:47:04 +00:00
|
|
|
edit_cb(NULL, tree_view);
|
2011-10-03 02:03:46 +00:00
|
|
|
}
|
|
|
|
|
2011-11-19 19:47:04 +00:00
|
|
|
GtkWidget *cylinder_list_widget(void)
|
2011-10-02 20:13:27 +00:00
|
|
|
{
|
2011-11-19 19:47:04 +00:00
|
|
|
GtkListStore *model = cylinder_list.model;
|
2011-10-02 20:13:27 +00:00
|
|
|
GtkWidget *tree_view;
|
2011-10-02 20:27:03 +00:00
|
|
|
GtkTreeSelection *selection;
|
2011-09-09 15:38:48 +00:00
|
|
|
|
2011-10-02 20:13:27 +00:00
|
|
|
tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
|
2011-11-18 13:13:02 +00:00
|
|
|
gtk_widget_set_can_focus(tree_view, FALSE);
|
2011-11-19 19:47:04 +00:00
|
|
|
|
2011-10-03 02:03:46 +00:00
|
|
|
g_signal_connect(tree_view, "row-activated", G_CALLBACK(row_activated_cb), model);
|
2011-10-02 20:27:03 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2011-10-03 02:03:46 +00:00
|
|
|
g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
|
|
|
|
"enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH,
|
|
|
|
NULL);
|
|
|
|
|
2011-12-11 19:40:17 +00:00
|
|
|
tree_view_column(tree_view, CYL_DESC, "Type", NULL, ALIGN_LEFT | UNSORTABLE);
|
|
|
|
tree_view_column(tree_view, CYL_SIZE, "Size", size_data_func, ALIGN_RIGHT | UNSORTABLE);
|
|
|
|
tree_view_column(tree_view, CYL_WORKP, "MaxPress", pressure_data_func, ALIGN_RIGHT | UNSORTABLE);
|
|
|
|
tree_view_column(tree_view, CYL_STARTP, "Start", pressure_data_func, ALIGN_RIGHT | UNSORTABLE);
|
|
|
|
tree_view_column(tree_view, CYL_ENDP, "End", pressure_data_func, ALIGN_RIGHT | UNSORTABLE);
|
|
|
|
tree_view_column(tree_view, CYL_O2, "O" UTF8_SUBSCRIPT_2 "%", percentage_data_func, ALIGN_RIGHT | UNSORTABLE);
|
|
|
|
tree_view_column(tree_view, CYL_HE, "He%", percentage_data_func, ALIGN_RIGHT | UNSORTABLE);
|
2011-10-02 20:13:27 +00:00
|
|
|
return tree_view;
|
|
|
|
}
|
|
|
|
|
2011-11-19 19:47:04 +00:00
|
|
|
static GtkWidget *cylinder_list_create(void)
|
|
|
|
{
|
|
|
|
GtkListStore *model;
|
|
|
|
|
|
|
|
model = gtk_list_store_new(CYL_COLUMNS,
|
|
|
|
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;
|
|
|
|
return cylinder_list_widget();
|
|
|
|
}
|
|
|
|
|
2011-10-02 20:13:27 +00:00
|
|
|
GtkWidget *equipment_widget(void)
|
|
|
|
{
|
2011-11-19 19:47:04 +00:00
|
|
|
GtkWidget *vbox, *hbox, *frame, *framebox, *tree_view;
|
2011-10-02 20:13:27 +00:00
|
|
|
GtkWidget *add, *del, *edit;
|
|
|
|
|
2011-09-10 02:46:53 +00:00
|
|
|
vbox = gtk_vbox_new(FALSE, 3);
|
2011-09-09 15:38:48 +00:00
|
|
|
|
2011-10-02 20:13:27 +00:00
|
|
|
/*
|
|
|
|
* 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();
|
|
|
|
|
2011-11-19 19:47:04 +00:00
|
|
|
tree_view = cylinder_list_create();
|
2011-09-13 20:50:03 +00:00
|
|
|
|
2011-10-02 20:13:27 +00:00
|
|
|
hbox = gtk_hbox_new(FALSE, 3);
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
|
2011-09-13 20:50:03 +00:00
|
|
|
|
2011-10-02 20:13:27 +00:00
|
|
|
frame = gtk_frame_new("Cylinders");
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, FALSE, 3);
|
2011-09-09 15:38:48 +00:00
|
|
|
|
2011-10-02 20:13:27 +00:00
|
|
|
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);
|
2011-09-20 16:53:45 +00:00
|
|
|
|
2011-11-19 19:47:04 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
|
2011-09-20 16:53:45 +00:00
|
|
|
|
2011-10-02 20:13:27 +00:00
|
|
|
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;
|
|
|
|
|
2011-11-19 19:47:04 +00:00
|
|
|
g_signal_connect(edit, "clicked", G_CALLBACK(edit_cb), tree_view);
|
|
|
|
g_signal_connect(add, "clicked", G_CALLBACK(add_cb), tree_view);
|
|
|
|
g_signal_connect(del, "clicked", G_CALLBACK(del_cb), tree_view);
|
2011-09-20 16:53:45 +00:00
|
|
|
|
2011-09-09 15:38:48 +00:00
|
|
|
return vbox;
|
|
|
|
}
|