From 0b241a14fe5511fab72ea75b6d5c46edd4d3aebb Mon Sep 17 00:00:00 2001 From: werner Date: Sat, 24 Apr 2010 21:46:43 +0000 Subject: [PATCH] Dragging a frame into the canvas now works. It's built on top of the frame tool, with all the old code still around, so the code paths are a bit obscure. - gui_frame_drag.c: use GTK_DEST_DEFAULT_MOTION instead of GTK_DEST_DEFAULT_HIGHLIGHT - gui_frame_drag.c: put meat on the frame and canvas drag and drop skeleton - gui_frame_drag.c (setup_frame_drag, setup_canvas_drag): use GDK_ACTION_COPY instead of GDK_ACTION_PRIVATE - gui_frame_drag.h, gui_frame_drag.c (is_dragging_anything): new helper function to check if we're dragging anything, without specifying what - gui_canvas.h, gui_canvas.c: added thin interface layer between gui_frame.c and gui_tool.c - gui_canvas.c (enter_notify_event, leave_notify_event): return FALSE so that other widgets can get the events, too - gui_tool.h, gui_tool.c (tool_hover): return whether we found anything to hover on - gui_tool.h, gui_tool.c: added interface for dropping a frame on the canvas git-svn-id: http://svn.openmoko.org/trunk/eda/fped@5932 99fdad57-331a-0410-800a-d7fa5415bdb3 --- gui_canvas.c | 42 +++++++++++++++- gui_canvas.h | 9 +++- gui_frame_drag.c | 124 +++++++++++++++++++++++++++++++++++++++++++---- gui_frame_drag.h | 1 + gui_tool.c | 75 ++++++++++++++++++++++++++-- gui_tool.h | 6 ++- 6 files changed, 240 insertions(+), 17 deletions(-) diff --git a/gui_canvas.c b/gui_canvas.c index 76dab6f..9a2ec05 100644 --- a/gui_canvas.c +++ b/gui_canvas.c @@ -187,6 +187,41 @@ static gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event, } +/* ----- drag and drop (frame to canvas) ----------------------------------- */ + + +void canvas_frame_begin(struct frame *frame) +{ + tool_push_frame(frame); +} + + +int canvas_frame_motion(struct frame *frame, int x, int y) +{ + struct coord pos = canvas_to_coord(x, y); + + return tool_hover(pos); +} + + +void canvas_frame_end(void) +{ + tool_dehover(); + tool_pop_frame(); +} + + +int canvas_frame_drop(struct frame *frame, int x, int y) +{ + struct coord pos = canvas_to_coord(x, y); + + if (!tool_place_frame(frame, pos)) + return FALSE; + change_world(); + return TRUE; +} + + /* ----- button press and release ------------------------------------------ */ @@ -254,6 +289,8 @@ static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event, DPRINTF("--- button release ---"); switch (event->button) { case 1: + if (is_dragging_anything()) + return FALSE; if (!dragging) break; drag_left(pos); @@ -448,8 +485,9 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, static gboolean enter_notify_event(GtkWidget *widget, GdkEventCrossing *event, gpointer data) { + DPRINTF("--- enter ---"); gtk_widget_grab_focus(widget); - return TRUE; + return FALSE; } @@ -461,7 +499,7 @@ static gboolean leave_notify_event(GtkWidget *widget, GdkEventCrossing *event, tool_cancel_drag(); tool_dehover(); dragging = 0; - return TRUE; + return FALSE; } diff --git a/gui_canvas.h b/gui_canvas.h index 5842797..93443c0 100644 --- a/gui_canvas.h +++ b/gui_canvas.h @@ -1,8 +1,8 @@ /* * gui_canvas.h - GUI, canvas * - * Written 2009 by Werner Almesberger - * Copyright 2009 by Werner Almesberger + * Written 2009, 2010 by Werner Almesberger + * Copyright 2009, 2010 by Werner Almesberger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,6 +34,11 @@ void zoom_out_center(void); void zoom_to_frame(void); void zoom_to_extents(void); +void canvas_frame_begin(struct frame *frame); +int canvas_frame_motion(struct frame *frame, int x, int y); +void canvas_frame_end(void); +int canvas_frame_drop(struct frame *frame, int x, int y); + GtkWidget *make_canvas(void); void init_canvas(void); diff --git a/gui_frame_drag.c b/gui_frame_drag.c index b98a8ff..fcc112b 100644 --- a/gui_frame_drag.c +++ b/gui_frame_drag.c @@ -15,8 +15,14 @@ #include "obj.h" #include "gui_util.h" +#include "gui.h" +#include "gui_canvas.h" #include "gui_frame_drag.h" +#if 0 +#include "icons/frame.xpm" +#endif + enum { target_id_var, @@ -61,6 +67,12 @@ int is_dragging(void *this) } +int is_dragging_anything(void) +{ + return !!dragging; +} + + /* ----- helper functions for indexed list and swapping -------------------- */ @@ -273,7 +285,7 @@ void setup_var_drag(struct var *var) box = box_of_label(var->widget); gtk_drag_source_set(box, GDK_BUTTON1_MASK, &target_var, 1, GDK_ACTION_PRIVATE); - gtk_drag_dest_set(box, GTK_DEST_DEFAULT_HIGHLIGHT, + gtk_drag_dest_set(box, GTK_DEST_DEFAULT_MOTION, &target_var, 1, GDK_ACTION_PRIVATE); setup_drag_common(box, var); g_signal_connect(G_OBJECT(box), "drag-motion", @@ -342,7 +354,7 @@ void setup_value_drag(struct value *value) box = box_of_label(value->widget); gtk_drag_source_set(box, GDK_BUTTON1_MASK, &target_value, 1, GDK_ACTION_PRIVATE); - gtk_drag_dest_set(box, GTK_DEST_DEFAULT_HIGHLIGHT, + gtk_drag_dest_set(box, GTK_DEST_DEFAULT_MOTION, &target_value, 1, GDK_ACTION_PRIVATE); setup_drag_common(box, value); g_signal_connect(G_OBJECT(box), "drag-motion", @@ -350,17 +362,66 @@ void setup_value_drag(struct value *value) } +/* ----- frame to canvas helper functions ---------------------------------- */ + + +static int frame_on_canvas = 0; + + +static void leave_canvas(void) +{ + if (frame_on_canvas) + canvas_frame_end(); + frame_on_canvas = 0; +} + + /* ----- drag frame labels ------------------------------------------------- */ +#if 0 + +/* + * Setting our own icon looks nice but it slows things down to the point where + * cursor movements can lag noticeable and it adds yet another element to an + * already crowded cursor. + */ + +static void drag_frame_begin(GtkWidget *widget, + GtkTextDirection previous_direction, gpointer user_data) +{ + GdkPixmap *pixmap; + GdkBitmap *mask; + GdkColormap *cmap; + + pixmap = gdk_pixmap_create_from_xpm_d(DA, &mask, NULL, xpm_frame); + cmap = gdk_drawable_get_colormap(root->window); + gtk_drag_source_set_icon(widget, cmap, pixmap, mask); + g_object_unref(pixmap); + g_object_unref(mask); + + dragging = user_data; +} + +#endif + + 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; + /* nothing else to do yet */ + return FALSE; +} + + +static void drag_frame_end(GtkWidget *widget, GdkDragContext *drag_context, + gpointer user_data) +{ + leave_canvas(); + drag_end(widget, drag_context, user_data); } @@ -370,8 +431,17 @@ void setup_frame_drag(struct frame *frame) box = box_of_label(frame->label); gtk_drag_source_set(box, GDK_BUTTON1_MASK, - &target_frame, 1, GDK_ACTION_PRIVATE); + &target_frame, 1, GDK_ACTION_COPY); setup_drag_common(box, frame); + + /* override */ +#if 0 + g_signal_connect(G_OBJECT(box), "drag-begin", + G_CALLBACK(drag_frame_begin), frame); +#endif + g_signal_connect(G_OBJECT(box), "drag-end", + G_CALLBACK(drag_frame_end), frame); + g_signal_connect(G_OBJECT(box), "drag-motion", G_CALLBACK(drag_frame_motion), frame); } @@ -386,16 +456,52 @@ static gboolean drag_canvas_motion(GtkWidget *widget, { if (!has_target(widget, drag_context, "frame")) return FALSE; -//fprintf(stderr, "canvas\n"); +gtk_drag_finish(drag_context, FALSE, FALSE, time_); return FALSE; + if (!frame_on_canvas) { + frame_on_canvas = 1; + canvas_frame_begin(dragging); + } + if (canvas_frame_motion(dragging, x, y)) { + gdk_drag_status(drag_context, GDK_ACTION_COPY, time_); + return TRUE; + } else { + gdk_drag_status(drag_context, 0, time_); + return FALSE; + } +} + + +static void drag_canvas_leave(GtkWidget *widget, GdkDragContext *drag_context, + guint time_, gpointer user_data) +{ + leave_canvas(); +} + + +static gboolean drag_canvas_drop(GtkWidget *widget, + GdkDragContext *drag_context, gint x, gint y, guint time_, + gpointer user_data) +{ + if (!has_target(widget, drag_context, "frame")) + return FALSE; + if (!canvas_frame_drop(dragging, x, y)) + return FALSE; + gtk_drag_finish(drag_context, TRUE, FALSE, time_); + return TRUE; } 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); + gtk_drag_dest_set(canvas, + GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, + &target_frame, 1, GDK_ACTION_COPY); + g_signal_connect(G_OBJECT(canvas), "drag-motion", G_CALLBACK(drag_canvas_motion), NULL); + g_signal_connect(G_OBJECT(canvas), "drag-leave", + G_CALLBACK(drag_canvas_leave), NULL); + g_signal_connect(G_OBJECT(canvas), "drag-drop", + G_CALLBACK(drag_canvas_drop), NULL); } diff --git a/gui_frame_drag.h b/gui_frame_drag.h index d91b2b0..f45c8e8 100644 --- a/gui_frame_drag.h +++ b/gui_frame_drag.h @@ -20,6 +20,7 @@ int is_dragging(void *this); +int is_dragging_anything(void); void setup_var_drag(struct var *var); void setup_value_drag(struct value *value); diff --git a/gui_tool.c b/gui_tool.c index 69c3025..cdc1bc0 100644 --- a/gui_tool.c +++ b/gui_tool.c @@ -803,7 +803,7 @@ static struct inst *get_hover_inst(struct coord pos) } -void tool_hover(struct coord pos) +int tool_hover(struct coord pos) { struct inst *curr; @@ -825,15 +825,84 @@ got: #endif if (curr == hover_inst) - return; + return !!curr; if (hover_inst) { over_leave(); hover_inst = NULL; } if (!curr) - return; + return 0; hover_inst = curr; over_enter(hover_save_and_draw, NULL); + return 1; +} + + +/* ----- frame drag and drop ----------------------------------------------- */ + + +/* + * When dragging a frame, we temporarily replace the selected tool (if any) + * with the frame tool. + */ + + +static struct tool_ops *pushed_ops; + + +void tool_push_frame(struct frame *frame) +{ + pushed_ops = active_ops; + locked_frame = frame; + active_ops = &frame_ops; + /* + * We don't need to call tool_selected since, with drag and drop, the + * frame tools doesn't need activation anymore. + */ +} + + +static int do_place_frame(struct frame *frame, struct coord pos) +{ + if (!get_hover_inst(pos)) + return 0; + tool_consider_drag(pos); + return 1; +} + + +/* + * Gtk calls drag-leave, drag-end, and only then drag-drop. So we'll already + * have cleaned up in tool_pop_frame before we get here. In order to place the + * frame, we need to activate the frame tool again. + * + * @@@ bug: there's a tool_reset in this path, so we'll lose the widget of the + * tool that's really active. This problem will vanish when scrapping the + * old-style frame referenes. + */ + +int tool_place_frame(struct frame *frame, struct coord pos) +{ + int ok; + + active_ops = &frame_ops; + ok = do_place_frame(frame, pos); + active_ops = pushed_ops; + return ok; +} + + +void tool_pop_frame(void) +{ + if (!active_tool) + return; + active_ops = pushed_ops; + /* + * We don't need to call tool_selected since the only tool that could + * use this would be the delete tool, and there the semantics would be + * undesirable. Also, the delete tool never stays active, so it can't + * appear together with drag and drop anyway. + */ } diff --git a/gui_tool.h b/gui_tool.h index e06b103..048e32e 100644 --- a/gui_tool.h +++ b/gui_tool.h @@ -46,7 +46,7 @@ struct pix_buf *gui_hover_frame(struct inst *self); void do_move_to_arc(struct inst *inst, struct inst *to, int i); void tool_dehover(void); -void tool_hover(struct coord pos); +int tool_hover(struct coord pos); const char *tool_tip(struct coord pos); int tool_consider_drag(struct coord pos); void tool_drag(struct coord to); @@ -73,6 +73,10 @@ struct pix_buf *drag_new_line(struct inst *from, struct coord to); void tool_frame_update(void); void tool_frame_deleted(const struct frame *frame); +void tool_push_frame(struct frame *frame); +int tool_place_frame(struct frame *frame, struct coord pos); +void tool_pop_frame(void); + void tool_selected_inst(struct inst *inst); GtkWidget *get_icon_by_inst(const struct inst *inst);