To gtk team,
I need to know if it´s possible to create a tooltip while i am dragging some itens of one treeview to another treeview.
I was studing with a Vikram Ambrose example find into
http://en.wikibooks.org/wiki/GTK%2B_By_Example/Tree_View/DnD
into item Dragging Rows from One Tree to Another
I did some changes into program to study treestore. Vikram Ambrose example uses liststore. The problem ocurrs when i dragging some item of one treeview and drop in another place inside the other treeview or inside itself because i have four position to insert
1)Insert before item pointed;
2)Insert after item pointed;
3)Insert into item pointed like a child in the 1st place;
4)Insert into item pointed like a child in the last place;
When the application has Drag and drop struture into high level an automatic feedback signal that print a trace into cell to tell what position this item is inserted is create but into this example I wanna make this feedback with tooltip that is more directly.
I wanna know what signal i must use to do this. In my study i have “tooltip-query” (works without drag and drop) , drag-data-get , drag-data-received and drag-motion.
Thanks in advance
Follow the code.
#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DESCRIPTION "Drag and Drop Between 2 Treeviews - by Vikram Ambrose"
/* Row data structure */
struct DATA {
char *row;
char *item;
int qty;
float price;
};
/* A convenience enumerator to tag data types */
enum {
TARGET_STRING,
TARGET_INTEGER,
TARGET_FLOAT
};
/* A convenience enumerator to count the columns */
enum {
ROW_COL=0,
ITEM_COL,
QTY_COL,
PRICE_COL,
NUM_COLS
};
/* Some sample data for treeview 1. A NULL row is added so we dont
need to pass around the size of the array */
static struct DATA row_data[] = {
{ "row0","item 12", 3, 4.3 },
{ "row1","item 23", 44,34.4},
{ "row2","item 33", 34,25.4},
{ "row3","item 43", 37,64.4},
{ "row4","item 53", 12,14.4},
{ "row5","item 68", 42,34.4},
{ "row6","item 75", 72,74.4},
{NULL}
};
/* Sample data for treeview 2 */
static struct DATA row2_data[] = {
{"row7", "item 127", 105, 115.5},
{"row8","item 124", 117, 118.6},
{"row9", "item 123", 120, 121.73},
{NULL}
};
static const GtkTargetEntry drag_targets = {
"STRING", GTK_TARGET_SAME_APP,TARGET_STRING
};
static guint n_targets = 1;
/* Could be used instead, if GtkTargetEntry had more than one row */
//static guint n_targets = G_N_ELEMENTS (drag_targets);
/* Convenience function to deallocated memory used for DATA struct */
void free_DATA(struct DATA *data){
if(data){
free(data->row);
free(data->item);
}
free(data);
}
/* Convenience function to print out the contents of a DATA struct onto stdout */
void print_DATA(struct DATA *data){
printf("DATA @ %p\n",data);
printf(" |->row = %s\n",data->row);
printf(" |->item = %s\n",data->item);
printf(" |->qty = %i\n",data->qty);
printf(" +->price = %f\n",data->price);
}
/* User callback for "get"ing the data out of the row that was DnD'd */
void on_drag_data_get( GtkWidget *widget, GdkDragContext *drag_context,
GtkSelectionData *sdata, guint info, guint time,
gpointer user_data){
GtkTreeIter iter;
GtkTreeModel *tree_store;
GtkTreeSelection *selector;
gboolean rv;
printf("on_drag_data_get: ");
/* Get the selector widget from the treeview in question */
selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
/* Get the tree model (list_store) and initialise the iterator */
rv = gtk_tree_selection_get_selected(selector,&tree_store,&iter);
/* This shouldn't really happen, but just in case */
if(rv==FALSE){
printf(" No row selected\n");
return;
}
/* Always initialise a GValue with 0 */
GValue value={0,};
char *cptr;
/* Allocate a new row to send off to the other side */
struct DATA *temp = malloc(sizeof(struct DATA));
/* Go through the columns */
/* Get the GValue of a particular column from the row, the iterator currently points to*/
gtk_tree_model_get_value(tree_store,&iter,ROW_COL,&value);
cptr = (char*) g_value_get_string(&value);
temp->row = malloc(strlen(cptr)*sizeof(char)+1);
strcpy(temp->row,cptr);
g_value_unset(&value);
gtk_tree_model_get_value(tree_store,&iter,ITEM_COL,&value);
cptr = (char*)g_value_get_string(&value);
temp->item = malloc(strlen(cptr)*sizeof(char)+1);
strcpy(temp->item,cptr);
g_value_unset(&value);
gtk_tree_model_get_value(tree_store,&iter,QTY_COL,&value);
temp->qty = g_value_get_int(&value);
g_value_unset(&value);
gtk_tree_model_get_value(tree_store,&iter,PRICE_COL,&value);
temp->price = g_value_get_float(&value);
g_value_unset(&value);
/* Send the data off into the GtkSelectionData object */
gtk_selection_data_set(sdata,
gdk_atom_intern ("struct DATA pointer", FALSE),
8, /* Tell GTK how to pack the data (bytes) */
(void *)&temp, /* The actual pointer that we just made */
sizeof (temp)); /* The size of the pointer */
/* Just print out what we sent for debugging purposes */
print_DATA(temp);
}
/* User callback for putting the data into the other treeview */
GdkModifierType mask;
void on_drag_data_received(GtkWidget *widget, GdkDragContext *drag_context,
gint x, gint y, GtkSelectionData *sdata, guint info,
guint time, gpointer user_data){
GtkTreeModel *tree_store;
GtkTreeIter iter;
printf("on_drag_data_received:\n");
/* Remove row from the source treeview */
GtkTreeSelection *selector;
selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(user_data));
gtk_tree_selection_get_selected(selector,&tree_store,&iter);
gdk_window_get_pointer(drag_context->dest_window,NULL,NULL,&mask);
gdk_drag_status(drag_context,GDK_ACTION_ASK,time);
if(mask & GDK_CONTROL_MASK) // & compara binarios "bitwise-and" operator
{gdk_drag_status(drag_context,GDK_ACTION_COPY,time);}
if(mask & GDK_SHIFT_MASK)
{
gdk_drag_status(drag_context,GDK_ACTION_MOVE,time);
gtk_tree_store_remove(GTK_TREE_STORE(tree_store),&iter);
}
if(mask & GDK_MOD1_MASK)
{gdk_drag_status(drag_context,GDK_ACTION_LINK,time);}
if(mask & GDK_LOCK_MASK)
{gdk_drag_status(drag_context,GDK_ACTION_ASK,time);}
/* Now add to the other treeview */
GtkTreeModel *tree_store2;
GtkTreeIter iter2,iter2pai;
GtkTreePath *path;
GtkTreeViewDropPosition pos;
tree_store2 = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
//if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),x,y,&path,NULL,NULL,NULL)==1)
if(gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget),x,y,&path,&pos)==1)
{
gtk_tree_model_get_iter(GTK_TREE_MODEL(tree_store2),&iter2,path);
gtk_tree_model_iter_parent(GTK_TREE_MODEL(tree_store2),&iter2pai,&iter2);
switch (pos){
case 0: //Insere nó antes da linha apontada
{gtk_tree_store_insert_before(GTK_TREE_STORE(tree_store2),&iter2,&iter2pai,&iter2);
break;}
case 1: //Insere nó depois da linha apontada
{gtk_tree_store_insert_after(GTK_TREE_STORE(tree_store2),&iter2,&iter2pai,&iter2);
break;}
case 2: //Insere nó dentro da linha apontada passando a ser o primeiro item
{gtk_tree_store_prepend(GTK_TREE_STORE(tree_store2),&iter2,&iter2);
break;}
case 3: //Insere nó dentro da linha apontada passando a ser o ultimo item
{gtk_tree_store_append(GTK_TREE_STORE(tree_store2),&iter2,&iter2);
break;}
}
/*printf("A posição de inserção é %i\n",pos);
gtk_tree_model_get_iter(GTK_TREE_MODEL(tree_store2),&iter2pai,path);
printf("O path do destino é: %s\n",gtk_tree_model_get_string_from_iter(GTK_TREE_MODEL(tree_store2),&iter2pai));
gtk_tree_store_append(GTK_TREE_STORE(tree_store2),&iter2,&iter2pai);*/
}
else
{
printf("Deu erro ao achar o path valido\n");
}
gtk_tree_path_free(path);
/* Copy the pointer we received into a new struct */
struct DATA *temp = NULL;
memcpy (&temp, sdata->data, sizeof (temp));
/* Add the received data to the treeview model */
gtk_tree_store_set(GTK_TREE_STORE(tree_store2),&iter2,
ROW_COL,temp->row,
ITEM_COL,temp->item,
QTY_COL,temp->qty,
PRICE_COL,temp->price,-1);
/* We dont need this anymore */
free_DATA(temp);
}
/* User callback to see tooltip to see what kind of insert operation will be done int destiny dropo*/
gboolean tree_tool_tip(GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_mode,
GtkTooltip *tooltip,
gpointer user_data)
{
keyboard_mode=0;
if(TRUE)//(GDK_DRAG_STATUS==25)
{
printf("estamos em DND\n");
GtkTreePath *path;
GtkTreeIter iter;
GtkTreeViewDropPosition pos;
GtkTreeModel *tree_model;
gchar *s;
tree_model=gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
if(gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget),x,y,&path,&pos)==1)
{
gtk_tree_model_get_iter(GTK_TREE_MODEL(tree_model),&iter,path);
s=gtk_tree_model_get_string_from_iter(GTK_TREE_MODEL(tree_model),&iter);
printf("Foi encontrado um path válido");
switch (pos)
{
case 0:
{gtk_tooltip_set_text(tooltip,"Inserir antes deste item!");
printf("path %s O valor é %i significa GTK_TREE_VIEW_DROP_BEFORE\n",s,pos);
}
break;
case 1:
{gtk_tooltip_set_text(tooltip,"Inserir depois deste item!");
printf("path %s O valor é %i significa GTK_TREE_VIEW_DROP_AFTER\n",s,pos);
}
break;
case 2:
{gtk_tooltip_set_text(tooltip,"Inserir dentro deste item na 1a. posicao!");
printf("path %s O valor é %i significa GTK_TREE_VIEW_DROP_INTO_OR_BEFORE\n",s,pos);
}
break;
case 3:
{gtk_tooltip_set_text(tooltip,"Inserir dentro deste item na ultima posicao!");
printf("path %s O valor é %i significa GTK_TREE_VIEW_DROP_INTO_OR_AFTER\n",s,pos);
}
break;
}
return(1);
}
else
{
printf("Não foi encontrado um path válido na função tooltip\n");
return(0);
}
}
else
return(0);
};
/* User callback for see what kind of insert operation will be done into destiny drop
*/
gboolean on_drag_move (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
guint time,
gpointer user_data)
{
GtkTreePath *path;
GtkTreeIter iter;
GtkTreeViewDropPosition pos;
GtkTreeModel *tree_model;
gchar *s;
tree_model=gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
gtk_widget_trigger_tooltip_query(widget);
if(gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget),x,y,&path,&pos)==1)
{
gtk_tree_model_get_iter(GTK_TREE_MODEL(tree_model),&iter,path);
s=gtk_tree_model_get_string_from_iter(GTK_TREE_MODEL(tree_model),&iter);
switch (pos)
{
case 0:
{
//printf("path %s O valor é %i significa GTK_TREE_VIEW_DROP_BEFORE\n",s,pos);
}
break;
case 1:
{
//printf("path %s O valor é %i significa GTK_TREE_VIEW_DROP_AFTER\n",s,pos);
}
break;
case 2:
{
//printf("path %s O valor é %i significa GTK_TREE_VIEW_DROP_INTO_OR_BEFORE\n",s,pos);
}
break;
case 3:
{
//printf("path %s O valor é %i significa GTK_TREE_VIEW_DROP_INTO_OR_AFTER\n",s,pos);
}
break;
}
}
else
printf("F_on_drag_move_Não foi encontrado um path válido\n");
return(0);
}
/* User callback just to see which row was selected, doesnt affect DnD.
However it might be important to note that this signal and drag-data-received may occur at the same time. If you drag a row out of one view, your selection changes too */
void on_selection_changed (GtkTreeSelection *treeselection,gpointer user_data){
GtkTreeIter iter;
GtkTreeModel *tree_store;
gboolean rv;
printf("on_selection_changed: ");
rv = gtk_tree_selection_get_selected(treeselection,
&tree_store,&iter);
/* "changed" signal sometimes fires blanks, so make sure we actually
have a selection/
http://library.gnome.org/devel/gtk/stable/GtkTreeSelection.html#GtkTreeSelection-changed */
if (rv==FALSE){
printf("No row selected\n");
return;
}
GValue value={0,};
char *cptr;
int i;
/* Walk throw the columns to see the row data */
for(i=0;i<NUM_COLS;i++){
gtk_tree_model_get_value(tree_store,&iter,i,&value);
cptr = (gchar *) g_strdup_value_contents (&value);
g_value_unset(&value);
if(cptr)printf("%s|",cptr);
free(cptr);
}
printf("\n");
}
/* Creates a scroll windows, puts a treeview in it and populates it */
GtkWidget *add_treeview(GtkWidget *box, struct DATA array[]){
GtkWidget *swindow;
swindow = gtk_scrolled_window_new(NULL,NULL);
/* Both Vertical and Horizontal scroll set to Auto (NULL) */
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow),
GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
/* Add this window to the box */
gtk_box_pack_start(GTK_BOX(box),swindow,TRUE,TRUE,2);
/* Create the treeview and its list store */
//GtkListStore *list_store;
GtkTreeStore *tree_store;
tree_store = gtk_tree_store_new(NUM_COLS,
G_TYPE_STRING,G_TYPE_STRING,G_TYPE_INT,G_TYPE_FLOAT);
GtkWidget *tree_view;
tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(/*list*/tree_store));
/* Add the treeview to the scrolled window */
gtk_container_add(GTK_CONTAINER(swindow),tree_view);
/* Add the columns */
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
char column_names[NUM_COLS][16] = {
"Row #", "Description", "Qty", "Price"};
int i;
for(i=0;i<4;i++){
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes (
column_names[i],renderer,"text",i,NULL);
gtk_tree_view_column_set_sort_column_id (column, i);
gtk_tree_view_append_column (GTK_TREE_VIEW(tree_view), column);
}
/* Tell the theme engine we would like differentiated row colour */
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree_view),TRUE);
/* Add the data */
GtkTreeIter iter;
i=0;
do
{
if(i==0)
gtk_tree_store_append(/*list*/tree_store,&iter,NULL);
else
gtk_tree_store_append(/*list*/tree_store,&iter,&iter);
gtk_tree_store_set(tree_store,&iter,
ROW_COL,array[i].row,
ITEM_COL,array[i].item,
QTY_COL,array[i].qty,
PRICE_COL,array[i].price,-1);
i+=1;
if (array[i].row==NULL)
break;
}while(1/*array[++i].row!=NULL*/);
/* Attach the "changed" callback onto the tree's selector */
g_signal_connect(
gtk_tree_view_get_selection (GTK_TREE_VIEW(tree_view)),
"changed",G_CALLBACK(on_selection_changed),NULL);
return tree_view;
}
int main(int argc, char **argv){
GtkWidget *window;
gtk_init(&argc,&argv);
/* Create the top level window and setup the quit callback */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window),666,266);
g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(gtk_exit),NULL);
/* Build up the GUI with some boxes */
GtkWidget *vbox = gtk_vbox_new(FALSE,10);
gtk_container_add(GTK_CONTAINER(window),vbox);
/* Add a title */
GtkWidget *title = gtk_label_new(DESCRIPTION);
gtk_box_pack_start(GTK_BOX(vbox),title,FALSE,FALSE,1);
GtkWidget *hbox = gtk_hbox_new(TRUE,1);
gtk_box_pack_start(GTK_BOX(vbox),hbox,TRUE,TRUE,1);
/* Create treeview 1 */
GtkWidget *view1;
view1 = add_treeview(hbox,row_data);
/* Create treeview 2 */
GtkWidget *view2;
view2 = add_treeview(hbox,row2_data);
gtk_widget_set(GTK_WIDGET(view1),"reorderable",1,
"enable-tree-lines",1,
"enable-grid-lines",3,
"rubber-banding",1,
"has-tooltip",1,
"hover-selection",1,
//"hover-expand",1,//funciona somente numa ação de movimentação sem estar em DND
NULL);
gtk_widget_set(GTK_WIDGET(view2),"reorderable",1,
"enable-tree-lines",1,
"enable-grid-lines",3,
"rubber-banding",1,
"has-tooltip",1,
"hover-selection",1,
//"hover-expand",1,//funciona somente numa ação de movimentação sem estar em DND
NULL);
/* Set treeview 1 as the source of the Drag-N-Drop operation */
gtk_drag_source_set(view1,GDK_BUTTON1_MASK, &drag_targets,n_targets,
GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_ASK);
gtk_drag_source_set(view2,GDK_BUTTON1_MASK, &drag_targets,n_targets,
GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_ASK);
/* Attach a "drag-data-get" signal to send out the dragged data */
g_signal_connect(view1,"drag-data-get",
G_CALLBACK(on_drag_data_get),NULL);
g_signal_connect(view2,"drag-data-get",
G_CALLBACK(on_drag_data_get),NULL);
g_signal_connect(view1,"drag-motion",G_CALLBACK(on_drag_move),view1);
g_signal_connect(view2,"drag-motion",G_CALLBACK(on_drag_move),view2);
g_signal_connect(view2,"drag-motion",G_CALLBACK(on_drag_move),view1);
g_signal_connect(view1,"drag-motion",G_CALLBACK(on_drag_move),view2);
g_signal_connect(view1,"query-tooltip",G_CALLBACK(tree_tool_tip),NULL);
g_signal_connect(view2,"query-tooltip",G_CALLBACK(tree_tool_tip),NULL);
/* Set treeview 2 as the destination of the Drag-N-Drop operation */
gtk_drag_dest_set(view1,GTK_DEST_DEFAULT_ALL,&drag_targets,n_targets,
GDK_ACTION_ASK|GDK_ACTION_COPY|GDK_ACTION_MOVE);
gtk_drag_dest_set(view2,GTK_DEST_DEFAULT_ALL,&drag_targets,n_targets,
GDK_ACTION_ASK|GDK_ACTION_COPY|GDK_ACTION_MOVE);
/* Attach a "drag-data-received" signal to pull in the dragged data */
g_signal_connect(view2,"drag-data-received",G_CALLBACK(on_drag_data_received),view1);
g_signal_connect(view1,"drag-data-received",G_CALLBACK(on_drag_data_received),view2);
/*g_signal_connect(view1,"drag-data-received",
G_CALLBACK(on_drag_data_received),view1);*/
/* Rock'n Roll */
gtk_widget_show_all(window);
gtk_main();
return 0;
}
Ubirajara Cruz
_______________________________________________
gtk-list mailing list
gtk-list gnome org
https://mail.gnome.org/mailman/listinfo/gtk-list