diff options
-rw-r--r-- | widgets/table/e-table-header-item.c | 173 | ||||
-rw-r--r-- | widgets/table/e-table-header-item.h | 7 |
2 files changed, 157 insertions, 23 deletions
diff --git a/widgets/table/e-table-header-item.c b/widgets/table/e-table-header-item.c index f854f98e8d..07e807e773 100644 --- a/widgets/table/e-table-header-item.c +++ b/widgets/table/e-table-header-item.c @@ -101,12 +101,24 @@ enum { ARG_TREE, }; +enum { + ET_SCROLL_UP = 1 << 0, + ET_SCROLL_DOWN = 1 << 1, + ET_SCROLL_LEFT = 1 << 2, + ET_SCROLL_RIGHT = 1 << 3 +}; + +static void scroll_off (ETableHeaderItem *ethi); +static void scroll_on (ETableHeaderItem *ethi, guint scroll_direction); + static void ethi_destroy (GtkObject *object){ ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (object); ethi_drop_table_header (ethi); + scroll_off (ethi); + if (ethi->dnd_code) { g_free (ethi->dnd_code); ethi->dnd_code = NULL; @@ -475,12 +487,12 @@ make_shaped_window_from_xpm (const char **xpm) } static void -ethi_add_drop_marker (ETableHeaderItem *ethi, int col) +ethi_add_drop_marker (ETableHeaderItem *ethi, int col, gboolean recreate) { int rx, ry; int x; - if (ethi->drag_mark == col) + if (!recreate && ethi->drag_mark == col) return; ethi->drag_mark = col; @@ -498,6 +510,9 @@ ethi_add_drop_marker (ETableHeaderItem *ethi, int col) GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas)->window, &rx, &ry); + rx -= gtk_layout_get_hadjustment (GTK_LAYOUT (GNOME_CANVAS_ITEM (ethi)->canvas))->value; + ry -= gtk_layout_get_vadjustment (GTK_LAYOUT (GNOME_CANVAS_ITEM (ethi)->canvas))->value; + gtk_widget_set_uposition (arrow_down, rx + x - ARROW_PTR, ry - ARROW_DOWN_HEIGHT); gtk_widget_show_all (arrow_down); @@ -568,26 +583,14 @@ moved (ETableHeaderItem *ethi, guint col, guint model_col) } #endif -static gboolean -ethi_drag_motion (GtkObject *canvas, GdkDragContext *context, - gint x, gint y, guint time, - ETableHeaderItem *ethi) +static void +do_drag_motion(ETableHeaderItem *ethi, + GdkDragContext *context, + gint x, + gint y, + guint time, + gboolean recreate) { - char *droptype, *headertype; - - gdk_drag_status (context, 0, time); - - droptype = gdk_atom_name (GPOINTER_TO_INT (context->targets->data)); - headertype = g_strdup_printf ("%s-%s", TARGET_ETABLE_COL_TYPE, - ethi->dnd_code); - - if (strcmp (droptype, headertype) != 0) { - g_free (headertype); - return FALSE; - } - - g_free (headertype); - if ((x >= 0) && (x <= (ethi->width)) && (y >= 0) && (y <= (ethi->height))){ int col; @@ -605,7 +608,7 @@ ethi_drag_motion (GtkObject *canvas, GdkDragContext *context, if (ethi->drag_col != -1) ethi_remove_destroy_marker (ethi); - ethi_add_drop_marker (ethi, col); + ethi_add_drop_marker (ethi, col, recreate); gdk_drag_status (context, context->suggested_action, time); } else { ethi_remove_drop_marker (ethi); @@ -617,6 +620,128 @@ ethi_drag_motion (GtkObject *canvas, GdkDragContext *context, if (ethi->drag_col != -1) ethi_add_destroy_marker (ethi); } +} + +static gboolean +scroll_timeout (gpointer data) +{ + ETableHeaderItem *ethi = data; + int dx = 0; + GtkAdjustment *h, *v; + double value; + + if (ethi->scroll_direction & ET_SCROLL_RIGHT) + dx += 20; + if (ethi->scroll_direction & ET_SCROLL_LEFT) + dx -= 20; + + h = GTK_LAYOUT(GNOME_CANVAS_ITEM (ethi)->canvas)->hadjustment; + v = GTK_LAYOUT(GNOME_CANVAS_ITEM (ethi)->canvas)->vadjustment; + + value = h->value; + + gtk_adjustment_set_value(h, CLAMP(h->value + dx, h->lower, h->upper - h->page_size)); + + if (h->value != value) + do_drag_motion(ethi, + ethi->last_drop_context, + ethi->last_drop_x + h->value, + ethi->last_drop_y + v->value, + ethi->last_drop_time, + TRUE); + + return TRUE; +} + +static void +scroll_on (ETableHeaderItem *ethi, guint scroll_direction) +{ + if (ethi->scroll_idle_id == 0 || scroll_direction != ethi->scroll_direction) { + if (ethi->scroll_idle_id != 0) + g_source_remove (ethi->scroll_idle_id); + ethi->scroll_direction = scroll_direction; + ethi->scroll_idle_id = g_timeout_add (100, scroll_timeout, ethi); + } +} + +static void +scroll_off (ETableHeaderItem *ethi) +{ + if (ethi->scroll_idle_id) { + g_source_remove (ethi->scroll_idle_id); + ethi->scroll_idle_id = 0; + } +} + +static void +context_destroyed (gpointer data) +{ + ETableHeaderItem *ethi = data; + if (!GTK_OBJECT_DESTROYED (ethi)) { + ethi->last_drop_x = 0; + ethi->last_drop_y = 0; + ethi->last_drop_time = 0; + ethi->last_drop_context = NULL; + scroll_off (ethi); + } + gtk_object_unref (GTK_OBJECT (ethi)); +} + +static void +context_connect (ETableHeaderItem *ethi, GdkDragContext *context) +{ + if (g_dataset_get_data (context, "e-table-header-item") == NULL) { + gtk_object_ref (GTK_OBJECT (ethi)); + g_dataset_set_data_full (context, "e-table-header-item", ethi, context_destroyed); + } +} + +static gboolean +ethi_drag_motion (GtkWidget *widget, GdkDragContext *context, + gint x, gint y, guint time, + ETableHeaderItem *ethi) +{ + char *droptype, *headertype; + guint direction = 0; + + gdk_drag_status (context, 0, time); + + droptype = gdk_atom_name (GPOINTER_TO_INT (context->targets->data)); + headertype = g_strdup_printf ("%s-%s", TARGET_ETABLE_COL_TYPE, + ethi->dnd_code); + + if (strcmp (droptype, headertype) != 0) { + g_free (headertype); + return FALSE; + } + + g_free (headertype); + + x -= widget->allocation.x; + y -= widget->allocation.y; + + if (x < 20) + direction |= ET_SCROLL_LEFT; + if (x > widget->allocation.width - 20) + direction |= ET_SCROLL_RIGHT; + + ethi->last_drop_x = x; + ethi->last_drop_y = y; + ethi->last_drop_time = time; + ethi->last_drop_context = context; + context_connect (ethi, context); + + do_drag_motion (ethi, + context, + x + GTK_LAYOUT(widget)->hadjustment->value, + y + GTK_LAYOUT(widget)->vadjustment->value, + time, + FALSE); + + if (direction != 0) + scroll_on (ethi, direction); + else + scroll_off (ethi); return TRUE; } @@ -631,6 +756,7 @@ ethi_drag_end (GtkWidget *canvas, GdkDragContext *context, ETableHeaderItem *eth ethi_remove_drop_marker (ethi); ethi_remove_destroy_marker (ethi); ethi->drag_col = -1; + scroll_off (ethi); } static void @@ -717,7 +843,7 @@ ethi_drag_drop (GtkWidget *canvas, col = ethi_find_col_by_x_nearest (ethi, x); - ethi_add_drop_marker (ethi, col); + ethi_add_drop_marker (ethi, col, FALSE); ethi->drop_col = col; @@ -728,6 +854,7 @@ ethi_drag_drop (GtkWidget *canvas, } } gtk_drag_finish (context, successful, successful, time); + scroll_off (ethi); return successful; } diff --git a/widgets/table/e-table-header-item.h b/widgets/table/e-table-header-item.h index 73df683029..38d0aa1791 100644 --- a/widgets/table/e-table-header-item.h +++ b/widgets/table/e-table-header-item.h @@ -84,6 +84,13 @@ typedef struct { */ ETableSortInfo *sort_info; + guint scroll_direction : 4; + int last_drop_x; + int last_drop_y; + int last_drop_time; + GdkDragContext *last_drop_context; + int scroll_idle_id; + /* For adding fields. */ ETableHeader *full_header; ETable *table; |