diff --git a/gui_canvas.c b/gui_canvas.c index 8d7f0f5..76dab6f 100644 --- a/gui_canvas.c +++ b/gui_canvas.c @@ -24,6 +24,7 @@ #include "gui_status.h" #include "gui_tool.h" #include "gui.h" +#include "gui_frame_drag.h" #include "gui_canvas.h" @@ -182,7 +183,7 @@ static gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event, if (event->state & GDK_BUTTON2_MASK) drag_middle(pos); update_pos(pos); - return TRUE; + return FALSE; } @@ -541,6 +542,8 @@ GtkWidget *make_canvas(void) gtk_widget_set_double_buffered(canvas, FALSE); + setup_canvas_drag(canvas); + draw_ctx.widget = canvas; return canvas; diff --git a/gui_frame.c b/gui_frame.c index 6467346..bd6943e 100644 --- a/gui_frame.c +++ b/gui_frame.c @@ -886,30 +886,59 @@ static void set_row_values(void *user, const struct value *values, } -static gboolean table_var_select_event(GtkWidget *widget, +static gboolean table_var_press_event(GtkWidget *widget, + GdkEventButton *event, gpointer data) +{ + struct var *var = data; + + switch (event->button) { + case 3: + pop_up_table_var(var, event); + return TRUE; + } + return FALSE; +} + + +static gboolean table_var_release_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { struct var *var = data; switch (event->button) { case 1: + if (is_dragging(var)) + return FALSE; edit_var(var, set_col_values, var, -1); - return FALSE; - case 3: - pop_up_table_var(var, event); - break; + return TRUE; } - return TRUE; + return FALSE; } -static gboolean table_value_select_event(GtkWidget *widget, +static gboolean table_value_press_event(GtkWidget *widget, + GdkEventButton *event, gpointer data) +{ + struct value *value = data; + + switch (event->button) { + case 3: + pop_up_table_value(value, event); + return TRUE; + } + return FALSE; +} + + +static gboolean table_value_release_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { struct value *value = data; switch (event->button) { case 1: + if (is_dragging(value)) + return FALSE; if (!value->row || value->row->table->active_row == value->row) { edit_nothing(); @@ -919,12 +948,9 @@ static gboolean table_value_select_event(GtkWidget *widget, select_row(value->row); change_world(); } - return FALSE; - case 3: - pop_up_table_value(value, event); - break; + return TRUE; } - return TRUE; + return FALSE; } @@ -1009,7 +1035,10 @@ static void build_table(GtkWidget *vbox, struct frame *frame, label_in_box_bg(field, COLOR_VAR_PASSIVE); g_signal_connect(G_OBJECT(box_of_label(field)), "button_press_event", - G_CALLBACK(table_var_select_event), var); + G_CALLBACK(table_var_press_event), var); + g_signal_connect(G_OBJECT(box_of_label(field)), + "button_release_event", + G_CALLBACK(table_var_release_event), var); g_signal_connect(G_OBJECT(box_of_label(field)), "scroll_event", G_CALLBACK(table_scroll_event), table); @@ -1034,7 +1063,10 @@ static void build_table(GtkWidget *vbox, struct frame *frame, COLOR_ROW_SELECTED : COLOR_ROW_UNSELECTED); g_signal_connect(G_OBJECT(box_of_label(field)), "button_press_event", - G_CALLBACK(table_value_select_event), value); + G_CALLBACK(table_value_press_event), value); + g_signal_connect(G_OBJECT(box_of_label(field)), + "button_release_event", + G_CALLBACK(table_value_release_event), value); g_signal_connect(G_OBJECT(box_of_label(field)), "scroll_event", G_CALLBACK(table_scroll_event), table); @@ -1653,13 +1685,29 @@ void select_frame(struct frame *frame) } -static gboolean frame_select_event(GtkWidget *widget, GdkEventButton *event, +static gboolean frame_press_event(GtkWidget *widget, GdkEventButton *event, + gpointer data) +{ + struct frame *frame = data; + + switch (event->button) { + case 3: + pop_up_frame(frame, event); + return TRUE; + } + return FALSE; +} + + +static gboolean frame_release_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { struct frame *frame = data; switch (event->button) { case 1: + if (is_dragging(frame)) + return FALSE; if (active_frame != frame) select_frame(frame); else { @@ -1668,12 +1716,9 @@ static gboolean frame_select_event(GtkWidget *widget, GdkEventButton *event, edit_frame(frame); } } - break; - case 3: - pop_up_frame(frame, event); - break; + return TRUE; } - return TRUE; + return FALSE; } @@ -1691,9 +1736,13 @@ static GtkWidget *build_frame_label(struct frame *frame) COLOR_FRAME_SELECTED : COLOR_FRAME_UNSELECTED); g_signal_connect(G_OBJECT(box_of_label(label)), - "button_press_event", G_CALLBACK(frame_select_event), frame); + "button_press_event", G_CALLBACK(frame_press_event), frame); + g_signal_connect(G_OBJECT(box_of_label(label)), + "button_release_event", G_CALLBACK(frame_release_event), frame); frame->label = label; + setup_frame_drag(frame); + return box_of_label(label); } diff --git a/gui_frame_drag.c b/gui_frame_drag.c index b8db128..b98a8ff 100644 --- a/gui_frame_drag.c +++ b/gui_frame_drag.c @@ -18,12 +18,49 @@ #include "gui_frame_drag.h" +enum { + target_id_var, + target_id_value, + target_id_frame, + target_id_canvas, +}; + + +static GtkTargetEntry target_var = { + .target = "var", + .flags = GTK_TARGET_SAME_APP, + .info = target_id_var, +}; + +static GtkTargetEntry target_value = { + .target = "value", + .flags = GTK_TARGET_SAME_APP, + .info = target_id_value, +}; + +static GtkTargetEntry target_frame = { + .target = "frame", + .flags = GTK_TARGET_SAME_APP, + .info = target_id_frame, +}; + + +/* ----- dragging status --------------------------------------------------- */ + + /* - * Pointer to whatever it is we're dragging. Undefined if not dragging. + * Pointer to whatever it is we're dragging. NULL if not dragging. */ + static void *dragging; +int is_dragging(void *this) +{ + return this == dragging; +} + + /* ----- helper functions for indexed list and swapping -------------------- */ @@ -148,7 +185,27 @@ static void swap_rows(struct row **a, struct row **b) } -/* ----- common callback --------------------------------------------------- */ +/* ----- common functions -------------------------------------------------- */ + + +/* + * according to + * http://www.pubbs.net/201004/gtk/22819-re-drag-and-drop-drag-motion-cursor-lockup-fixed-.html + * http://www.cryingwolf.org/articles/gtk-dnd.html + */ + +static int has_target(GtkWidget *widget, GdkDragContext *drag_context, + const char *name) +{ + GdkAtom target; + + target = gtk_drag_dest_find_target(widget, drag_context, NULL); + + /* + * Force allocation so that we don't have to check for GDK_NONE. + */ + return target == gdk_atom_intern(name, FALSE); +} static void drag_begin(GtkWidget *widget, @@ -163,11 +220,28 @@ static void drag_begin(GtkWidget *widget, pixbuf = gdk_pixbuf_get_from_drawable(NULL, DA, NULL, 0, 0, 0, 0, 1, 1); gtk_drag_source_set_icon_pixbuf(widget, pixbuf); + g_object_unref(pixbuf); dragging = user_data; } +static void drag_end(GtkWidget *widget, GdkDragContext *drag_context, + gpointer user_data) +{ + dragging = NULL; +} + + +static void setup_drag_common(GtkWidget *widget, void *user_arg) +{ + g_signal_connect(G_OBJECT(widget), "drag-begin", + G_CALLBACK(drag_begin), user_arg); + g_signal_connect(G_OBJECT(widget), "drag-end", + G_CALLBACK(drag_end), user_arg); +} + + /* ----- drag variables ---------------------------------------------------- */ @@ -179,6 +253,8 @@ static gboolean drag_var_motion(GtkWidget *widget, struct var *to = user_data; int from_n, to_n, i; + if (!has_target(widget, drag_context, "var")) + return FALSE; if (from == to || from->table != to->table) return FALSE; from_n = NDX(from->table->vars, from); @@ -192,19 +268,14 @@ static gboolean drag_var_motion(GtkWidget *widget, void setup_var_drag(struct var *var) { - static GtkTargetEntry target = { - .target = "var", - .flags = GTK_TARGET_SAME_APP, - }; GtkWidget *box; box = box_of_label(var->widget); gtk_drag_source_set(box, GDK_BUTTON1_MASK, - &target, 1, GDK_ACTION_PRIVATE); + &target_var, 1, GDK_ACTION_PRIVATE); gtk_drag_dest_set(box, GTK_DEST_DEFAULT_HIGHLIGHT, - &target, 1, GDK_ACTION_PRIVATE); - g_signal_connect(G_OBJECT(box), "drag-begin", - G_CALLBACK(drag_begin), var); + &target_var, 1, GDK_ACTION_PRIVATE); + setup_drag_common(box, var); g_signal_connect(G_OBJECT(box), "drag-motion", G_CALLBACK(drag_var_motion), var); } @@ -219,10 +290,13 @@ static gboolean drag_value_motion(GtkWidget *widget, { struct value *from = dragging; struct value *to = user_data; - struct table *table = from->row->table; + struct table *table; struct row **row, *end; int from_n, to_n, i; + if (!has_target(widget, drag_context, "value")) + return FALSE; + table = from->row->table; if (table != to->row->table) return FALSE; @@ -263,19 +337,65 @@ static gboolean drag_value_motion(GtkWidget *widget, void setup_value_drag(struct value *value) { - static GtkTargetEntry target = { - .target = "value", - .flags = GTK_TARGET_SAME_APP, - }; GtkWidget *box; box = box_of_label(value->widget); gtk_drag_source_set(box, GDK_BUTTON1_MASK, - &target, 1, GDK_ACTION_PRIVATE); + &target_value, 1, GDK_ACTION_PRIVATE); gtk_drag_dest_set(box, GTK_DEST_DEFAULT_HIGHLIGHT, - &target, 1, GDK_ACTION_PRIVATE); - g_signal_connect(G_OBJECT(box), "drag-begin", - G_CALLBACK(drag_begin), value); + &target_value, 1, GDK_ACTION_PRIVATE); + setup_drag_common(box, value); g_signal_connect(G_OBJECT(box), "drag-motion", G_CALLBACK(drag_value_motion), value); } + + +/* ----- drag frame labels ------------------------------------------------- */ + + +static gboolean drag_frame_motion(GtkWidget *widget, + GdkDragContext *drag_context, gint x, gint y, guint time_, + gpointer user_data) +{ + if (!has_target(widget, drag_context, "frame")) + return FALSE; +//fprintf(stderr, "frame\n"); +return FALSE; +} + + +void setup_frame_drag(struct frame *frame) +{ + GtkWidget *box; + + box = box_of_label(frame->label); + gtk_drag_source_set(box, GDK_BUTTON1_MASK, + &target_frame, 1, GDK_ACTION_PRIVATE); + setup_drag_common(box, frame); + g_signal_connect(G_OBJECT(box), "drag-motion", + G_CALLBACK(drag_frame_motion), frame); +} + + +/* ----- drag to the canvas ------------------------------------------------ */ + + +static gboolean drag_canvas_motion(GtkWidget *widget, + GdkDragContext *drag_context, gint x, gint y, guint time_, + gpointer user_data) +{ + if (!has_target(widget, drag_context, "frame")) + return FALSE; +//fprintf(stderr, "canvas\n"); +return FALSE; +} + + +void setup_canvas_drag(GtkWidget *canvas) +{ + gtk_drag_dest_set(canvas, GTK_DEST_DEFAULT_HIGHLIGHT, + &target_frame, 1, GDK_ACTION_PRIVATE); + setup_drag_common(canvas, NULL); + g_signal_connect(G_OBJECT(canvas), "drag-motion", + G_CALLBACK(drag_canvas_motion), NULL); +} diff --git a/gui_frame_drag.h b/gui_frame_drag.h index 1044259..d91b2b0 100644 --- a/gui_frame_drag.h +++ b/gui_frame_drag.h @@ -19,7 +19,11 @@ #include "obj.h" +int is_dragging(void *this); + void setup_var_drag(struct var *var); void setup_value_drag(struct value *value); +void setup_frame_drag(struct frame *frame); +void setup_canvas_drag(GtkWidget *canvas); #endif /* !GUI_FRAME_DRAG_H */