#include <string.h>
#include "viking.h"
-
#include "config.h"
+#define VT_COL_WIDTH_NAME 160
+#define VT_COL_WIDTH_TYPE 20
+#define VT_COL_WIDTH_VISIBLE 20
+
#define TREEVIEW_GET(model,iter,what,dest) gtk_tree_model_get(GTK_TREE_MODEL(model),(iter),(what),(dest),-1)
enum {
static void treeview_finalize ( GObject *gob );
static void treeview_add_columns ( VikTreeview *vt );
+static gboolean treeview_drag_data_received ( GtkTreeDragDest *drag_dest, GtkTreePath *dest, GtkSelectionData *selection_data );
+static gboolean treeview_drag_data_delete ( GtkTreeDragSource *drag_source, GtkTreePath *path );
+
GType vik_treeview_get_type (void)
{
static GType vt_type = 0;
return rv;
}
-void vik_treeview_get_iter_from_path_str ( VikTreeview *vt, GtkTreeIter *iter, const gchar *path_str )
+gboolean vik_treeview_get_iter_from_path_str ( VikTreeview *vt, GtkTreeIter *iter, const gchar *path_str )
{
- gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(vt->model), iter, path_str );
+ return gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(vt->model), iter, path_str );
}
static void treeview_add_columns ( VikTreeview *vt )
column = gtk_tree_view_get_column (GTK_TREE_VIEW (vt), col_offset - 1);
gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
GTK_TREE_VIEW_COLUMN_FIXED);
- gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 100);
+ gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column),
+ VT_COL_WIDTH_NAME);
gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
gtk_tree_view_column_set_resizable (GTK_TREE_VIEW_COLUMN (column), TRUE);
renderer = gtk_cell_renderer_pixbuf_new ();
- g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL);
+ g_object_set (G_OBJECT (renderer), "xalign", 0.5, NULL);
col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (vt),
- -1, "Type",
+ -1, "",
renderer, "pixbuf",
ICON_COLUMN,
NULL);
column = gtk_tree_view_get_column (GTK_TREE_VIEW (vt), col_offset - 1);
- gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 33);
+ gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column),
+ VT_COL_WIDTH_TYPE);
gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
renderer = gtk_cell_renderer_toggle_new ();
- g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL);
+ g_object_set (G_OBJECT (renderer), "xalign", 0.5, NULL);
g_signal_connect (renderer, "toggled", G_CALLBACK (treeview_toggled_cb), vt);
col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (vt),
- -1, "Visible",
+ -1, "",
renderer,
"active",
VISIBLE_COLUMN,
NULL);
column = gtk_tree_view_get_column (GTK_TREE_VIEW (vt), col_offset - 1);
- gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 40);
+ gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column),
+ VT_COL_WIDTH_VISIBLE);
gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
}
+static void select_cb(GtkTreeSelection *selection, gpointer data)
+{
+ VikTreeview *vt = data;
+ gint type;
+ GtkTreeIter iter, parent;
+ VikLayer *vl;
+ VikWindow * vw;
+
+ if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
+ type = vik_treeview_item_get_type( vt, &iter);
+
+ while ( type != VIK_TREEVIEW_TYPE_LAYER ) {
+ if ( ! vik_treeview_item_get_parent_iter ( vt, &iter, &parent ) )
+ return;
+ iter = parent;
+ type = vik_treeview_item_get_type (vt, &iter );
+ }
+
+ vl = VIK_LAYER( vik_treeview_item_get_pointer ( vt, &iter ) );
+
+ vw = VIK_GTK_WINDOW_FROM_LAYER(vl);
+ vik_window_selected_layer(vw, vl);
+}
+
void treeview_init ( VikTreeview *vt )
{
guint16 i;
gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (vt)),
GTK_SELECTION_SINGLE);
+ /* Override treestore's dnd methods only; this is easier than deriving from GtkTreeStore.
+ * The downside is that all treestores will have this behavior, so this needs to be
+ * changed if we add more treeviews in the future. //Alex
+ */
+ if (1) {
+ GtkTreeDragSourceIface *isrc;
+ GtkTreeDragDestIface *idest;
+
+ isrc = g_type_interface_peek (g_type_class_peek(G_OBJECT_TYPE(vt->model)), GTK_TYPE_TREE_DRAG_SOURCE);
+ isrc->drag_data_delete = treeview_drag_data_delete;
+
+ idest = g_type_interface_peek (g_type_class_peek(G_OBJECT_TYPE(vt->model)), GTK_TYPE_TREE_DRAG_DEST);
+ idest->drag_data_received = treeview_drag_data_received;
+ }
+
for ( i = 0; i < VIK_LAYER_NUM_TYPES; i++ )
vt->layer_type_icons[i] = vik_layer_load_icon ( i ); /* if icon can't be loaded, it will be null and simply not be shown. */
+ gtk_tree_view_set_reorderable (GTK_TREE_VIEW(vt), TRUE);
+ g_signal_connect(gtk_tree_view_get_selection (GTK_TREE_VIEW (vt)), "changed",
+ G_CALLBACK(select_cb), vt);
+
}
gboolean vik_treeview_item_get_parent_iter ( VikTreeview *vt, GtkTreeIter *iter, GtkTreeIter *parent )
{
g_assert ( iter != NULL );
g_assert ( icon_type < VIK_LAYER_NUM_TYPES );
- gtk_tree_store_insert_before ( GTK_TREE_STORE(vt->model), iter, parent_iter, sibling );
+ if (sibling) {
+ gtk_tree_store_insert_before ( GTK_TREE_STORE(vt->model), iter, parent_iter, sibling );
+ } else {
+ gtk_tree_store_append ( GTK_TREE_STORE(vt->model), iter, parent_iter );
+ }
+
gtk_tree_store_set ( GTK_TREE_STORE(vt->model), iter, NAME_COLUMN, name, VISIBLE_COLUMN, TRUE,
TYPE_COLUMN, VIK_TREEVIEW_TYPE_LAYER, ITEM_PARENT_COLUMN, parent, ITEM_POINTER_COLUMN, item,
ITEM_DATA_COLUMN, data, HAS_VISIBLE_COLUMN, TRUE, EDITABLE_COLUMN, TRUE,
G_OBJECT_CLASS(parent_class)->finalize(gob);
}
+
+static gboolean treeview_drag_data_received (GtkTreeDragDest *drag_dest, GtkTreePath *dest, GtkSelectionData *selection_data)
+{
+ GtkTreeModel *tree_model;
+ GtkTreeStore *tree_store;
+ GtkTreeModel *src_model = NULL;
+ GtkTreePath *src_path = NULL, *dest_cp = NULL;
+ gboolean retval = FALSE;
+ GtkTreeIter src_iter, root_iter, dest_iter, dest_parent;
+ guint *i_src = NULL;
+ VikTreeview *vt;
+ VikLayer *vl;
+
+ g_return_val_if_fail (GTK_IS_TREE_STORE (drag_dest), FALSE);
+
+ tree_model = GTK_TREE_MODEL (drag_dest);
+ tree_store = GTK_TREE_STORE (drag_dest);
+
+ if (gtk_tree_get_row_drag_data (selection_data, &src_model, &src_path) && src_model == tree_model) {
+ /*
+ * Copy src_path to dest. There are two subcases here, depending on what
+ * is being dragged.
+ *
+ * 1. src_path is a layer. In this case, interpret the drop
+ * as a request to move the layer to a different aggregate layer.
+ * If the destination is not an aggregate layer, use the first
+ * ancestor that is.
+ *
+ * 2. src_path is a sublayer. In this case, find ancestors of
+ * both source and destination nodes who are full layers,
+ * and call the move method of that layer type.
+ *
+ */
+ if (!gtk_tree_model_get_iter (src_model, &src_iter, src_path)) {
+ goto out;
+ }
+ if (!gtk_tree_path_compare(src_path, dest)) {
+ goto out;
+ }
+
+ i_src = gtk_tree_path_get_indices (src_path);
+ dest_cp = gtk_tree_path_copy (dest);
+
+ gtk_tree_model_get_iter_first(tree_model, &root_iter);
+ TREEVIEW_GET(tree_model, &root_iter, ITEM_POINTER_COLUMN, &vl);
+ vt = vl->vt;
+
+
+ if (gtk_tree_path_get_depth(dest_cp)>1) { /* can't be sibling of top layer */
+ VikLayer *vl_src, *vl_dest;
+
+ /* Find the first ancestor that is a full layer, and store in dest_parent.
+ * In addition, put in dest_iter where Gtk wants us to insert the dragged object.
+ * (Note that this may end up being an invalid iter).
+ */
+ do {
+ gtk_tree_path_up(dest_cp);
+ dest_iter = dest_parent;
+ gtk_tree_model_get_iter (src_model, &dest_parent, dest_cp);
+ } while (gtk_tree_path_get_depth(dest_cp)>1 &&
+ vik_treeview_item_get_type(vt, &dest_parent) != VIK_TREEVIEW_TYPE_LAYER);
+
+
+ g_assert ( vik_treeview_item_get_parent(vt, &src_iter) );
+ vl_src = vik_treeview_item_get_parent(vt, &src_iter);
+ vl_dest = vik_treeview_item_get_pointer(vt, &dest_parent);
+
+ /* TODO: might want to allow different types, and let the clients handle how they want */
+ if (vl_src->type == vl_dest->type && vik_layer_get_interface(vl_dest->type)->drag_drop_request) {
+ // g_print("moving an item from layer '%s' into layer '%s'\n", vl_src->name, vl_dest->name);
+ vik_layer_get_interface(vl_dest->type)->drag_drop_request(vl_src, vl_dest, &src_iter, dest);
+ }
+ }
+ }
+
+ out:
+ if (dest_cp)
+ gtk_tree_path_free(dest_cp);
+ if (src_path)
+ gtk_tree_path_free (src_path);
+
+ return retval;
+}
+
+/*
+ * This may not be necessary.
+ */
+static gboolean treeview_drag_data_delete ( GtkTreeDragSource *drag_source, GtkTreePath *path )
+{
+ gchar *s_dest = gtk_tree_path_to_string(path);
+ g_print("delete data from %s\n", s_dest);
+ g_free(s_dest);
+ return FALSE;
+}
+