diff options
-rw-r--r-- | widgets/e-table/ChangeLog | 6 | ||||
-rw-r--r-- | widgets/e-table/e-table.c | 263 | ||||
-rw-r--r-- | widgets/e-table/e-table.h | 12 | ||||
-rw-r--r-- | widgets/table/e-table.c | 263 | ||||
-rw-r--r-- | widgets/table/e-table.h | 12 |
5 files changed, 478 insertions, 78 deletions
diff --git a/widgets/e-table/ChangeLog b/widgets/e-table/ChangeLog index c71a663f88..4b91e9dcc2 100644 --- a/widgets/e-table/ChangeLog +++ b/widgets/e-table/ChangeLog @@ -1,5 +1,11 @@ 2000-08-04 Christopher James Lahey <clahey@helixcode.com> + * e-table.c, e-table.h: Built code to have autodrags only work + from within the table and to report the row dragged from + automatically. + +2000-08-04 Christopher James Lahey <clahey@helixcode.com> + * e-table-group-container.c, e-table-group-leaf.c, e-table-group.c, e-table-group.h, e-table-item.c, e-table-item.h: Made drag events calculate a row and column and signal that diff --git a/widgets/e-table/e-table.c b/widgets/e-table/e-table.c index 8099d3de0d..4daddc3985 100644 --- a/widgets/e-table/e-table.c +++ b/widgets/e-table/e-table.c @@ -112,6 +112,9 @@ static void et_drag_data_received(GtkWidget *widget, guint info, guint time, ETable *et); +static gint e_table_drag_source_event_cb (GtkWidget *widget, + GdkEvent *event, + ETable *table); static void et_destroy (GtkObject *object) @@ -178,10 +181,11 @@ e_table_init (GtkObject *object) e_table->drag_get_data_row = -1; e_table->drag_get_data_col = -1; - e_table->drag_row = -1; - e_table->drag_col = -1; e_table->drop_row = -1; e_table->drop_col = -1; + e_table->site = NULL; + e_table->drag_source_button_press_event_id = 0; + e_table->drag_source_motion_notify_event_id = 0; e_table->selection = e_table_selection_model_new(); e_table->cursor_loc = E_TABLE_CURSOR_LOC_NONE; @@ -915,6 +919,73 @@ set_scroll_adjustments (ETable *table, hadjustment); } +struct _ETableDragSourceSite +{ + GdkModifierType start_button_mask; + GtkTargetList *target_list; /* Targets for drag data */ + GdkDragAction actions; /* Possible actions */ + GdkColormap *colormap; /* Colormap for drag icon */ + GdkPixmap *pixmap; /* Icon for drag data */ + GdkBitmap *mask; + + /* Stored button press information to detect drag beginning */ + gint state; + gint x, y; + gint row, col; +}; + +typedef enum +{ + GTK_DRAG_STATUS_DRAG, + GTK_DRAG_STATUS_WAIT, + GTK_DRAG_STATUS_DROP +} GtkDragStatus; + +typedef struct _GtkDragDestInfo GtkDragDestInfo; +typedef struct _GtkDragSourceInfo GtkDragSourceInfo; + +struct _GtkDragDestInfo +{ + GtkWidget *widget; /* Widget in which drag is in */ + GdkDragContext *context; /* Drag context */ + GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */ + GtkSelectionData *proxy_data; /* Set while retrieving proxied data */ + gboolean dropped : 1; /* Set after we receive a drop */ + guint32 proxy_drop_time; /* Timestamp for proxied drop */ + gboolean proxy_drop_wait : 1; /* Set if we are waiting for a + * status reply before sending + * a proxied drop on. + */ + gint drop_x, drop_y; /* Position of drop */ +}; + +struct _GtkDragSourceInfo +{ + GtkWidget *widget; + GtkTargetList *target_list; /* Targets for drag data */ + GdkDragAction possible_actions; /* Actions allowed by source */ + GdkDragContext *context; /* drag context */ + GtkWidget *icon_window; /* Window for drag */ + GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */ + GdkCursor *cursor; /* Cursor for drag */ + gint hot_x, hot_y; /* Hot spot for drag */ + gint button; /* mouse button starting drag */ + + GtkDragStatus status; /* drag status */ + GdkEvent *last_event; /* motion event waiting for response */ + + gint start_x, start_y; /* Initial position */ + gint cur_x, cur_y; /* Current Position */ + + GList *selections; /* selections we've claimed */ + + GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */ + + guint drop_timeout; /* Timeout for aborting drop */ + guint destroy_icon : 1; /* If true, destroy icon_window + */ +}; + /* Drag & drop stuff. */ /* Target */ void e_table_drag_get_data (ETable *table, @@ -984,16 +1055,60 @@ void e_table_drag_source_set (ETable *table, gint n_targets, GdkDragAction actions) { - gtk_drag_source_set(GTK_WIDGET(table), - start_button_mask, - targets, - n_targets, - actions); + ETableDragSourceSite *site; + GtkWidget *canvas = GTK_WIDGET(table->table_canvas); + + g_return_if_fail (table != NULL); + + site = table->site; + + gtk_widget_add_events (canvas, + gtk_widget_get_events (canvas) | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK); + + if (site) { + if (site->target_list) + gtk_target_list_unref (site->target_list); + } else { + site = g_new0 (ETableDragSourceSite, 1); + + table->drag_source_button_press_event_id = + gtk_signal_connect (GTK_OBJECT (canvas), "button_press_event", + GTK_SIGNAL_FUNC (e_table_drag_source_event_cb), + site); + table->drag_source_motion_notify_event_id = + gtk_signal_connect (GTK_OBJECT (canvas), "motion_notify_event", + GTK_SIGNAL_FUNC (e_table_drag_source_event_cb), + site); + + table->site = site; + } + + site->start_button_mask = start_button_mask; + + if (targets) + site->target_list = gtk_target_list_new (targets, n_targets); + else + site->target_list = NULL; + + site->actions = actions; } void e_table_drag_source_unset (ETable *table) { - gtk_drag_source_unset(GTK_WIDGET(table)); + ETableDragSourceSite *site; + + g_return_if_fail (table != NULL); + + site = table->site; + + if (site) { + gtk_signal_disconnect (GTK_OBJECT (table->table_canvas), table->drag_source_button_press_event_id); + gtk_signal_disconnect (GTK_OBJECT (table->table_canvas), table->drag_source_motion_notify_event_id); + g_free(site); + table->site = NULL; + } } /* There probably should be functions for setting the targets @@ -1029,10 +1144,7 @@ e_table_compute_location(ETable *table, { if (!(row || col)) return; - if (row) - *row = 0; - if (col) - *col = 0; + e_table_group_compute_location(table->group, &x, &y, row, col); } static void @@ -1132,15 +1244,16 @@ et_drag_motion(GtkWidget *widget, } et->drop_row = row; et->drop_col = col; - gtk_signal_emit (GTK_OBJECT (et), - et_signals [TABLE_DRAG_MOTION], - et->drop_row, - et->drop_col, - context, - x, - y, - time, - &ret_val); + if (row >= 0 && col >= 0) + gtk_signal_emit (GTK_OBJECT (et), + et_signals [TABLE_DRAG_MOTION], + et->drop_row, + et->drop_col, + context, + x, + y, + time, + &ret_val); return ret_val; } @@ -1168,27 +1281,29 @@ et_drag_drop(GtkWidget *widget, et->drop_col, context, time); + if (row >= 0 && col >= 0) + gtk_signal_emit (GTK_OBJECT (et), + et_signals [TABLE_DRAG_MOTION], + row, + col, + context, + x, + y, + time, + &ret_val); + } + et->drop_row = row; + et->drop_col = col; + if (row >= 0 && col >= 0) gtk_signal_emit (GTK_OBJECT (et), - et_signals [TABLE_DRAG_MOTION], - row, - col, + et_signals [TABLE_DRAG_DROP], + et->drop_row, + et->drop_col, context, x, y, time, &ret_val); - } - et->drop_row = row; - et->drop_col = col; - gtk_signal_emit (GTK_OBJECT (et), - et_signals [TABLE_DRAG_DROP], - et->drop_row, - et->drop_col, - context, - x, - y, - time, - &ret_val); et->drop_row = -1; et->drop_col = -1; return ret_val; @@ -1223,6 +1338,82 @@ et_drag_data_received(GtkWidget *widget, time); } +static gint +e_table_drag_source_event_cb (GtkWidget *widget, + GdkEvent *event, + ETable *table) +{ + ETableDragSourceSite *site; + site = table->site; + + switch (event->type) { + case GDK_BUTTON_PRESS: + if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask) { + int row, col; + e_table_compute_location(table, widget, event->button.x, event->button.y, &row, &col); + if (row >= 0 && col >= 0) { + site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1)); + site->x = event->button.x; + site->y = event->button.y; + site->row = row; + site->col = col; + } + } + break; + + case GDK_BUTTON_RELEASE: + if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask) { + site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1)); + } + break; + + case GDK_MOTION_NOTIFY: + if (site->state & event->motion.state & site->start_button_mask) { + /* FIXME: This is really broken and can leave us + * with a stuck grab + */ + int i; + for (i=1; i<6; i++) { + if (site->state & event->motion.state & + GDK_BUTTON1_MASK << (i - 1)) + break; + } + + if (MAX (abs (site->x - event->motion.x), + abs (site->y - event->motion.y)) > 3) { + GtkDragSourceInfo *info; + GdkDragContext *context; + + site->state = 0; + context = e_table_drag_begin (table, site->row, site->col, + site->target_list, + site->actions, + i, event); + + + info = g_dataset_get_data (context, "gtk-info"); + + if (!info->icon_window) { + if (site->pixmap) + gtk_drag_set_icon_pixmap (context, + site->colormap, + site->pixmap, + site->mask, -2, -2); + else + gtk_drag_set_icon_default (context); + } + + return TRUE; + } + } + break; + + default: /* hit for 2/3BUTTON_PRESS */ + break; + } + return FALSE; +} + static void e_table_class_init (GtkObjectClass *object_class) { diff --git a/widgets/e-table/e-table.h b/widgets/e-table/e-table.h index 8b41407d1a..6f4fe153c6 100644 --- a/widgets/e-table/e-table.h +++ b/widgets/e-table/e-table.h @@ -21,6 +21,8 @@ BEGIN_GNOME_DECLS #define E_IS_TABLE(o) (GTK_CHECK_TYPE ((o), E_TABLE_TYPE)) #define E_IS_TABLE_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TABLE_TYPE)) +typedef struct _ETableDragSourceSite ETableDragSourceSite; + typedef enum { E_TABLE_CURSOR_LOC_NONE = 0, E_TABLE_CURSOR_LOC_ETCTA = 1 << 0, @@ -77,11 +79,15 @@ typedef struct { int drag_get_data_row; int drag_get_data_col; - int drag_row; - int drag_col; - int drop_row; int drop_col; + + int drag_row; + int drag_col; + ETableDragSourceSite *site; + + int drag_source_button_press_event_id; + int drag_source_motion_notify_event_id; } ETable; typedef struct { diff --git a/widgets/table/e-table.c b/widgets/table/e-table.c index 8099d3de0d..4daddc3985 100644 --- a/widgets/table/e-table.c +++ b/widgets/table/e-table.c @@ -112,6 +112,9 @@ static void et_drag_data_received(GtkWidget *widget, guint info, guint time, ETable *et); +static gint e_table_drag_source_event_cb (GtkWidget *widget, + GdkEvent *event, + ETable *table); static void et_destroy (GtkObject *object) @@ -178,10 +181,11 @@ e_table_init (GtkObject *object) e_table->drag_get_data_row = -1; e_table->drag_get_data_col = -1; - e_table->drag_row = -1; - e_table->drag_col = -1; e_table->drop_row = -1; e_table->drop_col = -1; + e_table->site = NULL; + e_table->drag_source_button_press_event_id = 0; + e_table->drag_source_motion_notify_event_id = 0; e_table->selection = e_table_selection_model_new(); e_table->cursor_loc = E_TABLE_CURSOR_LOC_NONE; @@ -915,6 +919,73 @@ set_scroll_adjustments (ETable *table, hadjustment); } +struct _ETableDragSourceSite +{ + GdkModifierType start_button_mask; + GtkTargetList *target_list; /* Targets for drag data */ + GdkDragAction actions; /* Possible actions */ + GdkColormap *colormap; /* Colormap for drag icon */ + GdkPixmap *pixmap; /* Icon for drag data */ + GdkBitmap *mask; + + /* Stored button press information to detect drag beginning */ + gint state; + gint x, y; + gint row, col; +}; + +typedef enum +{ + GTK_DRAG_STATUS_DRAG, + GTK_DRAG_STATUS_WAIT, + GTK_DRAG_STATUS_DROP +} GtkDragStatus; + +typedef struct _GtkDragDestInfo GtkDragDestInfo; +typedef struct _GtkDragSourceInfo GtkDragSourceInfo; + +struct _GtkDragDestInfo +{ + GtkWidget *widget; /* Widget in which drag is in */ + GdkDragContext *context; /* Drag context */ + GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */ + GtkSelectionData *proxy_data; /* Set while retrieving proxied data */ + gboolean dropped : 1; /* Set after we receive a drop */ + guint32 proxy_drop_time; /* Timestamp for proxied drop */ + gboolean proxy_drop_wait : 1; /* Set if we are waiting for a + * status reply before sending + * a proxied drop on. + */ + gint drop_x, drop_y; /* Position of drop */ +}; + +struct _GtkDragSourceInfo +{ + GtkWidget *widget; + GtkTargetList *target_list; /* Targets for drag data */ + GdkDragAction possible_actions; /* Actions allowed by source */ + GdkDragContext *context; /* drag context */ + GtkWidget *icon_window; /* Window for drag */ + GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */ + GdkCursor *cursor; /* Cursor for drag */ + gint hot_x, hot_y; /* Hot spot for drag */ + gint button; /* mouse button starting drag */ + + GtkDragStatus status; /* drag status */ + GdkEvent *last_event; /* motion event waiting for response */ + + gint start_x, start_y; /* Initial position */ + gint cur_x, cur_y; /* Current Position */ + + GList *selections; /* selections we've claimed */ + + GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */ + + guint drop_timeout; /* Timeout for aborting drop */ + guint destroy_icon : 1; /* If true, destroy icon_window + */ +}; + /* Drag & drop stuff. */ /* Target */ void e_table_drag_get_data (ETable *table, @@ -984,16 +1055,60 @@ void e_table_drag_source_set (ETable *table, gint n_targets, GdkDragAction actions) { - gtk_drag_source_set(GTK_WIDGET(table), - start_button_mask, - targets, - n_targets, - actions); + ETableDragSourceSite *site; + GtkWidget *canvas = GTK_WIDGET(table->table_canvas); + + g_return_if_fail (table != NULL); + + site = table->site; + + gtk_widget_add_events (canvas, + gtk_widget_get_events (canvas) | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK); + + if (site) { + if (site->target_list) + gtk_target_list_unref (site->target_list); + } else { + site = g_new0 (ETableDragSourceSite, 1); + + table->drag_source_button_press_event_id = + gtk_signal_connect (GTK_OBJECT (canvas), "button_press_event", + GTK_SIGNAL_FUNC (e_table_drag_source_event_cb), + site); + table->drag_source_motion_notify_event_id = + gtk_signal_connect (GTK_OBJECT (canvas), "motion_notify_event", + GTK_SIGNAL_FUNC (e_table_drag_source_event_cb), + site); + + table->site = site; + } + + site->start_button_mask = start_button_mask; + + if (targets) + site->target_list = gtk_target_list_new (targets, n_targets); + else + site->target_list = NULL; + + site->actions = actions; } void e_table_drag_source_unset (ETable *table) { - gtk_drag_source_unset(GTK_WIDGET(table)); + ETableDragSourceSite *site; + + g_return_if_fail (table != NULL); + + site = table->site; + + if (site) { + gtk_signal_disconnect (GTK_OBJECT (table->table_canvas), table->drag_source_button_press_event_id); + gtk_signal_disconnect (GTK_OBJECT (table->table_canvas), table->drag_source_motion_notify_event_id); + g_free(site); + table->site = NULL; + } } /* There probably should be functions for setting the targets @@ -1029,10 +1144,7 @@ e_table_compute_location(ETable *table, { if (!(row || col)) return; - if (row) - *row = 0; - if (col) - *col = 0; + e_table_group_compute_location(table->group, &x, &y, row, col); } static void @@ -1132,15 +1244,16 @@ et_drag_motion(GtkWidget *widget, } et->drop_row = row; et->drop_col = col; - gtk_signal_emit (GTK_OBJECT (et), - et_signals [TABLE_DRAG_MOTION], - et->drop_row, - et->drop_col, - context, - x, - y, - time, - &ret_val); + if (row >= 0 && col >= 0) + gtk_signal_emit (GTK_OBJECT (et), + et_signals [TABLE_DRAG_MOTION], + et->drop_row, + et->drop_col, + context, + x, + y, + time, + &ret_val); return ret_val; } @@ -1168,27 +1281,29 @@ et_drag_drop(GtkWidget *widget, et->drop_col, context, time); + if (row >= 0 && col >= 0) + gtk_signal_emit (GTK_OBJECT (et), + et_signals [TABLE_DRAG_MOTION], + row, + col, + context, + x, + y, + time, + &ret_val); + } + et->drop_row = row; + et->drop_col = col; + if (row >= 0 && col >= 0) gtk_signal_emit (GTK_OBJECT (et), - et_signals [TABLE_DRAG_MOTION], - row, - col, + et_signals [TABLE_DRAG_DROP], + et->drop_row, + et->drop_col, context, x, y, time, &ret_val); - } - et->drop_row = row; - et->drop_col = col; - gtk_signal_emit (GTK_OBJECT (et), - et_signals [TABLE_DRAG_DROP], - et->drop_row, - et->drop_col, - context, - x, - y, - time, - &ret_val); et->drop_row = -1; et->drop_col = -1; return ret_val; @@ -1223,6 +1338,82 @@ et_drag_data_received(GtkWidget *widget, time); } +static gint +e_table_drag_source_event_cb (GtkWidget *widget, + GdkEvent *event, + ETable *table) +{ + ETableDragSourceSite *site; + site = table->site; + + switch (event->type) { + case GDK_BUTTON_PRESS: + if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask) { + int row, col; + e_table_compute_location(table, widget, event->button.x, event->button.y, &row, &col); + if (row >= 0 && col >= 0) { + site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1)); + site->x = event->button.x; + site->y = event->button.y; + site->row = row; + site->col = col; + } + } + break; + + case GDK_BUTTON_RELEASE: + if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask) { + site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1)); + } + break; + + case GDK_MOTION_NOTIFY: + if (site->state & event->motion.state & site->start_button_mask) { + /* FIXME: This is really broken and can leave us + * with a stuck grab + */ + int i; + for (i=1; i<6; i++) { + if (site->state & event->motion.state & + GDK_BUTTON1_MASK << (i - 1)) + break; + } + + if (MAX (abs (site->x - event->motion.x), + abs (site->y - event->motion.y)) > 3) { + GtkDragSourceInfo *info; + GdkDragContext *context; + + site->state = 0; + context = e_table_drag_begin (table, site->row, site->col, + site->target_list, + site->actions, + i, event); + + + info = g_dataset_get_data (context, "gtk-info"); + + if (!info->icon_window) { + if (site->pixmap) + gtk_drag_set_icon_pixmap (context, + site->colormap, + site->pixmap, + site->mask, -2, -2); + else + gtk_drag_set_icon_default (context); + } + + return TRUE; + } + } + break; + + default: /* hit for 2/3BUTTON_PRESS */ + break; + } + return FALSE; +} + static void e_table_class_init (GtkObjectClass *object_class) { diff --git a/widgets/table/e-table.h b/widgets/table/e-table.h index 8b41407d1a..6f4fe153c6 100644 --- a/widgets/table/e-table.h +++ b/widgets/table/e-table.h @@ -21,6 +21,8 @@ BEGIN_GNOME_DECLS #define E_IS_TABLE(o) (GTK_CHECK_TYPE ((o), E_TABLE_TYPE)) #define E_IS_TABLE_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TABLE_TYPE)) +typedef struct _ETableDragSourceSite ETableDragSourceSite; + typedef enum { E_TABLE_CURSOR_LOC_NONE = 0, E_TABLE_CURSOR_LOC_ETCTA = 1 << 0, @@ -77,11 +79,15 @@ typedef struct { int drag_get_data_row; int drag_get_data_col; - int drag_row; - int drag_col; - int drop_row; int drop_col; + + int drag_row; + int drag_col; + ETableDragSourceSite *site; + + int drag_source_button_press_event_id; + int drag_source_motion_notify_event_id; } ETable; typedef struct { |