From d577d991b97ae2b5ee1af23641bcffc3f83af5b2 Mon Sep 17 00:00:00 2001 From: Pixel Date: Wed, 4 Nov 2009 11:56:41 -0800 Subject: Initial import. Contains the im, cd and iup librairies, and a "working" Makefile for them under linux. --- iup/src/gtk/iupgtk_tree.c | 2369 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2369 insertions(+) create mode 100755 iup/src/gtk/iupgtk_tree.c (limited to 'iup/src/gtk/iupgtk_tree.c') diff --git a/iup/src/gtk/iupgtk_tree.c b/iup/src/gtk/iupgtk_tree.c new file mode 100755 index 0000000..d408f27 --- /dev/null +++ b/iup/src/gtk/iupgtk_tree.c @@ -0,0 +1,2369 @@ +/** \file + * \brief Tree Control + * + * See Copyright Notice in iup.h + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_key.h" +#include "iup_image.h" +#include "iup_array.h" +#include "iup_tree.h" + +#include "iup_drvinfo.h" +#include "iupgtk_drv.h" + +enum +{ + IUPGTK_TREE_IMAGE, + IUPGTK_TREE_HAS_IMAGE, + IUPGTK_TREE_IMAGE_EXPANDED, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, + IUPGTK_TREE_TITLE, + IUPGTK_TREE_KIND, + IUPGTK_TREE_COLOR, + IUPGTK_TREE_FONT, + IUPGTK_TREE_USERDATA +}; + +static GtkTreeIter gtkTreeInvalidIter = {0,0,0,0}; + +/*****************************************************************************/ +/* COPYING ITEMS (Branches and its children) */ +/*****************************************************************************/ +/* Insert the copied item in a new location. Returns the new item. */ +static void gtkTreeCopyItem(GtkTreeModel* model, GtkTreeIter* iterItem, GtkTreeIter* iterParent, int position, GtkTreeIter *iterNewItem, int full_copy) +{ + GtkTreeStore* store = GTK_TREE_STORE(model); + int kind; + char* title; + gboolean has_image, has_image_expanded; + PangoFontDescription* font; + void* userdata; + GdkColor *color; + GdkPixbuf* image, *image_expanded; + + gtk_tree_model_get(GTK_TREE_MODEL(store), iterItem, IUPGTK_TREE_IMAGE, &image, + IUPGTK_TREE_HAS_IMAGE, &has_image, + IUPGTK_TREE_IMAGE_EXPANDED, &image_expanded, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, &has_image_expanded, + IUPGTK_TREE_TITLE, &title, + IUPGTK_TREE_KIND, &kind, + IUPGTK_TREE_COLOR, &color, + IUPGTK_TREE_FONT, &font, + IUPGTK_TREE_USERDATA, &userdata, + -1); + + if (position == 2) + gtk_tree_store_append(store, iterNewItem, iterParent); + else if (position == 1) /* copy as first child of expanded branch */ + gtk_tree_store_insert(store, iterNewItem, iterParent, 0); /* iterParent is parent of the new item (firstchild of it) */ + else /* copy as next brother of item or collapsed branch */ + gtk_tree_store_insert_after(store, iterNewItem, NULL, iterParent); /* iterParent is sibling of the new item */ + + if (full_copy) /* during a full copy the userdata reference is not copied */ + userdata = NULL; + + gtk_tree_store_set(store, iterNewItem, IUPGTK_TREE_IMAGE, image, + IUPGTK_TREE_HAS_IMAGE, has_image, + IUPGTK_TREE_IMAGE_EXPANDED, image_expanded, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, has_image_expanded, + IUPGTK_TREE_TITLE, title, + IUPGTK_TREE_KIND, kind, + IUPGTK_TREE_COLOR, color, + IUPGTK_TREE_FONT, font, + IUPGTK_TREE_USERDATA, userdata, + -1); +} + +static void gtkTreeCopyChildren(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst, int full_copy) +{ + GtkTreeIter iterChildSrc; + int hasItem = gtk_tree_model_iter_children(model, &iterChildSrc, iterItemSrc); /* get the firstchild */ + while(hasItem) + { + GtkTreeIter iterNewItem; + gtkTreeCopyItem(model, &iterChildSrc, iterItemDst, 2, &iterNewItem, full_copy); /* append always */ + + /* Recursively transfer all the items */ + gtkTreeCopyChildren(ih, model, &iterChildSrc, &iterNewItem, full_copy); + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterChildSrc); + } +} + +/* Copies all items in a branch to a new location. Returns the new branch node. */ +static void gtkTreeCopyNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst, GtkTreeIter* iterNewItem, int full_copy) +{ + int kind, position = 0; /* insert after iterItemDst */ + gtk_tree_model_get(model, iterItemDst, IUPGTK_TREE_KIND, &kind, -1); + + if (kind == ITREE_BRANCH) + { + GtkTreePath* path = gtk_tree_model_get_path(model, iterItemDst); + if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) + position = 1; /* insert as first child of iterItemDst */ + gtk_tree_path_free(path); + } + + gtkTreeCopyItem(model, iterItemSrc, iterItemDst, position, iterNewItem, full_copy); + + gtkTreeCopyChildren(ih, model, iterItemSrc, iterNewItem, full_copy); +} + +/*****************************************************************************/ +/* FINDING ITEMS */ +/*****************************************************************************/ + +static void gtkTreeInvertAllNodeMarking(Ihandle* ih, GtkTreeModel* model, GtkTreeSelection* selection, GtkTreeIter* iterItem) +{ + GtkTreeIter iterChild; + int hasItem = TRUE; + + while(hasItem) + { + if(gtk_tree_selection_iter_is_selected(selection, iterItem)) + gtk_tree_selection_unselect_iter(selection, iterItem); + else + gtk_tree_selection_select_iter(selection, iterItem); + + /* Check whether we have child items */ + if(gtk_tree_model_iter_has_child(model, iterItem)) + { + gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ + gtkTreeInvertAllNodeMarking(ih, model, selection, &iterChild); + } + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, iterItem); + } +} + +static GtkTreeIter gtkTreeFindVisibleNodeId(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, GtkTreeIter iterNode) +{ + GtkTreeIter iterChild; + GtkTreePath* path; + int hasItem = TRUE; + + while(hasItem) + { + /* ID control to traverse items */ + ih->data->id_control++; /* not the real id since it counts only the visible ones */ + + /* StateID founded! */ + if(iterItem.user_data == iterNode.user_data) + return iterItem; + + path = gtk_tree_model_get_path(model, &iterItem); + + /* Check whether we have child items and it is expanded (visible) */ + if (gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) + { + gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ + iterChild = gtkTreeFindVisibleNodeId(ih, model, iterChild, iterNode); + + /* StateID founded! */ + if(iterChild.user_data) + { + gtk_tree_path_free(path); + return iterChild; + } + } + + gtk_tree_path_free(path); + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterItem); + } + + return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ +} + +static GtkTreeIter gtkTreeFindVisibleNodeFromId(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem) +{ + GtkTreeIter iterChild; + GtkTreePath* path; + int hasItem = TRUE; + + while(hasItem) + { + /* ID control to traverse items */ + ih->data->id_control--; /* not the real id since it counts only the visible ones */ + + /* StateID founded! */ + if(ih->data->id_control < 0) + return iterItem; + + path = gtk_tree_model_get_path(model, &iterItem); + + /* Check whether we have child items and it is expanded (visible) */ + if(gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) + { + gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ + iterChild = gtkTreeFindVisibleNodeFromId(ih, model, iterChild); + + /* StateID founded! */ + if(ih->data->id_control < 0) + { + gtk_tree_path_free(path); + return iterChild; + } + } + + gtk_tree_path_free(path); + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterItem); + } + + return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ +} + +static GtkTreeIter gtkTreeGetLastVisibleNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem) +{ + GtkTreeIter iterChild, iterPrev = gtkTreeInvalidIter; + GtkTreePath* path = gtk_tree_model_get_path(model, &iterItem); + + /* Check whether we have child items and it is expanded (visible) */ + if(gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) + { + int hasItem = TRUE; + gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ + + while(hasItem) + { + iterPrev = iterChild; + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterChild); + } + + iterItem = gtkTreeGetLastVisibleNode(ih, model, iterPrev); + } + gtk_tree_path_free(path); + + return iterItem; +} + +static GtkTreeIter gtkTreeFindNodeID(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, GtkTreeIter iterNode) +{ + GtkTreeIter iterChild; + int hasItem = TRUE; + + while(hasItem) + { + /* ID control to traverse items */ + ih->data->id_control++; + + /* StateID founded! */ + if (iterItem.user_data == iterNode.user_data) + return iterItem; + + /* Check whether we have child items */ + if (gtk_tree_model_iter_has_child(model, &iterItem)) + { + gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ + iterChild = gtkTreeFindNodeID(ih, model, iterChild, iterNode); + + /* StateID founded! */ + if(iterChild.user_data) + return iterChild; + } + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterItem); + } + + return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ +} + +static int gtkTreeGetNodeId(Ihandle* ih, GtkTreeIter iterItem) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterRoot; + gtk_tree_model_get_iter_first(model, &iterRoot); + + ih->data->id_control = -1; + iterItem = gtkTreeFindNodeID(ih, model, iterRoot, iterItem); + if (iterItem.user_data) + return ih->data->id_control; + else + return -1; +} + +static GtkTreeIter gtkTreeFindUserData(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, void* userdata) +{ + GtkTreeIter iterChild; + int hasItem = TRUE; + void* node_userdata; + + while(hasItem) + { + /* ID control to traverse items */ + ih->data->id_control++; + + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &node_userdata, -1); + + /* userdata founded! */ + if (node_userdata == userdata) + return iterItem; + + /* Check whether we have child items */ + if (gtk_tree_model_iter_has_child(model, &iterItem)) + { + gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ + iterChild = gtkTreeFindUserData(ih, model, iterChild, userdata); + + /* userdata founded! */ + if (iterChild.user_data) + return iterChild; + } + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterItem); + } + + return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ +} + +static int gtkTreeGetUserDataId(Ihandle* ih, GtkTreeModel* model, void* userdata) +{ + GtkTreeIter iterRoot, iterItem; + gtk_tree_model_get_iter_first(model, &iterRoot); + + ih->data->id_control = -1; + iterItem = gtkTreeFindUserData(ih, model, iterRoot, userdata); + if (iterItem.user_data) + return ih->data->id_control; + else + return -1; +} + +static void gtkTreeCallNodeRemovedRec(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, IFnis cb) +{ + GtkTreeIter iterChild; + int hasItem = TRUE; + void* node_userdata; + + while(hasItem) + { + /* ID control to traverse items */ + ih->data->id_control++; + + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &node_userdata, -1); + + cb(ih, ih->data->id_control, (char*)node_userdata); + + /* Check whether we have child items */ + if (gtk_tree_model_iter_has_child(model, &iterItem)) + { + gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ + gtkTreeCallNodeRemovedRec(ih, model, iterChild, cb); + } + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterItem); + } +} + +static void gtkTreeCallNodeRemoved(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem) +{ + IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB"); + if (cb) + { + ih->data->id_control = gtkTreeGetNodeId(ih, *iterItem)-1; + gtkTreeCallNodeRemovedRec(ih, model, *iterItem, cb); + } +} + +static gboolean gtkTreeFindNodeFromID(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem, int *id) +{ + GtkTreeIter iterChild; + int hasItem = TRUE; + + while(hasItem) + { + /* ID control to traverse items */ + (*id)--; + + /* StateID founded! */ + if (*id < 0) + return TRUE; + + /* Check whether we have child items */ + if (gtk_tree_model_iter_has_child(model, iterItem)) + { + gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ + + if (gtkTreeFindNodeFromID(ih, model, &iterChild, id)) + { + *iterItem = iterChild; + return TRUE; + } + } + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, iterItem); + } + + return FALSE; +} + +static gboolean gtkTreeFindNodeFromString(Ihandle* ih, GtkTreeModel* model, const char* name_id, GtkTreeIter *iterItem) +{ + if (name_id[0]) + { + int id; + if (iupStrToInt(name_id, &id)) + { + gtk_tree_model_get_iter_first(model, iterItem); + return gtkTreeFindNodeFromID(ih, model, iterItem, &id); + } + } + else + { + GtkTreePath* path = NULL; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL); + if (path) + { + gtk_tree_model_get_iter(model, iterItem, path); + gtk_tree_path_free(path); + return TRUE; + } + } + return FALSE; +} + +/*****************************************************************************/ +/* MANIPULATING IMAGES */ +/*****************************************************************************/ +static void gtkTreeUpdateImages(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, int mode) +{ + GtkTreeIter iterChild; + int hasItem = TRUE; + int kind; + + while(hasItem) + { + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); + + if (kind == ITREE_BRANCH) + { + if (mode == ITREE_UPDATEIMAGE_EXPANDED) + { + gboolean has_image_expanded = FALSE; + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_HAS_IMAGE_EXPANDED, &has_image_expanded, -1); + if (!has_image_expanded) + gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, -1); + } + else if(mode == ITREE_UPDATEIMAGE_COLLAPSED) + { + gboolean has_image = FALSE; + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_HAS_IMAGE, &has_image, -1); + if (!has_image) + gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, -1); + } + + if (gtk_tree_model_iter_has_child(model, &iterItem)) + { + + /* Recursively traverse child items */ + gtk_tree_model_iter_children(model, &iterChild, &iterItem); + gtkTreeUpdateImages(ih, model, iterChild, mode); + } + } + else + { + if (mode == ITREE_UPDATEIMAGE_LEAF) + { + gboolean has_image = FALSE; + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_HAS_IMAGE, &has_image, -1); + if (!has_image) + gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf, -1); + } + } + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterItem); + } +} + +static void gtkTreeExpandItem(Ihandle* ih, GtkTreePath* path, int expand) +{ + if (expand == -1) + expand = !gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path); /* toggle */ + + if (expand) + gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), path, FALSE); + else + gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path); +} + +int iupgtkGetColor(const char* value, GdkColor *color) +{ + unsigned char r, g, b; + if (iupStrToRGB(value, &r, &g, &b)) + { + iupgdkColorSet(color, r, g, b); + return 1; + } + return 0; +} + +/*****************************************************************************/ +/* ADDING ITEMS */ +/*****************************************************************************/ +void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* title, int add) +{ + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterPrev, iterNewItem, iterParent; + GtkTreePath* path; + GdkColor color = {0L,0,0,0}; + int kindPrev; + + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterPrev)) + return; + + gtk_tree_model_get(GTK_TREE_MODEL(store), &iterPrev, IUPGTK_TREE_KIND, &kindPrev, -1); + + if (kindPrev == ITREE_BRANCH && add) + gtk_tree_store_insert(store, &iterNewItem, &iterPrev, 0); /* iterPrev is parent of the new item (firstchild of it) */ + else + gtk_tree_store_insert_after(store, &iterNewItem, NULL, &iterPrev); /* iterPrev is sibling of the new item */ + + iupgtkGetColor(iupAttribGetStr(ih, "FGCOLOR"), &color); + + /* set the attributes of the new node */ + gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_HAS_IMAGE, FALSE, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, FALSE, + IUPGTK_TREE_TITLE, iupgtkStrConvertToUTF8(title), + IUPGTK_TREE_KIND, kind, + IUPGTK_TREE_COLOR, &color, -1); + + if (kind == ITREE_LEAF) + gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf, -1); + else + gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, + IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, -1); + + if (kindPrev == ITREE_BRANCH && add) + iterParent = iterPrev; + else + gtk_tree_model_iter_parent(GTK_TREE_MODEL(store), &iterParent, &iterNewItem); + + /* If this is the first child of the parent, then handle the ADDEXPANDED attribute */ + if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), &iterParent) == 1) + { + int depth; + path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterParent); + depth = gtk_tree_path_get_depth(path)-1; + if (ih->data->add_expanded || depth==0) /* if this is the first child of the root, expand always */ + { + iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB", "1"); + gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), path, FALSE); + } + else + gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path); + gtk_tree_path_free(path); + } +} + +static void gtkTreeAddRootNode(Ihandle* ih) +{ + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreePath* path; + GtkTreeIter iterRoot; + GdkColor color = {0L,0,0,0}; + + iupgtkGetColor(iupAttribGetStr(ih, "FGCOLOR"), &color); + + gtk_tree_store_append(store, &iterRoot, NULL); /* root node */ + gtk_tree_store_set(store, &iterRoot, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, + IUPGTK_TREE_HAS_IMAGE, FALSE, + IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, FALSE, + IUPGTK_TREE_KIND, ITREE_BRANCH, + IUPGTK_TREE_COLOR, &color, -1); + + path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterRoot); + /* MarkStart node */ + iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)path); + + /* Set the default VALUE */ + gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE); +} + +/*****************************************************************************/ +/* AUXILIAR FUNCTIONS */ +/*****************************************************************************/ +static void gtkTreeOpenCloseEvent(Ihandle* ih) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + GtkTreePath* path; + int kind; + + if (!gtkTreeFindNodeFromString(ih, model, "", &iterItem)) + return; + + path = gtk_tree_model_get_path(model, &iterItem); + if (path) + { + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); + + if (kind == ITREE_LEAF) /* leafs */ + gtk_tree_view_row_activated(GTK_TREE_VIEW(ih->handle), path, (GtkTreeViewColumn*)iupAttribGet(ih, "_IUPGTK_COLUMN")); + else /* branches */ + gtkTreeExpandItem(ih, path, -1); /* toggle */ + + gtk_tree_path_free(path); + } +} + +static gboolean gtkTreeSelected_Foreach_Func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **rowref_list) +{ + GtkTreeRowReference *rowref; + + rowref = gtk_tree_row_reference_new(model, path); + *rowref_list = g_list_append(*rowref_list, rowref); + + (void)iter; + return FALSE; /* do not stop walking the store, call us with next row */ +} + +static gboolean gtkTreeSelected_Iter_Func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **rowref_list) +{ + GtkTreeRowReference *rowref; + GtkTreeIter iterParent; + if (!gtk_tree_model_iter_parent(model, &iterParent, iter)) /* the root node can't be deleted */ + return FALSE; /* do not stop walking the store, call us with next row */ + + rowref = gtk_tree_row_reference_new(model, path); + *rowref_list = g_list_append(*rowref_list, rowref); + + return FALSE; /* do not stop walking the store, call us with next row */ +} + +/*****************************************************************************/ +/* CALLBACKS */ +/*****************************************************************************/ +static void gtkTreeCallMultiSelectionCb(Ihandle* ih) +{ + IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTISELECTION_CB"); + IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); + if (cbMulti || cbSelec) + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterRoot; + GList *rr_list = NULL; + GList *node; + int* id_rowItem; + int count_selected_rows, i = 0; + + gtk_tree_model_get_iter_first(model, &iterRoot); + + gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)gtkTreeSelected_Foreach_Func, &rr_list); + count_selected_rows = g_list_length(rr_list); + id_rowItem = malloc(sizeof(int) * count_selected_rows); + + for(node = rr_list; node != NULL; node = node->next) + { + GtkTreePath* path = gtk_tree_row_reference_get_path(node->data); + if (path) + { + GtkTreeIter iterItem; + gtk_tree_model_get_iter(model, &iterItem, path); + + id_rowItem[i] = gtkTreeGetNodeId(ih, iterItem); + i++; + + gtk_tree_path_free(path); + } + } + + g_list_foreach(rr_list, (GFunc) gtk_tree_row_reference_free, NULL); + g_list_free(rr_list); + + if (cbMulti) + cbMulti(ih, id_rowItem, count_selected_rows); + else + { + for (i=0; ihandle)); +#else + int indent = 0; +#endif + sprintf(str, "%d", indent); + return str; +} + +static int gtkTreeSetIndentationAttrib(Ihandle* ih, const char* value) +{ +#if GTK_CHECK_VERSION(2, 12, 0) + int indent; + if (iupStrToInt(value, &indent)) + gtk_tree_view_set_level_indentation(GTK_TREE_VIEW(ih->handle), indent); +#endif + return 0; +} + +static int gtkTreeSetTopItemAttrib(Ihandle* ih, const char* value) +{ + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; + GtkTreePath* path; + + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), value, &iterItem)) + return 0; + + path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterItem); + + if (!gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) + gtk_tree_view_expand_to_path(GTK_TREE_VIEW(ih->handle), path); + + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE, 0, 0); /* scroll to visible */ + + gtk_tree_path_free(path); + + return 0; +} + +static int gtkTreeSetSpacingAttrib(Ihandle* ih, const char* value) +{ + if(!iupStrToInt(value, &ih->data->spacing)) + ih->data->spacing = 1; + + if(ih->data->spacing < 1) + ih->data->spacing = 1; + + if (ih->handle) + { + GtkCellRenderer *renderer_img = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_IMG"); + GtkCellRenderer *renderer_txt = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_TEXT"); + g_object_set(G_OBJECT(renderer_img), "ypad", ih->data->spacing, NULL); + g_object_set(G_OBJECT(renderer_txt), "ypad", ih->data->spacing, NULL); + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ +} + +static int gtkTreeSetExpandAllAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + gtk_tree_view_expand_all(GTK_TREE_VIEW(ih->handle)); + else + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterRoot; + GtkTreePath* pathRoot; + + gtk_tree_view_collapse_all(GTK_TREE_VIEW(ih->handle)); + + /* The root node is always expanded */ + gtk_tree_model_get_iter_first(model, &iterRoot); + pathRoot = gtk_tree_model_get_path(model, &iterRoot); + gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), pathRoot, FALSE); + gtk_tree_path_free(pathRoot); + } + + return 0; +} + +static char* gtkTreeGetDepthAttrib(Ihandle* ih, const char* name_id) +{ + char* depth; + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + return NULL; + + depth = iupStrGetMemory(10); + sprintf(depth, "%d", gtk_tree_store_iter_depth(store, &iterItem)); + return depth; +} + +static int gtkTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeModel* model; + GtkTreeIter iterItemSrc, iterItemDst, iterNewItem; + GtkTreeIter iterParent, iterNextParent; + + if (!ih->handle) /* do not store the action before map */ + return 0; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItemSrc)) + return 0; + + if (!gtkTreeFindNodeFromString(ih, model, value, &iterItemDst)) + return 0; + + /* If Drag item is an ancestor of Drop item then return */ + iterParent = iterItemDst; + while(gtk_tree_model_iter_parent(model, &iterNextParent, &iterParent)) + { + if (iterNextParent.user_data == iterItemSrc.user_data) + return 0; + iterParent = iterNextParent; + } + + /* Copying the node and its children to the new position */ + gtkTreeCopyNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 0); /* not a full copy, preserve user data */ + + /* Deleting the node of its old position */ + /* do not delete the user data, we copy the references in CopyNode */ + gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItemSrc); + + return 0; +} + +static int gtkTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeModel* model; + GtkTreeIter iterItemSrc, iterItemDst, iterNewItem; + GtkTreeIter iterParent, iterNextParent; + + if (!ih->handle) /* do not store the action before map */ + return 0; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItemSrc)) + return 0; + + if (!gtkTreeFindNodeFromString(ih, model, value, &iterItemDst)) + return 0; + + /* If Drag item is an ancestor of Drop item then return */ + iterParent = iterItemDst; + while(gtk_tree_model_iter_parent(model, &iterNextParent, &iterParent)) + { + if (iterNextParent.user_data == iterItemSrc.user_data) + return 0; + iterParent = iterNextParent; + } + + /* Copying the node and its children to the new position */ + gtkTreeCopyNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 1); + + return 0; +} + +static char* gtkTreeGetColorAttrib(Ihandle* ih, const char* name_id) +{ + char* str; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + GdkColor *color; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_COLOR, &color, -1); + if (!color) + return NULL; + + str = iupStrGetMemory(20); + sprintf(str, "%d %d %d", iupCOLOR16TO8(color->red), + iupCOLOR16TO8(color->green), + iupCOLOR16TO8(color->blue)); + return str; +} + +static int gtkTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; + GdkColor color; + unsigned char r, g, b; + + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + return 0; + + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + iupgdkColorSet(&color, r, g, b); + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_COLOR, &color, -1); + + return 0; +} + +static char* gtkTreeGetParentAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + GtkTreeIter iterParent; + char* str; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + + if (!gtk_tree_model_iter_parent(model, &iterParent, &iterItem)) + return NULL; + + str = iupStrGetMemory(10); + sprintf(str, "%d", gtkTreeGetNodeId(ih, iterParent)); + return str; +} + +static char* gtkTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + char* str; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + + str = iupStrGetMemory(10); + sprintf(str, "%d", gtk_tree_model_iter_n_children(model, &iterItem)); + return str; +} + +static int gtkTreeCount(GtkTreeModel* model, GtkTreeIter iterBranch) +{ + GtkTreeIter iterChild; + int count = 0; + int hasItem = gtk_tree_model_iter_children(model, &iterChild, &iterBranch); /* get the firstchild */ + count++; + while(hasItem) + { + count += gtkTreeCount(model, iterChild); + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterChild); + } + + return count; +} + +static char* gtkTreeGetCountAttrib(Ihandle* ih) +{ + GtkTreeIter iterRoot; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + char* str = iupStrGetMemory(10); + gtk_tree_model_get_iter_first(model, &iterRoot); + sprintf(str, "%d", gtkTreeCount(model, iterRoot)); + return str; +} + +static char* gtkTreeGetKindAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + int kind; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); + + if(!kind) + return "BRANCH"; + else + return "LEAF"; +} + +static char* gtkTreeGetStateAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + + if (gtk_tree_model_iter_has_child(model, &iterItem)) + { + GtkTreePath* path = gtk_tree_model_get_path(model, &iterItem); + int expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path); + gtk_tree_path_free(path); + + if (expanded) + return "EXPANDED"; + else + return "COLLAPSED"; + } + + return NULL; +} + +static int gtkTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + GtkTreePath* path; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return 0; + + path = gtk_tree_model_get_path(model, &iterItem); + gtkTreeExpandItem(ih, path, iupStrEqualNoCase(value, "EXPANDED")); + gtk_tree_path_free(path); + + return 0; +} + +static char* gtkTreeGetTitle(GtkTreeModel* model, GtkTreeIter iterItem) +{ + char* title; + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_TITLE, &title, -1); + return iupgtkStrConvertFromUTF8(title); +} + +static char* gtkTreeGetTitleAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + return gtkTreeGetTitle(model, iterItem); +} + +static int gtkTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + return 0; + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_TITLE, iupgtkStrConvertToUTF8(value), -1); + return 0; +} + +static int gtkTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + PangoFontDescription* fontdesc = NULL; + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + return 0; + if (value) + fontdesc = iupgtkGetPangoFontDesc(value); + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_FONT, fontdesc, -1); + return 0; +} + +static char* gtkTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id) +{ + PangoFontDescription* fontdesc; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_FONT, &fontdesc, -1); + return pango_font_description_to_string(fontdesc); +} + +static char* gtkTreeGetFindUserDataAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + int id; + char* str = (char*)(name_id+1); /* skip ':' */ + void* userdata = NULL; + if (sscanf(str, "%p", &userdata)!=1) + return NULL; + id = gtkTreeGetUserDataId(ih, model, userdata); + if (id == -1) + return NULL; + str = iupStrGetMemory(16); + sprintf(str, "%d", id); + return str; +} + +static char* gtkTreeGetUserDataAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + char* userdata; + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &userdata, -1); + return userdata; +} + +static int gtkTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + return 0; + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_USERDATA, value, -1); + return 0; +} + +static char* gtkTreeGetValueAttrib(Ihandle* ih) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreePath* path = NULL; + char* str; + + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL); + if (path) + { + GtkTreeIter iterItem; + gtk_tree_model_get_iter(model, &iterItem, path); + gtk_tree_path_free(path); + + str = iupStrGetMemory(16); + sprintf(str, "%d", gtkTreeGetNodeId(ih, iterItem)); + return str; + } + + return "0"; /* default VALUE is root */ +} + +static int gtkTreeSetMarkAttrib(Ihandle* ih, const char* value) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterRoot; + + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + return 0; + + gtk_tree_model_get_iter_first(model, &iterRoot); + + if(iupStrEqualNoCase(value, "BLOCK")) + { + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); + gtk_tree_selection_select_range(selection, (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"), pathFocus); + gtk_tree_path_free(pathFocus); + } + else if(iupStrEqualNoCase(value, "CLEARALL")) + gtk_tree_selection_unselect_all(selection); + else if(iupStrEqualNoCase(value, "MARKALL")) + gtk_tree_selection_select_all(selection); + else if(iupStrEqualNoCase(value, "INVERTALL")) /* INVERTALL *MUST* appear before INVERT, or else INVERTALL will never be called. */ + gtkTreeInvertAllNodeMarking(ih, model, selection, &iterRoot); + else if(iupStrEqualPartial(value, "INVERT")) + { + /* iupStrEqualPartial allows the use of "INVERTid" form */ + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, model, &value[strlen("INVERT")], &iterItem)) + return 0; + + if(gtk_tree_selection_iter_is_selected(selection, &iterItem)) + gtk_tree_selection_unselect_iter(selection, &iterItem); + else + gtk_tree_selection_select_iter(selection, &iterItem); + } + else + { + GtkTreePath *path1, *path2; + GtkTreeIter iterItem1, iterItem2; + char str1[50], str2[50]; + if (iupStrToStrStr(value, str1, str2, '-')!=2) + return 0; + + if (!gtkTreeFindNodeFromString(ih, model, str1, &iterItem1)) + return 0; + if (!gtkTreeFindNodeFromString(ih, model, str2, &iterItem2)) + return 0; + + path1 = gtk_tree_model_get_path(model, &iterItem1); + path2 = gtk_tree_model_get_path(model, &iterItem2); + gtk_tree_selection_select_range(selection, path1, path2); + gtk_tree_path_free(path1); + gtk_tree_path_free(path2); + } + + return 1; +} + +static int gtkTreeSetValueAttrib(Ihandle* ih, const char* value) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterRoot, iterItem; + GtkTreePath* path; + + if (gtkTreeSetMarkAttrib(ih, value)) + return 0; + + gtk_tree_model_get_iter_first(model, &iterRoot); + + if (iupStrEqualNoCase(value, "ROOT")) + iterItem = iterRoot; + else if(iupStrEqualNoCase(value, "LAST")) + iterItem = gtkTreeGetLastVisibleNode(ih, model, iterRoot); + else if(iupStrEqualNoCase(value, "PGUP")) + { + GtkTreeIter iterPrev; + + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); + gtk_tree_model_get_iter(model, &iterPrev, pathFocus); + gtk_tree_path_free(pathFocus); + + ih->data->id_control = -1; + gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterPrev); + ih->data->id_control -= 10; /* less 10 visible nodes */ + + if(ih->data->id_control < 0) + ih->data->id_control = 0; /* Begin of tree = Root id */ + + iterItem = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); + } + else if(iupStrEqualNoCase(value, "PGDN")) + { + GtkTreeIter iterNext; + + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); + gtk_tree_model_get_iter(model, &iterNext, pathFocus); + gtk_tree_path_free(pathFocus); + + ih->data->id_control = -1; + gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterNext); + ih->data->id_control += 10; /* more 10 visible nodes */ + + iterNext = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); + + if (ih->data->id_control >= 0) + iterNext = gtkTreeGetLastVisibleNode(ih, model, iterRoot); + + iterItem = iterNext; + } + else if(iupStrEqualNoCase(value, "NEXT")) + { + GtkTreeIter iterNext; + + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); + gtk_tree_model_get_iter(model, &iterNext, pathFocus); + gtk_tree_path_free(pathFocus); + + ih->data->id_control = -1; + gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterNext); + ih->data->id_control++; /* more 1 visible node */ + + iterNext = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); + + if (ih->data->id_control >= 0) + iterNext = gtkTreeGetLastVisibleNode(ih, model, iterRoot); + + iterItem = iterNext; + } + else if(iupStrEqualNoCase(value, "PREVIOUS")) + { + GtkTreeIter iterPrev; + + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); + gtk_tree_model_get_iter(model, &iterPrev, pathFocus); + gtk_tree_path_free(pathFocus); + + ih->data->id_control = -1; + gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterPrev); + ih->data->id_control--; /* less 1 visible node */ + + if (ih->data->id_control < 0) + ih->data->id_control = 0; + + iterItem = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); + if (!iterItem.user_data) + return 0; + } + else + { + if (!gtkTreeFindNodeFromString(ih, model, value, &iterItem)) + return 0; + } + + /* select */ + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + { + iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", "1"); + gtk_tree_selection_select_iter(selection, &iterItem); + } + + path = gtk_tree_model_get_path(model, &iterItem); + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE, 0, 0); /* scroll to visible */ + gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE); /* set focus */ + gtk_tree_path_free(path); + + iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", gtkTreeGetNodeId(ih, iterItem)); + + return 0; +} + +static int gtkTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreePath *pathMarkStart, *pathMarkStartPrev; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return 0; + + pathMarkStart = gtk_tree_model_get_path(model, &iterItem); + + pathMarkStartPrev = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"); + if (pathMarkStartPrev) + gtk_tree_path_free(pathMarkStartPrev); + + iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)pathMarkStart); + + return 1; +} + +static char* gtkTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeSelection* selection; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return 0; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + if (gtk_tree_selection_iter_is_selected(selection, &iterItem)) + return "YES"; + else + return "NO"; +} + +static int gtkTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeSelection* selection; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return 0; + + iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", "1"); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + if (iupStrBoolean(value)) + gtk_tree_selection_select_iter(selection, &iterItem); + else + gtk_tree_selection_unselect_iter(selection, &iterItem); + + return 0; +} + +static int gtkTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + if (iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */ + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + GtkTreeIter iterParent; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return 0; + + if (!gtk_tree_model_iter_parent(model, &iterParent, &iterItem)) /* the root node can't be deleted */ + return 0; + + gtkTreeCallNodeRemoved(ih, model, &iterItem); + + /* deleting the specified node (and it's children) */ + gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItem); + } + else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */ + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem, iterChild; + int hasChildren; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return 0; + + hasChildren = gtk_tree_model_iter_children(model, &iterChild, &iterItem); + + /* deleting the selected node's children */ + while(hasChildren) + { + gtkTreeCallNodeRemoved(ih, model, &iterChild); + hasChildren = gtk_tree_store_remove(GTK_TREE_STORE(model), &iterChild); + } + } + else if(iupStrEqualNoCase(value, "MARKED")) /* Delete the array of marked nodes */ + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + GList *rr_list = NULL; + GList *node; + + gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)gtkTreeSelected_Iter_Func, &rr_list); + + for(node = rr_list; node != NULL; node = node->next) + { + GtkTreePath* path = gtk_tree_row_reference_get_path(node->data); + if (path) + { + GtkTreeIter iterItem; + if (gtk_tree_model_get_iter(model, &iterItem, path)) + { + gtkTreeCallNodeRemoved(ih, model, &iterItem); + gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItem); + } + gtk_tree_path_free(path); + } + gtk_tree_row_reference_free(node->data); + } + g_list_free(rr_list); + } + + return 0; +} + +static int gtkTreeSetRenameAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->show_rename) + { + GtkTreePath* path; + IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); + GtkTreeViewColumn *focus_column; + + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, &focus_column); + + if (cbShowRename) + { + GtkTreeIter iterItem; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + gtk_tree_model_get_iter(model, &iterItem, path); + cbShowRename(ih, gtkTreeGetNodeId(ih, iterItem)); + } + + gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, focus_column, TRUE); + gtk_tree_path_free(path); + } + else + { + IFnis cbRenameNode = (IFnis)IupGetCallback(ih, "RENAMENODE_CB"); + if (cbRenameNode) + { + GtkTreePath* path; + GtkTreeIter iterItem; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL); + gtk_tree_model_get_iter(model, &iterItem, path); + gtk_tree_path_free(path); + cbRenameNode(ih, gtkTreeGetNodeId(ih, iterItem), gtkTreeGetTitle(model, iterItem)); + } + } + + (void)value; + return 0; +} + +static int gtkTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int kind; + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GdkPixbuf* pixExpand = iupImageGetImage(value, ih, 0); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + return 0; + + gtk_tree_model_get(GTK_TREE_MODEL(store), &iterItem, IUPGTK_TREE_KIND, &kind, -1); + + if (kind == ITREE_BRANCH) + { + if (pixExpand) + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE_EXPANDED, pixExpand, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, TRUE, -1); + else + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, FALSE, -1); + } + + return 1; +} + +static int gtkTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GdkPixbuf* pixImage = iupImageGetImage(value, ih, 0); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + return 0; + + if (pixImage) + { + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE, pixImage, + IUPGTK_TREE_HAS_IMAGE, TRUE, -1); + } + else + { + int kind; + gtk_tree_model_get(GTK_TREE_MODEL(store), &iterItem, IUPGTK_TREE_KIND, &kind, -1); + if (kind == ITREE_BRANCH) + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, + IUPGTK_TREE_HAS_IMAGE, FALSE, -1); + else + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf, + IUPGTK_TREE_HAS_IMAGE, FALSE, -1); + } + + return 1; +} + +static int gtkTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value) +{ + GtkTreeIter iterRoot; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + ih->data->def_image_expanded = iupImageGetImage(value, ih, 0); + + gtk_tree_model_get_iter_first(model, &iterRoot); + + /* Update all images, starting at root node */ + gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_EXPANDED); + + return 1; +} + +static int gtkTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value) +{ + GtkTreeIter iterRoot; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + ih->data->def_image_collapsed = iupImageGetImage(value, ih, 0); + + gtk_tree_model_get_iter_first(model, &iterRoot); + + /* Update all images, starting at root node */ + gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_COLLAPSED); + + return 1; +} + +static int gtkTreeSetImageLeafAttrib(Ihandle* ih, const char* value) +{ + GtkTreeIter iterRoot; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + ih->data->def_image_leaf = iupImageGetImage(value, ih, 0); + + gtk_tree_model_get_iter_first(model, &iterRoot); + + /* Update all images, starting at root node */ + gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_LEAF); + + return 1; +} + +static int gtkTreeSetBgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + + GtkScrolledWindow* scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (scrolled_window) + { + /* ignore given value, must use only from parent for the scrollbars */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + if (iupStrToRGB(parent_value, &r, &g, &b)) + { + GtkWidget* sb; + + if (!GTK_IS_SCROLLED_WINDOW(scrolled_window)) + scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUPGTK_SCROLLED_WINDOW"); + + iupgtkBaseSetBgColor((GtkWidget*)scrolled_window, r, g, b); + +#if GTK_CHECK_VERSION(2, 8, 0) + sb = gtk_scrolled_window_get_hscrollbar(scrolled_window); + if (sb) iupgtkBaseSetBgColor(sb, r, g, b); + + sb = gtk_scrolled_window_get_vscrollbar(scrolled_window); + if (sb) iupgtkBaseSetBgColor(sb, r, g, b); +#endif + } + } + + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + { + GtkCellRenderer* renderer_txt = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_TEXT"); + GtkCellRenderer* renderer_img = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_IMG"); + GdkColor color; + iupgdkColorSet(&color, r, g, b); + g_object_set(G_OBJECT(renderer_txt), "cell-background-gdk", &color, NULL); + g_object_set(G_OBJECT(renderer_img), "cell-background-gdk", &color, NULL); + } + + iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */ + + /* no need to update internal image cache in GTK */ + + return 1; +} + +static int gtkTreeSetFgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + iupgtkBaseSetFgColor(ih->handle, r, g, b); + + { + GtkCellRenderer* renderer_txt = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_TEXT"); + GdkColor color; + iupgdkColorSet(&color, r, g, b); + g_object_set(G_OBJECT(renderer_txt), "foreground-gdk", &color, NULL); + g_object_get(G_OBJECT(renderer_txt), "foreground-gdk", &color, NULL); + color.blue = 0; + } + + return 1; +} + +void iupdrvTreeUpdateMarkMode(Ihandle *ih) +{ + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + gtk_tree_selection_set_mode(selection, (ih->data->mark_mode==ITREE_MARK_SINGLE)? GTK_SELECTION_SINGLE: GTK_SELECTION_MULTIPLE); + + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && !ih->data->show_dragdrop) + { +#if GTK_CHECK_VERSION(2, 10, 0) + gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(ih->handle), TRUE); +#endif + } +} + + +/***********************************************************************************************/ + + +static void gtkTreeSetRenameCaretPos(GtkCellEditable *editable, const char* value) +{ + int pos = 1; + + if (iupStrToInt(value, &pos)) + { + if (pos < 1) pos = 1; + pos--; /* IUP starts at 1 */ + + gtk_editable_set_position(GTK_EDITABLE(editable), pos); + } +} + +static void gtkTreeSetRenameSelectionPos(GtkCellEditable *editable, const char* value) +{ + int start = 1, end = 1; + + if (iupStrToIntInt(value, &start, &end, ':') != 2) + return; + + if(start < 1 || end < 1) + return; + + start--; /* IUP starts at 1 */ + end--; + + gtk_editable_select_region(GTK_EDITABLE(editable), start, end); +} + +/*****************************************************************************/ +/* SIGNALS */ +/*****************************************************************************/ + +static void gtkTreeCellTextEditingStarted(GtkCellRenderer *cell, GtkCellEditable *editable, const gchar *path_string, Ihandle *ih) +{ + char* value; + GtkTreeIter iterItem; + PangoFontDescription* fontdesc = NULL; + GdkColor *color = NULL; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + + value = iupAttribGetStr(ih, "RENAMECARET"); + if (value) + gtkTreeSetRenameCaretPos(editable, value); + + value = iupAttribGetStr(ih, "RENAMESELECTION"); + if (value) + gtkTreeSetRenameSelectionPos(editable, value); + + gtk_tree_model_get_iter_from_string(model, &iterItem, path_string); + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_FONT, &fontdesc, -1); + if (fontdesc) + gtk_widget_modify_font(GTK_WIDGET(editable), fontdesc); + + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_COLOR, &color, -1); + if (color) + iupgtkBaseSetFgGdkColor(GTK_WIDGET(editable), color); + + (void)cell; +} + +static void gtkTreeCellTextEdited(GtkCellRendererText *cell, gchar *path_string, gchar *new_text, Ihandle* ih) +{ + GtkTreeModel* model; + GtkTreeIter iterItem; + IFnis cbRename; + + if (!new_text) + return; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + if (!gtk_tree_model_get_iter_from_string(model, &iterItem, path_string)) + return; + + cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB"); + if (cbRename) + { + if (cbRename(ih, gtkTreeGetNodeId(ih, iterItem), iupgtkStrConvertFromUTF8(new_text)) == IUP_IGNORE) + return; + } + + /* It is the responsibility of the application to update the model and store new_text at the position indicated by path. */ + gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_TITLE, new_text, -1); + + (void)cell; +} + +static int gtkTreeCallDragDropCb(Ihandle* ih, GtkTreeIter *iterDrag, GtkTreeIter *iterDrop, int *is_ctrl) +{ + IFniiii cbDragDrop = (IFniiii)IupGetCallback(ih, "DRAGDROP_CB"); + int is_shift = 0; + char key[5]; + iupdrvGetKeyState(key); + if (key[0] == 'S') + is_shift = 1; + if (key[1] == 'C') + *is_ctrl = 1; + else + *is_ctrl = 0; + + if (cbDragDrop) + { + int drag_id = gtkTreeGetNodeId(ih, *iterDrag); + int drop_id = gtkTreeGetNodeId(ih, *iterDrop); + return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl); + } + + return IUP_CONTINUE; /* allow to move by default if callback not defined */ +} + +static void gtkTreeDragDataReceived(GtkWidget *widget, GdkDragContext *context, gint x, gint y, + GtkSelectionData *selection_data, guint info, guint time, Ihandle* ih) +{ + GtkTreePath* pathDrag = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DRAGITEM"); + GtkTreePath* pathDrop = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DROPITEM"); + int accepted = FALSE; + int is_ctrl; + + if (pathDrag && pathDrop) + { + GtkTreeIter iterDrag, iterDrop, iterParent, iterNextParent; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + + gtk_tree_model_get_iter(model, &iterDrag, pathDrag); + gtk_tree_model_get_iter(model, &iterDrop, pathDrop); + + iterParent = iterDrop; + while(gtk_tree_model_iter_parent(model, &iterNextParent, &iterParent)) + { + if (iterNextParent.user_data == iterDrag.user_data) + goto gtkTreeDragDataReceived_FINISH; + iterParent = iterNextParent; + } + + accepted = TRUE; + + if (gtkTreeCallDragDropCb(ih, &iterDrag, &iterDrop, &is_ctrl) == IUP_CONTINUE) + { + GtkTreeIter iterNewItem; + + /* Copy the dragged item to the new position. */ + gtkTreeCopyNode(ih, model, &iterDrag, &iterDrop, &iterNewItem, is_ctrl); + + if (!is_ctrl) + { + /* do not delete the user data, we copy the references in CopyNode */ + gtk_tree_store_remove(GTK_TREE_STORE(model), &iterDrag); + } + + /* set focus and selection */ + { + GtkTreePath *pathNew; + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + + pathNew = gtk_tree_model_get_path(model, &iterNewItem); + gtk_tree_selection_select_path(selection, pathNew); + + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), pathNew, NULL, FALSE, 0, 0); + gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), pathNew, NULL, FALSE); + + gtk_tree_path_free(pathNew); + } + } + } + +gtkTreeDragDataReceived_FINISH: + if (pathDrag) gtk_tree_path_free(pathDrag); + if (pathDrop) gtk_tree_path_free(pathDrop); + + iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", NULL); + iupAttribSetStr(ih, "_IUPTREE_DROPITEM", NULL); + + gtk_drag_finish(context, accepted, (context->action == GDK_ACTION_MOVE), time); + + (void)widget; + (void)info; + (void)x; + (void)y; + (void)selection_data; +} + +static gboolean gtkTreeDragDrop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, Ihandle* ih) +{ + GtkTreePath* path; + GtkTreeViewDropPosition pos; + GdkAtom target = GDK_NONE; + + /* unset any highlight row */ + gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW(widget), NULL, GTK_TREE_VIEW_DROP_BEFORE); + + if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, &pos)) + { + if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER) && + (gtk_tree_path_compare(path, (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DRAGITEM")) != 0)) + { + target = gtk_drag_dest_find_target(widget, context, gtk_drag_dest_get_target_list(widget)); + if (target != GDK_NONE) + { + iupAttribSetStr(ih, "_IUPTREE_DROPITEM", (char*)path); + gtk_drag_get_data(widget, context, target, time); + return TRUE; + } + } + } + + (void)widget; + return FALSE; +} + +static void gtkTreeDragLeave(GtkWidget *widget, GdkDragContext *context, guint time) +{ + /* unset any highlight row */ + gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(widget), NULL, GTK_TREE_VIEW_DROP_BEFORE); + (void)context; + (void)time; +} + +static gboolean gtkTreeDragMotion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, Ihandle* ih) +{ + GtkTreePath* path; + GtkTreeViewDropPosition pos; + GtkTreePath* pathDrag = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DRAGITEM"); + if (pathDrag && gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, &pos)) + { + if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER) && + (gtk_tree_path_compare(path, pathDrag) != 0)) + { + gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(widget), path, pos); + gdk_drag_status(context, context->actions, time); + return TRUE; + } + + gtk_tree_path_free(path); + } + + (void)widget; + return FALSE; +} + +static void gtkTreeDragBegin(GtkWidget *widget, GdkDragContext *context, Ihandle* ih) +{ + int x = iupAttribGetInt(ih, "_IUPTREE_DRAG_X"); + int y = iupAttribGetInt(ih, "_IUPTREE_DRAG_Y"); + GtkTreePath* path; + GtkTreeViewDropPosition pos; + if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, &pos)) + { + if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)) + { + GdkPixmap* pixmap; + iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", (char*)path); + + pixmap = gtk_tree_view_create_row_drag_icon(GTK_TREE_VIEW(ih->handle), path); + gtk_drag_source_set_icon(widget, gtk_widget_get_colormap(widget), pixmap, NULL); + g_object_unref(pixmap); + return; + } + } + + (void)context; + (void)widget; +} + +static void gtkTreeSelectionChanged(GtkTreeSelection* selection, Ihandle* ih) +{ + IFnii cbSelec; + int is_ctrl = 0; + + if (ih->data->mark_mode == ITREE_MARK_MULTIPLE) + { + char key[5]; + iupdrvGetKeyState(key); + if (key[0] == 'S') + return; + else if (key[1] == 'C') + is_ctrl = 1; + + if (iupAttribGetInt(ih, "_IUPTREE_EXTENDSELECT")==2 && !is_ctrl) + { + iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", NULL); + gtkTreeCallMultiSelectionCb(ih); + return; + } + } + + cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); + if (cbSelec) + { + int curpos = -1, is_selected = 0; + + if (iupAttribGet(ih, "_IUP_IGNORE_SELECTION")) + { + iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", NULL); + return; + } + + { + GtkTreeIter iterFocus; + GtkTreePath* pathFocus; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); + if (pathFocus) + { + gtk_tree_model_get_iter(model, &iterFocus, pathFocus); + gtk_tree_path_free(pathFocus); + curpos = gtkTreeGetNodeId(ih, iterFocus); + is_selected = gtk_tree_selection_iter_is_selected(selection, &iterFocus); + } + } + + if (curpos == -1) + return; + + if (is_ctrl) + cbSelec(ih, curpos, is_selected); + else + { + int oldpos = iupAttribGetInt(ih, "_IUPTREE_OLDVALUE"); + if(oldpos != curpos) + { + cbSelec(ih, oldpos, 0); /* unselected */ + cbSelec(ih, curpos, 1); /* selected */ + + iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", curpos); + } + } + } +} + +static gboolean gtkTreeTestExpandRow(GtkTreeView* tree_view, GtkTreeIter *iterItem, GtkTreePath *path, Ihandle* ih) +{ + IFni cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB"); + if (cbBranchOpen) + { + if (iupAttribGet(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB")) + { + iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB", NULL); + return FALSE; + } + + if (cbBranchOpen(ih, gtkTreeGetNodeId(ih, *iterItem)) == IUP_IGNORE) + return TRUE; /* prevent the change */ + } + + (void)path; + (void)tree_view; + return FALSE; +} + +static gboolean gtkTreeTestCollapseRow(GtkTreeView* tree_view, GtkTreeIter *iterItem, GtkTreePath *path, Ihandle* ih) +{ + IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB"); + if (cbBranchClose) + { + if (cbBranchClose(ih, gtkTreeGetNodeId(ih, *iterItem)) == IUP_IGNORE) + return TRUE; + } + + (void)path; + (void)tree_view; + return FALSE; +} + +static void gtkTreeRowActived(GtkTreeView* tree_view, GtkTreePath *path, GtkTreeViewColumn *column, Ihandle* ih) +{ + GtkTreeIter iterItem; + GtkTreeModel* model; + int kind; /* used for nodes defined as branches, but do not have children */ + IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB"); + if (!cbExecuteLeaf) + return; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + gtk_tree_model_get_iter(model, &iterItem, path); + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); + + /* just to leaf nodes */ + if(gtk_tree_model_iter_has_child(model, &iterItem) == 0 && kind == ITREE_LEAF) + cbExecuteLeaf(ih, gtkTreeGetNodeId(ih, iterItem)); + + (void)column; + (void)tree_view; +} + +static int gtkTreeConvertXYToPos(Ihandle* ih, int x, int y) +{ + GtkTreePath* path; + if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, NULL)) + { + GtkTreeIter iterItem; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + gtk_tree_model_get_iter(model, &iterItem, path); + gtk_tree_path_free (path); + return gtkTreeGetNodeId(ih, iterItem); + } + return -1; +} + +static gboolean gtkTreeButtonEvent(GtkWidget *treeview, GdkEventButton *evt, Ihandle* ih) +{ + if (iupgtkButtonEvent(treeview, evt, ih) == TRUE) + return TRUE; + + if (evt->type == GDK_BUTTON_PRESS && evt->button == 3) /* right single click */ + { + IFni cbRightClick = (IFni)IupGetCallback(ih, "RIGHTCLICK_CB"); + if (cbRightClick) + { + int id = gtkTreeConvertXYToPos(ih, (int)evt->x, (int)evt->y); + if (id != -1) + cbRightClick(ih, id); + return TRUE; + } + } + else if (evt->type == GDK_2BUTTON_PRESS && evt->button == 1) /* left double click */ + { + GtkTreePath *path; + + if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), (gint) evt->x, (gint) evt->y, &path, NULL, NULL, NULL)) + { + GtkTreeIter iter; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + int kind; /* used for nodes defined as branches, but do not have children */ + + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get(model, &iter, IUPGTK_TREE_KIND, &kind, -1); + + if (kind == ITREE_BRANCH) + gtkTreeExpandItem(ih, path, -1); /* toggle */ + + gtk_tree_path_free(path); + } + } + else if (evt->type == GDK_BUTTON_RELEASE && evt->button == 1) /* left single release */ + { + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & GDK_SHIFT_MASK)) + gtkTreeCallMultiSelectionCb(ih); /* Multi Selection Callback */ + + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && + !(evt->state & GDK_SHIFT_MASK) && !(evt->state & GDK_CONTROL_MASK)) + { + if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT")) + iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "2"); + } + } + else if (evt->type == GDK_BUTTON_PRESS && evt->button == 1) /* left single press */ + { + iupAttribSetInt(ih, "_IUPTREE_DRAG_X", (int)evt->x); + iupAttribSetInt(ih, "_IUPTREE_DRAG_Y", (int)evt->y); + + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && + !(evt->state & GDK_SHIFT_MASK) && !(evt->state & GDK_CONTROL_MASK)) + iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "1"); + } + + return FALSE; +} + +static gboolean gtkTreeKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) +{ + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & GDK_SHIFT_MASK)) + { + if (evt->keyval == GDK_Up || evt->keyval == GDK_Down || evt->keyval == GDK_Home || evt->keyval == GDK_End) + gtkTreeCallMultiSelectionCb(ih); /* Multi Selection Callback */ + } + + (void)widget; + return TRUE; +} + +static gboolean gtkTreeKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) +{ + if (iupgtkKeyPressEvent(widget, evt, ih) == TRUE) + return TRUE; + + if (evt->keyval == GDK_F2) + { + gtkTreeSetRenameAttrib(ih, NULL); + return TRUE; + } + else if (evt->keyval == GDK_Return || evt->keyval == GDK_KP_Enter) + { + gtkTreeOpenCloseEvent(ih); + return TRUE; + } + + return FALSE; +} + +static void gtkTreeEnableDragDrop(Ihandle* ih) +{ + const GtkTargetEntry row_targets[] = { + { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 } + }; + + if (iupAttribGetBoolean(ih, "AUTODRAGDROP")) + { + gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW(ih->handle), + GDK_BUTTON1_MASK, + row_targets, + G_N_ELEMENTS(row_targets), + GDK_ACTION_MOVE|GDK_ACTION_COPY); + gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW(ih->handle), + row_targets, + G_N_ELEMENTS(row_targets), + GDK_ACTION_MOVE|GDK_ACTION_COPY); + } + else + { + gtk_drag_source_set(ih->handle, GDK_BUTTON1_MASK, row_targets, G_N_ELEMENTS(row_targets), GDK_ACTION_MOVE|GDK_ACTION_COPY); + gtk_drag_dest_set(ih->handle, GDK_BUTTON1_MASK, row_targets, G_N_ELEMENTS(row_targets), GDK_ACTION_MOVE|GDK_ACTION_COPY); + + g_signal_connect(G_OBJECT(ih->handle), "drag-begin", G_CALLBACK(gtkTreeDragBegin), ih); + g_signal_connect(G_OBJECT(ih->handle), "drag-motion", G_CALLBACK(gtkTreeDragMotion), ih); + g_signal_connect(G_OBJECT(ih->handle), "drag-leave", G_CALLBACK(gtkTreeDragLeave), NULL); + g_signal_connect(G_OBJECT(ih->handle), "drag-drop", G_CALLBACK(gtkTreeDragDrop), ih); + g_signal_connect(G_OBJECT(ih->handle), "drag-data-received", G_CALLBACK(gtkTreeDragDataReceived), ih); + } +} + +/*****************************************************************************/ + +static int gtkTreeMapMethod(Ihandle* ih) +{ + GtkScrolledWindow* scrolled_window = NULL; + GtkTreeStore *store; + GtkCellRenderer *renderer_img, *renderer_txt; + GtkTreeSelection* selection; + GtkTreeViewColumn *column; + + store = gtk_tree_store_new(9, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN, + G_TYPE_STRING, G_TYPE_INT, GDK_TYPE_COLOR, PANGO_TYPE_FONT_DESCRIPTION, G_TYPE_POINTER); + + ih->handle = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + + g_object_unref(store); + + if (!ih->handle) + return IUP_ERROR; + + scrolled_window = (GtkScrolledWindow*)gtk_scrolled_window_new(NULL, NULL); + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)scrolled_window); + + /* Column and renderers */ + column = gtk_tree_view_column_new(); + iupAttribSetStr(ih, "_IUPGTK_COLUMN", (char*)column); + + renderer_img = gtk_cell_renderer_pixbuf_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(column), renderer_img, FALSE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(column), renderer_img, "pixbuf", IUPGTK_TREE_IMAGE, + "pixbuf-expander-open", IUPGTK_TREE_IMAGE_EXPANDED, + "pixbuf-expander-closed", IUPGTK_TREE_IMAGE, + NULL); + iupAttribSetStr(ih, "_IUPGTK_RENDERER_IMG", (char*)renderer_img); + + renderer_txt = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(column), renderer_txt, TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(column), renderer_txt, "text", IUPGTK_TREE_TITLE, + "is-expander", IUPGTK_TREE_KIND, + "font-desc", IUPGTK_TREE_FONT, + "foreground-gdk", IUPGTK_TREE_COLOR, + NULL); + iupAttribSetStr(ih, "_IUPGTK_RENDERER_TEXT", (char*)renderer_txt); + + if (ih->data->show_rename) + g_object_set(G_OBJECT(renderer_txt), "editable", TRUE, NULL); + + g_object_set(G_OBJECT(renderer_txt), "xpad", 0, NULL); + g_object_set(G_OBJECT(renderer_txt), "ypad", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(ih->handle), column); + + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(ih->handle), FALSE); + gtk_tree_view_set_enable_search(GTK_TREE_VIEW(ih->handle), FALSE); + +#if GTK_CHECK_VERSION(2, 10, 0) + if (iupAttribGetBoolean(ih, "HIDELINES")) + gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(ih->handle), FALSE); + else + gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(ih->handle), TRUE); +#endif + +#if GTK_CHECK_VERSION(2, 12, 0) + if (iupAttribGetBoolean(ih, "HIDEBUTTONS")) + gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(ih->handle), FALSE); + else + gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(ih->handle), TRUE); +#endif + + if (ih->data->show_dragdrop) + gtkTreeEnableDragDrop(ih); + + gtk_container_add((GtkContainer*)scrolled_window, ih->handle); + gtk_widget_show((GtkWidget*)scrolled_window); + gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_IN); + + gtk_scrolled_window_set_policy(scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + + gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); + gtk_tree_view_set_reorderable(GTK_TREE_VIEW(ih->handle), FALSE); + + /* callbacks */ + g_signal_connect(selection, "changed", G_CALLBACK(gtkTreeSelectionChanged), ih); + + g_signal_connect(renderer_txt, "editing-started", G_CALLBACK(gtkTreeCellTextEditingStarted), ih); + g_signal_connect(renderer_txt, "edited", G_CALLBACK(gtkTreeCellTextEdited), ih); + + g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih); + + g_signal_connect(G_OBJECT(ih->handle), "test-expand-row", G_CALLBACK(gtkTreeTestExpandRow), ih); + g_signal_connect(G_OBJECT(ih->handle), "test-collapse-row", G_CALLBACK(gtkTreeTestCollapseRow), ih); + g_signal_connect(G_OBJECT(ih->handle), "row-activated", G_CALLBACK(gtkTreeRowActived), ih); + g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkTreeKeyPressEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "key-release-event", G_CALLBACK(gtkTreeKeyReleaseEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkTreeButtonEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkTreeButtonEvent), ih); + + /* add to the parent, all GTK controls must call this. */ + iupgtkBaseAddToParent(ih); + + if (!iupAttribGetBoolean(ih, "CANFOCUS")) + GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS; + + gtk_widget_realize((GtkWidget*)scrolled_window); + gtk_widget_realize(ih->handle); + + /* Initialize the default images */ + ih->data->def_image_leaf = iupImageGetImage("IMGLEAF", ih, 0); + ih->data->def_image_collapsed = iupImageGetImage("IMGCOLLAPSED", ih, 0); + ih->data->def_image_expanded = iupImageGetImage("IMGEXPANDED", ih, 0); + + gtkTreeAddRootNode(ih); + + /* configure for DRAG&DROP of files */ + if (IupGetCallback(ih, "DROPFILES_CB")) + iupAttribSetStr(ih, "DRAGDROP", "YES"); + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)gtkTreeConvertXYToPos); + + return IUP_NOERROR; +} + +void iupdrvTreeInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkTreeMapMethod; + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkTreeSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkTreeSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT); + + /* IupTree Attributes - GENERAL */ + iupClassRegisterAttribute(ic, "EXPANDALL", NULL, gtkTreeSetExpandAllAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INDENTATION", gtkTreeGetIndentationAttrib, gtkTreeSetIndentationAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "COUNT", gtkTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPACING", iupTreeGetSpacingAttrib, gtkTreeSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "TOPITEM", NULL, gtkTreeSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + + /* IupTree Attributes - IMAGES */ + iupClassRegisterAttributeId(ic, "IMAGE", NULL, gtkTreeSetImageAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "IMAGEEXPANDED", NULL, gtkTreeSetImageExpandedAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "IMAGELEAF", NULL, gtkTreeSetImageLeafAttrib, IUPAF_SAMEASSYSTEM, "IMGLEAF", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEBRANCHCOLLAPSED", NULL, gtkTreeSetImageBranchCollapsedAttrib, IUPAF_SAMEASSYSTEM, "IMGCOLLAPSED", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEBRANCHEXPANDED", NULL, gtkTreeSetImageBranchExpandedAttrib, IUPAF_SAMEASSYSTEM, "IMGEXPANDED", IUPAF_NO_INHERIT); + + /* IupTree Attributes - NODES */ + iupClassRegisterAttributeId(ic, "STATE", gtkTreeGetStateAttrib, gtkTreeSetStateAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "DEPTH", gtkTreeGetDepthAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "KIND", gtkTreeGetKindAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "PARENT", gtkTreeGetParentAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "COLOR", gtkTreeGetColorAttrib, gtkTreeSetColorAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "NAME", gtkTreeGetTitleAttrib, gtkTreeSetTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLE", gtkTreeGetTitleAttrib, gtkTreeSetTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "USERDATA", gtkTreeGetUserDataAttrib, gtkTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT); + + iupClassRegisterAttributeId(ic, "CHILDCOUNT", gtkTreeGetChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLEFONT", gtkTreeGetTitleFontAttrib, gtkTreeSetTitleFontAttrib, IUPAF_NO_INHERIT); + + /* IupTree Attributes - MARKS */ + iupClassRegisterAttributeId(ic, "MARKED", gtkTreeGetMarkedAttrib, gtkTreeSetMarkedAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARK", NULL, gtkTreeSetMarkAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "STARTING", NULL, gtkTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARKSTART", NULL, gtkTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute (ic, "VALUE", gtkTreeGetValueAttrib, gtkTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupTree Attributes - ACTION */ + iupClassRegisterAttributeId(ic, "DELNODE", NULL, gtkTreeSetDelNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RENAME", NULL, gtkTreeSetRenameAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "MOVENODE", NULL, gtkTreeSetMoveNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "COPYNODE", NULL, gtkTreeSetCopyNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "FINDUSERDATA", gtkTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute (ic, "AUTODRAGDROP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT); +} -- cgit v1.2.3