GtkWidget *container_widget;
GtkTreeStore *model, *listmodel, *treemodel;
GtkTreeViewColumn *nr, *date, *stars, *depth, *duration, *location;
- GtkTreeViewColumn *temperature, *cylinder, *nitrox, *sac, *otu;
+ GtkTreeViewColumn *temperature, *cylinder, *totalweight, *suit, *nitrox, *sac, *otu;
int changed;
};
DIVE_DEPTH, /* int: dive->maxdepth in mm */
DIVE_DURATION, /* int: in seconds */
DIVE_TEMPERATURE, /* int: in mkelvin */
+ DIVE_TOTALWEIGHT, /* int: in grams */
+ DIVE_SUIT, /* "wet, 3mm" */
DIVE_CYLINDER,
DIVE_NITROX, /* int: dummy */
DIVE_SAC, /* int: in ml/min */
#endif
static GList *selected_dives;
-static int *selectiontracker;
+ static int st_size = 0;
+
+ gboolean is_in_st(int idx, int *atpos)
+ {
+ int i;
+
+ for (i = 0; i < amount_selected; i++)
+ if (selectiontracker[i] == idx) {
+ if (atpos)
+ *atpos = i;
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ #if DEBUG_SELECTION_TRACKING
+ void dump_selection(void)
+ {
+ int i;
+
+ printf("currently selected are ");
+ for (i = 0; i < amount_selected; i++)
+ printf("%d ", selectiontracker[i]);
+ printf("\n");
+ }
+ #endif
+
+ void track_select(int idx)
+ {
+ if (idx < 0)
+ return;
+
+ #if DEBUG_SELECTION_TRACKING
+ printf("add %d to selection of %d entries\n", idx, amount_selected);
+ #endif
+ if (is_in_st(idx, NULL))
+ return;
+ if (amount_selected >= st_size) {
+ selectiontracker = realloc(selectiontracker, dive_table.nr * sizeof(int));
+ st_size = dive_table.nr;
+ }
+ selectiontracker[amount_selected] = idx;
+ amount_selected++;
+ if (amount_selected == 1)
+ selected_dive = idx;
+ #if DEBUG_SELECTION_TRACKING
+ printf("increased amount_selected to %d\n", amount_selected);
+ dump_selection();
+ #endif
+ }
+
+ void track_unselect(int idx)
+ {
+ if (idx < 0)
+ return;
+
+ #if DEBUG_SELECTION_TRACKING
+ printf("remove %d from selection of %d entries\n", idx, amount_selected);
+ #endif
+ int atpos;
+
+ if (! is_in_st(idx, &atpos))
+ return;
+ memmove(selectiontracker + atpos,
+ selectiontracker + atpos + 1,
+ (amount_selected - atpos - 1) * sizeof(int));
+ amount_selected--;
+ #if DEBUG_SELECTION_TRACKING
+ printf("removed %d at pos %d and decreased amount_selected to %d\n", idx, atpos, amount_selected);
+ dump_selection();
+ #endif
+ }
/* when subsurface starts we want to have the last dive selected. So we simply
walk to the first leaf (and skip the summary entries - which have negative
if(!gtk_tree_view_row_expanded(GTK_TREE_VIEW(dive_list.tree_view), tpath))
gtk_tree_view_expand_row(GTK_TREE_VIEW(dive_list.tree_view), tpath, FALSE);
gtk_tree_model_get(GTK_TREE_MODEL(model), iter, DIVE_INDEX, diveidx, -1);
+ track_select(*diveidx);
}
}
GtkTreeIter *iter, gboolean was_selected)
{
int i, nr_children;
+ gboolean unexpand = FALSE;
GtkTreeIter parent;
GtkTreePath *tpath;
memcpy(&parent, iter, sizeof(parent));
tpath = gtk_tree_model_get_path(model, &parent);
- if(!gtk_tree_view_row_expanded(GTK_TREE_VIEW(dive_list.tree_view), tpath))
- gtk_tree_view_expand_row(GTK_TREE_VIEW(dive_list.tree_view), tpath, FALSE);
+ /* stupid gtk doesn't allow us to select rows that are invisible; so if the
+ user clicks on a row that isn't expanded, we briefly expand it, select the
+ children, and then unexpand it again */
+ if(!gtk_tree_view_row_expanded(GTK_TREE_VIEW(dive_list.tree_view), tpath)) {
+ unexpand = TRUE;
+ gtk_tree_view_expand_row(GTK_TREE_VIEW(dive_list.tree_view), tpath, FALSE);
+ }
nr_children = gtk_tree_model_iter_n_children(model, &parent);
for (i = 0; i < nr_children; i++) {
gtk_tree_model_iter_nth_child(model, iter, &parent, i);
else
gtk_tree_selection_select_iter(selection, iter);
}
+ if (unexpand)
+ gtk_tree_view_collapse_row(GTK_TREE_VIEW(dive_list.tree_view), tpath);
+ }
+
+ /* make sure that if we expand a summary row that is selected, the children show
+ up as selected, too */
+ void row_expanded_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
+ {
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
+
+ if (gtk_tree_selection_path_is_selected(selection, path))
+ select_children(GTK_TREE_MODEL(dive_list.model), selection, iter, FALSE);
}
/* this is called _before_ the selection is changed, for every single entry;
if (gtk_tree_model_get_iter(model, &iter, path)) {
gtk_tree_model_get(model, &iter, DIVE_INDEX, &dive_idx, -1);
+ /* turns out we need to move the selectiontracker here */
+ if (was_selected)
+ track_unselect(dive_idx);
+ else
+ track_select(dive_idx);
if (dive_idx < 0) {
select_children(model, selection, &iter, was_selected);
}
/* this is called when gtk thinks that the selection has changed */
static void selection_cb(GtkTreeSelection *selection, gpointer userdata)
{
- GtkTreeIter iter;
- GtkTreePath *path;
-
- int nr_selected = gtk_tree_selection_count_selected_rows(selection);
-
- if (selected_dives) {
- g_list_foreach (selected_dives, (GFunc) gtk_tree_path_free, NULL);
- g_list_free (selected_dives);
- }
- selected_dives = gtk_tree_selection_get_selected_rows(selection, NULL);
- selectiontracker = realloc(selectiontracker, nr_selected * sizeof(int));
-
- switch (nr_selected) {
- case 0: /* there is no clear way to figure out which dive to show */
- amount_selected = 0;
- selected_dive = -1;
- return;
- case 1:
- /* just pick that dive as selected */
- amount_selected = 1;
- path = g_list_nth_data(selected_dives, 0);
- if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dive_list.model), &iter, path)) {
- gtk_tree_model_get(GTK_TREE_MODEL(dive_list.model), &iter, DIVE_INDEX, &selected_dive, -1);
- /* due to the way this callback gets invoked it is possible that
- in the process of unselecting a summary dive we get here with
- just one summary dive selected - ignore that case */
- if (selected_dive < 0) {
- amount_selected = 0;
- return;
- }
- selectiontracker[0] = selected_dive;
- repaint_dive();
- }
- return;
- default: /* multiple selections - what now?
- * We don't change the selected dive unless there is exactly one dive selected; not sure this
- * is the most intuitive solution.
- * The dives that have been selected are processed */
- amount_selected = g_list_length(selected_dives);
- process_selected_dives(selected_dives, selectiontracker, GTK_TREE_MODEL(dive_list.model));
- repaint_dive();
- return;
- }
+ process_selected_dives(selected_dives, selectiontracker, GTK_TREE_MODEL(dive_list.model));
+ repaint_dive();
}
const char *star_strings[] = {
*o2low_p = mino2;
}
+static int total_weight(struct dive *dive)
+{
+ int i, total_grams = 0;
+
+ if (dive)
+ for (i=0; i< MAX_WEIGHTSYSTEMS; i++)
+ total_grams += dive->weightsystem[i].weight.grams;
+ return total_grams;
+}
+
+static void weight_data_func(GtkTreeViewColumn *col,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ int indx, decimals;
+ double value;
+ char buffer[80];
+ struct dive *dive;
+
+ gtk_tree_model_get(model, iter, DIVE_INDEX, &indx, -1);
+ dive = get_dive(indx);
+ value = get_weight_units(total_weight(dive), &decimals, NULL);
+ if (value == 0.0)
+ *buffer = '\0';
+ else
+ snprintf(buffer, sizeof(buffer), "%.*f", decimals, value);
+
+ g_object_set(renderer, "text", buffer, NULL);
+}
+
static gint nitrox_sort_func(GtkTreeModel *model,
GtkTreeIter *iter_a,
GtkTreeIter *iter_b,
get_string(str, dive->cylinder[0].type.description);
}
+static void get_suit(struct dive *dive, char **str)
+{
+ get_string(str, dive->suit);
+}
+
/*
* Set up anything that could have changed due to editing
* of dive information; we need to do this for both models,
GtkTreeModel *model,
GtkTreeIter *iter)
{
- char *location, *cylinder;
+ char *location, *cylinder, *suit;
GtkTreeStore *othermodel;
get_cylinder(dive, &cylinder);
get_location(dive, &location);
+ get_suit(dive, &suit);
gtk_tree_store_set(GTK_TREE_STORE(model), iter,
DIVE_NR, dive->number,
DIVE_RATING, dive->rating,
DIVE_SAC, dive->sac,
DIVE_OTU, dive->otu,
+ DIVE_TOTALWEIGHT, total_weight(dive),
+ DIVE_SUIT, suit,
-1);
+
+ free(location);
+ free(cylinder);
+ free(suit);
+
if (model == GTK_TREE_MODEL(dive_list.treemodel))
othermodel = dive_list.listmodel;
else
(void) get_temp_units(0, &unit);
gtk_tree_view_column_set_title(dive_list.temperature, unit);
+ (void) get_weight_units(0, NULL, &unit);
+ gtk_tree_view_column_set_title(dive_list.totalweight, unit);
+
gtk_tree_model_foreach(model, set_one_dive, NULL);
}
{
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);
DIVE_LOCATION, dive->location,
DIVE_RATING, dive->rating,
DIVE_TEMPERATURE, dive->watertemp.mkelvin,
+ DIVE_TOTALWEIGHT, 0,
+ DIVE_SUIT, dive->suit,
DIVE_SAC, 0,
-1);
}
first_leaf(GTK_TREE_MODEL(dive_list.model), &iter, &selected_dive);
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
gtk_tree_selection_select_iter(selection, &iter);
- selectiontracker = realloc(selectiontracker, sizeof(int));
- *selectiontracker = selected_dive;
}
}
[DIVE_DEPTH] = { "ft", depth_data_func, NULL, ALIGN_RIGHT },
[DIVE_DURATION] = { "min", duration_data_func, NULL, ALIGN_RIGHT },
[DIVE_TEMPERATURE] = { UTF8_DEGREE "F", temperature_data_func, NULL, ALIGN_RIGHT, &visible_cols.temperature },
+ [DIVE_TOTALWEIGHT] = { "lbs", weight_data_func, NULL, ALIGN_RIGHT, &visible_cols.totalweight },
+ [DIVE_SUIT] = { "Suit", NULL, NULL, ALIGN_LEFT, &visible_cols.suit },
[DIVE_CYLINDER] = { "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] = { "SAC", sac_data_func, NULL, 0, &visible_cols.sac },
G_TYPE_INT, /* Depth */
G_TYPE_INT, /* Duration */
G_TYPE_INT, /* Temperature */
+ G_TYPE_INT, /* Total weight */
+ G_TYPE_STRING, /* Suit */
G_TYPE_STRING, /* Cylinder */
G_TYPE_INT, /* Nitrox */
G_TYPE_INT, /* SAC */
G_TYPE_INT, /* Depth */
G_TYPE_INT, /* Duration */
G_TYPE_INT, /* Temperature */
+ G_TYPE_INT, /* Total weight */
+ G_TYPE_STRING, /* Suit */
G_TYPE_STRING, /* Cylinder */
G_TYPE_INT, /* Nitrox */
G_TYPE_INT, /* SAC */
dive_list.depth = divelist_column(&dive_list, dl_column + DIVE_DEPTH);
dive_list.duration = divelist_column(&dive_list, dl_column + DIVE_DURATION);
dive_list.temperature = divelist_column(&dive_list, dl_column + DIVE_TEMPERATURE);
+ dive_list.totalweight = divelist_column(&dive_list, dl_column + DIVE_TOTALWEIGHT);
+ dive_list.suit = divelist_column(&dive_list, dl_column + DIVE_SUIT);
dive_list.cylinder = divelist_column(&dive_list, dl_column + DIVE_CYLINDER);
dive_list.nitrox = divelist_column(&dive_list, dl_column + DIVE_NITROX);
dive_list.sac = divelist_column(&dive_list, dl_column + DIVE_SAC);
g_signal_connect_after(dive_list.tree_view, "realize", G_CALLBACK(realize_cb), NULL);
g_signal_connect(dive_list.tree_view, "row-activated", G_CALLBACK(row_activated_cb), NULL);
+ g_signal_connect(dive_list.tree_view, "row-expanded", G_CALLBACK(row_expanded_cb), NULL);
g_signal_connect(dive_list.tree_view, "button-press-event", G_CALLBACK(button_press_cb), NULL);
g_signal_connect(dive_list.tree_view, "popup-menu", G_CALLBACK(popup_menu_cb), NULL);
g_signal_connect(selection, "changed", G_CALLBACK(selection_cb), NULL);