Re: tooltip with drag and drop between two treeviews



in gtk2 (at least) it isn't well designed for that.

it is possible to do, but it is complex to explain. i regret that i don't have time to do so....


On Tue, Sep 24, 2013 at 4:30 PM, Ubirajara Marques da Cruz <biracruz cemig com br> wrote:

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




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]