diff options
author | Anders Carlsson <andersca@gnome.org> | 2001-07-22 20:09:00 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@src.gnome.org> | 2001-07-22 20:09:00 +0000 |
commit | f4ca329027a0fa5b96738bec5b099f08cb168355 (patch) | |
tree | 9ed81a604a73de8d4402562c07cb3f3928988d09 /gtk | |
parent | 5751ed9e167df757c5ebb74f8be1943b844a78dc (diff) | |
download | gtk+-f4ca329027a0fa5b96738bec5b099f08cb168355.tar.gz |
Add support for animating expanders.
2001-07-22 Anders Carlsson <andersca@gnome.org>
* gtk/gtktreeview.c (gtk_tree_view_class_init): Replace the
expander_height and expander_width properties with a single
property, expander_size.
(gtk_tree_view_init): Set the tab_offset to expander_size
plus some padding.
(gtk_tree_view_unrealize): Remove the expand/collapse
timeout if it exists.
(coords_are_over_arrow): Fix a small bug.
(gtk_tree_view_motion_draw_column_motion_arrow): Use
expander_size.
(gtk_tree_view_draw_focus): Use "treeview" instead of
"add-mode" as detail when drawing the focus.
(gtk_tree_view_bin_expose): Use "treeview-drop-indicator"
instead of "add-mode" as detail when drawing the focus.
(gtk_tree_view_deleted): If we have a node currently being
expanded or collapsed, remove the timeout and set the node
to NULL.
(gtk_tree_view_queue_draw_arrow): New function that just
redraws the arrow of a node.
(gtk_tree_view_draw_arrow): Use expander_size instead of
expander_width/expander_height, also pass a different
expander_style to gtk_paint_expander depending on the
state of the node being drawn.
(expand_collapse_timeout): New function for expanding
or collapsing a node depending on the previous state.
(gtk_tree_view_real_expand_row): Add timeout and set
correct state for node being expanded.
(gtk_tree_view_real_collapse_row): Add timeout and set
correct state for node being collapsed.
* gtk/gtktreeprivate.h (struct _GtkTreeViewPrivate): Add
information about the node currently being expanded or
collapsed, and also a timeout id.
* gtk/gtkstyle.h (struct _GtkStyleClass): Replace is_open
with expander_style for draw_expander.
* gtk/gtkstyle.c (gtk_draw_expander): Replace is_open with
expander_style.
(create_expander_affine): New function for creating an
expander affine.
(apply_affine_on_point): New function for applying an
affine to a point.
(gtk_default_draw_expander): Modified to take expander_style
instead of is_open, and to draw the rectangle rotated differently
depending on the expander style.
(gtk_paint_expander): Replace is_open with expander_style.
* gtk/gtkrbtree.h: Add expander states to GtkRBNodeColor.
* gtk/gtkenums.h: Add expander style enum.
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/gtkenums.h | 9 | ||||
-rw-r--r-- | gtk/gtkrbtree.h | 4 | ||||
-rw-r--r-- | gtk/gtkstyle.c | 110 | ||||
-rw-r--r-- | gtk/gtkstyle.h | 6 | ||||
-rw-r--r-- | gtk/gtktreeprivate.h | 5 | ||||
-rw-r--r-- | gtk/gtktreeview.c | 263 |
6 files changed, 312 insertions, 85 deletions
diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h index 71884c83b3..3214150ed6 100644 --- a/gtk/gtkenums.h +++ b/gtk/gtkenums.h @@ -115,6 +115,15 @@ typedef enum GTK_DIR_RIGHT } GtkDirectionType; +/* Expander styles */ +typedef enum +{ + GTK_EXPANDER_COLLAPSED, + GTK_EXPANDER_SEMI_COLLAPSED, + GTK_EXPANDER_SEMI_EXPANDED, + GTK_EXPANDER_EXPANDED +} GtkExpanderStyle; + /* Built-in stock icon sizes */ typedef enum { diff --git a/gtk/gtkrbtree.h b/gtk/gtkrbtree.h index 932648166f..a218c3e628 100644 --- a/gtk/gtkrbtree.h +++ b/gtk/gtkrbtree.h @@ -32,7 +32,9 @@ typedef enum GTK_RBNODE_IS_PARENT = 1 << 2, GTK_RBNODE_IS_SELECTED = 1 << 3, GTK_RBNODE_IS_PRELIT = 1 << 4, - GTK_RBNODE_NON_COLORS = GTK_RBNODE_IS_PARENT | GTK_RBNODE_IS_SELECTED | GTK_RBNODE_IS_PRELIT, + GTK_RBNODE_IS_SEMI_COLLAPSED = 1 << 5, + GTK_RBNODE_IS_SEMI_EXPANDED = 1 << 6, + GTK_RBNODE_NON_COLORS = GTK_RBNODE_IS_PARENT | GTK_RBNODE_IS_SELECTED | GTK_RBNODE_IS_PRELIT | GTK_RBNODE_IS_SEMI_COLLAPSED | GTK_RBNODE_IS_SEMI_EXPANDED } GtkRBNodeColor; typedef struct _GtkRBTree GtkRBTree; diff --git a/gtk/gtkstyle.c b/gtk/gtkstyle.c index 989540b724..84533d305f 100644 --- a/gtk/gtkstyle.c +++ b/gtk/gtkstyle.c @@ -278,7 +278,7 @@ static void gtk_default_draw_expander (GtkStyle *style, const gchar *detail, gint x, gint y, - gboolean is_open); + GtkExpanderStyle expander_style); static void gtk_default_draw_layout (GtkStyle *style, GdkWindow *window, GtkStateType state_type, @@ -1103,14 +1103,14 @@ gtk_draw_expander (GtkStyle *style, GtkStateType state_type, gint x, gint y, - gboolean is_open) + GtkExpanderStyle expander_style) { g_return_if_fail (GTK_IS_STYLE (style)); g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_expander != NULL); GTK_STYLE_GET_CLASS (style)->draw_expander (style, window, state_type, NULL, NULL, NULL, - x, y, is_open); + x, y, expander_style); } void @@ -3804,7 +3804,7 @@ gtk_default_draw_focus (GtkStyle *style, GdkPoint points[5]; sanitize_size (window, &width, &height); - + if (area) gdk_gc_set_clip_rectangle (style->black_gc, area); @@ -3992,6 +3992,43 @@ gtk_default_draw_handle (GtkStyle *style, } static void +create_expander_affine (gdouble affine[6], + gint degrees, + gint expander_size, + gint x, + gint y) +{ + gdouble s, c; + gdouble width; + gdouble height; + + width = expander_size / 4; + height = expander_size / 2; + + s = sin (degrees * M_PI / 180.0); + c = cos (degrees * M_PI / 180.0); + + affine[0] = c; + affine[1] = s; + affine[2] = -s; + affine[3] = c; + affine[4] = -width * c - height * -s + x; + affine[5] = -width * s - height * c + y; +} + +static void +apply_affine_on_point (double affine[6], GdkPoint *point) +{ + gdouble x, y; + + x = point->x * affine[0] + point->y * affine[2] + affine[4]; + y = point->x * affine[1] + point->y * affine[3] + affine[5]; + + point->x = x; + point->y = y; +} + +static void gtk_default_draw_expander (GtkStyle *style, GdkWindow *window, GtkStateType state_type, @@ -4000,12 +4037,17 @@ gtk_default_draw_expander (GtkStyle *style, const gchar *detail, gint x, gint y, - gboolean is_open) + GtkExpanderStyle expander_style) { - /* FIXME replace macro with a style property */ -#define PM_SIZE 8 - + gint expander_size; GdkPoint points[3]; + gint i; + gdouble affine[6]; + gint degrees = 0; + + gtk_widget_style_get (widget, + "expander_size", &expander_size, + NULL); if (area) { @@ -4013,38 +4055,46 @@ gtk_default_draw_expander (GtkStyle *style, gdk_gc_set_clip_rectangle (style->base_gc[GTK_STATE_NORMAL], area); } - if (is_open) - { - points[0].x = x; - points[0].y = y + (PM_SIZE + 2) / 6; - points[1].x = points[0].x + 1 * (PM_SIZE + 2); - points[1].y = points[0].y; - points[2].x = (points[0].x + 1 * (PM_SIZE + 2) / 2); - points[2].y = y + 2 * (PM_SIZE + 2) / 3; - } - else + points[0].x = 0; + points[0].y = 0; + points[1].x = expander_size / 2; + points[1].y = expander_size / 2; + points[2].x = 0; + points[2].y = expander_size; + + switch (expander_style) { - points[0].x = x + 1 * ((PM_SIZE + 2) / 6 + 2); - points[0].y = y - 1; - points[1].x = points[0].x; - points[1].y = points[0].y + (PM_SIZE + 2); - points[2].x = (points[0].x + 1 * (2 * (PM_SIZE + 2) / 3 - 1)); - points[2].y = points[0].y + (PM_SIZE + 2) / 2; + case GTK_EXPANDER_COLLAPSED: + degrees = 0; + break; + case GTK_EXPANDER_SEMI_COLLAPSED: + degrees = 30; + break; + case GTK_EXPANDER_SEMI_EXPANDED: + degrees = 60; + break; + case GTK_EXPANDER_EXPANDED: + degrees = 90; + break; + default: + g_assert_not_reached (); } + + create_expander_affine (affine, degrees, expander_size, x, y); + + for (i = 0; i < 3; i++) + apply_affine_on_point (affine, &points[i]); gdk_draw_polygon (window, style->base_gc[GTK_STATE_NORMAL], - TRUE, points, 3); + TRUE, points, 3); gdk_draw_polygon (window, style->fg_gc[GTK_STATE_NORMAL], FALSE, points, 3); - if (area) { gdk_gc_set_clip_rectangle (style->fg_gc[GTK_STATE_NORMAL], NULL); gdk_gc_set_clip_rectangle (style->base_gc[GTK_STATE_NORMAL], NULL); } - -#undef PM_SIZE } typedef struct _ByteRange ByteRange; @@ -4866,13 +4916,13 @@ gtk_paint_expander (GtkStyle *style, const gchar *detail, gint x, gint y, - gboolean is_open) + GtkExpanderStyle expander_style) { g_return_if_fail (GTK_IS_STYLE (style)); g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_expander != NULL); GTK_STYLE_GET_CLASS (style)->draw_expander (style, window, state_type, area, - widget, detail, x, y, is_open); + widget, detail, x, y, expander_style); } void diff --git a/gtk/gtkstyle.h b/gtk/gtkstyle.h index e49e4704b2..291dfdc392 100644 --- a/gtk/gtkstyle.h +++ b/gtk/gtkstyle.h @@ -379,7 +379,7 @@ struct _GtkStyleClass const gchar *detail, gint x, gint y, - gboolean is_open); + GtkExpanderStyle expander_style); void (*draw_layout) (GtkStyle *style, GdkWindow *window, GtkStateType state_type, @@ -587,7 +587,7 @@ void gtk_draw_expander (GtkStyle *style, GtkStateType state_type, gint x, gint y, - gboolean is_open); + GtkExpanderStyle expander_style); void gtk_draw_layout (GtkStyle *style, GdkWindow *window, GtkStateType state_type, @@ -804,7 +804,7 @@ void gtk_paint_expander (GtkStyle *style, const gchar *detail, gint x, gint y, - gboolean is_open); + GtkExpanderStyle expander_style); void gtk_paint_layout (GtkStyle *style, GdkWindow *window, GtkStateType state_type, diff --git a/gtk/gtktreeprivate.h b/gtk/gtktreeprivate.h index 9ca4240c8d..bf76f19645 100644 --- a/gtk/gtktreeprivate.h +++ b/gtk/gtktreeprivate.h @@ -121,6 +121,11 @@ struct _GtkTreeViewPrivate GtkRBNode *prelight_node; GtkRBTree *prelight_tree; + /* The node that's currently being collapsed or expanded */ + GtkRBNode *expanded_collapsed_node; + GtkRBTree *expanded_collapsed_tree; + guint expand_collapse_timeout; + /* Selection information */ GtkTreeSelection *selection; diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c index ea140fd9aa..50594b51bb 100644 --- a/gtk/gtktreeview.c +++ b/gtk/gtktreeview.c @@ -47,7 +47,7 @@ #define SCROLL_EDGE_SIZE 15 - +#define EXPANDER_EXTRA_PADDING 4 /* The "background" areas of all rows/cells add up to cover the entire tree. * The background includes all inter-row and inter-cell spacing. @@ -276,6 +276,10 @@ static void gtk_tree_view_queue_draw_node (GtkTreeView *tree_view, static void gtk_tree_view_queue_draw_path (GtkTreeView *tree_view, GtkTreePath *path, GdkRectangle *clip_rect); +static void gtk_tree_view_queue_draw_arrow (GtkTreeView *tree_view, + GtkRBTree *tree, + GtkRBNode *node, + GdkRectangle *clip_rect); static void gtk_tree_view_draw_arrow (GtkTreeView *tree_view, GtkRBTree *tree, GtkRBNode *node, @@ -513,30 +517,20 @@ gtk_tree_view_class_init (GtkTreeViewClass *class) /* Style properties */ /* the width of the column resize windows */ -#define _TREE_VIEW_EXPANDER_WIDTH 14 -#define _TREE_VIEW_EXPANDER_HEIGHT 14 +#define _TREE_VIEW_EXPANDER_SIZE 10 #define _TREE_VIEW_VERTICAL_SEPARATOR 2 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 0 gtk_widget_class_install_style_property (widget_class, - g_param_spec_int ("expander_width", - _("Expander Width"), - _("Width of the expander arrow"), + g_param_spec_int ("expander_size", + _("Expander Size"), + _("Size of the expander arrow"), 0, G_MAXINT, - _TREE_VIEW_EXPANDER_WIDTH, + _TREE_VIEW_EXPANDER_SIZE, G_PARAM_READABLE)); - + gtk_widget_class_install_style_property (widget_class, - g_param_spec_int ("expander_height", - _("Expander Height"), - _("Height of the expander arrow"), - 4, - G_MAXINT, - _TREE_VIEW_EXPANDER_HEIGHT, - G_PARAM_READABLE)); - - gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("vertical_separator", _("Vertical Separator Width"), _("Vertical space between cells"), @@ -544,8 +538,8 @@ gtk_tree_view_class_init (GtkTreeViewClass *class) G_MAXINT, _TREE_VIEW_VERTICAL_SEPARATOR, G_PARAM_READABLE)); - - gtk_widget_class_install_style_property (widget_class, + + gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("horizontal_separator", _("Horizontal Separator Width"), _("Horizontal space between cells"), @@ -822,7 +816,11 @@ gtk_tree_view_init (GtkTreeView *tree_view) GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS); tree_view->priv->flags = GTK_TREE_VIEW_IS_LIST | GTK_TREE_VIEW_SHOW_EXPANDERS | GTK_TREE_VIEW_DRAW_KEYFOCUS | GTK_TREE_VIEW_HEADERS_VISIBLE; - gtk_widget_style_get (GTK_WIDGET (tree_view), "expander_width", &tree_view->priv->tab_offset, NULL); + gtk_widget_style_get (GTK_WIDGET (tree_view), "expander_size", &tree_view->priv->tab_offset, NULL); + + /* We need some padding */ + tree_view->priv->tab_offset += EXPANDER_EXTRA_PADDING; + tree_view->priv->n_columns = 0; tree_view->priv->header_height = 1; tree_view->priv->x_drag = 0; @@ -1219,6 +1217,12 @@ gtk_tree_view_unrealize (GtkWidget *widget) tree_view->priv->open_dest_timeout = 0; } + if (tree_view->priv->expand_collapse_timeout != 0) + { + gtk_timeout_remove (tree_view->priv->expand_collapse_timeout); + tree_view->priv->expand_collapse_timeout = 0; + } + for (list = tree_view->priv->columns; list; list = list->next) _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data)); @@ -1570,7 +1574,7 @@ gtk_tree_view_button_press (GtkWidget *widget, } gtk_tree_view_real_set_cursor (tree_view, path, TRUE); - + if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) { if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT)) @@ -1784,7 +1788,7 @@ coords_are_over_arrow (GtkTreeView *tree_view, arrow.width = x2 - arrow.x; return (x >= arrow.x && - x < (arrow.x + arrow.height) && + x < (arrow.x + arrow.width) && y >= arrow.y && y < (arrow.y + arrow.height)); } @@ -1849,7 +1853,7 @@ ensure_unprelighted (GtkTreeView *tree_view) /* Our motion arrow is either a box (in the case of the original spot) - * or an arrow. It is expander_width wide. + * or an arrow. It is expander_size wide. */ /* * 11111111111111 @@ -1952,13 +1956,14 @@ gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view) gint i, j = 1; GdkGC *gc; GdkColor col; - gint expander_width; + gint expander_size; gtk_widget_style_get (widget, - "expander_height", &width, - "expander_width", &expander_width, + "expander_size", &expander_size, NULL); + width = expander_size; + /* Get x, y, width, height of arrow */ if (reorder->left_column) { @@ -1972,8 +1977,8 @@ gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view) x -= width/2; height = reorder->right_column->button->allocation.height; } - y -= expander_width/2; /* The arrow takes up only half the space */ - height += expander_width; + y -= expander_size/2; /* The arrow takes up only half the space */ + height += expander_size; /* Create the new window */ if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW) @@ -2026,13 +2031,14 @@ gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view) gint i, j = 1; GdkGC *gc; GdkColor col; - gint expander_height; + gint expander_size; gtk_widget_style_get (widget, - "expander_height", &expander_height, - "expander_width", &width, + "expander_size", &expander_size, NULL); + width = expander_size; + /* Get x, y, width, height of arrow */ width = width/2; /* remember, the arrow only takes half the available width */ gdk_window_get_origin (widget->window, &x, &y); @@ -2044,8 +2050,8 @@ gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view) else height = reorder->right_column->button->allocation.height; - y -= expander_height; - height += 2*expander_height; + y -= expander_size; + height += 2*expander_size; /* Create the new window */ if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT && @@ -2074,7 +2080,7 @@ gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view) /* Draw the 2 arrows as per above */ col.pixel = 0; gdk_gc_set_foreground (gc, &col); - j = expander_height; + j = expander_size; for (i = 0; i < width; i ++) { gint k; @@ -2083,8 +2089,8 @@ gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view) else k = i; gdk_draw_line (mask, gc, k, j, k, height - j); - gdk_draw_line (mask, gc, k, 0, k, expander_height - j); - gdk_draw_line (mask, gc, k, height, k, height - expander_height + j); + gdk_draw_line (mask, gc, k, 0, k, expander_size - j); + gdk_draw_line (mask, gc, k, height, k, height - expander_size + j); j--; } gdk_gc_destroy (gc); @@ -2309,7 +2315,7 @@ gtk_tree_view_draw_focus (GtkWidget *widget) tree_view = GTK_TREE_VIEW (widget); - gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL); + gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL); if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS)) return; @@ -2360,6 +2366,7 @@ gtk_tree_view_draw_focus (GtkWidget *widget) width += 2; height += 2; + x = cell_area.x + x_offset - 1; y = cell_area.y + y_offset - 1 + vertical_separator/2; } @@ -2369,7 +2376,7 @@ gtk_tree_view_draw_focus (GtkWidget *widget) tree_view->priv->bin_window, NULL, widget, - "add-mode", + "treeview", x, y, width, height); gtk_tree_path_free (cursor_path); @@ -2658,7 +2665,7 @@ gtk_tree_view_bin_expose (GtkWidget *widget, tree_view->priv->bin_window, NULL, widget, - "add-mode", + "treeview-drop-indicator", 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node), width - 1, BACKGROUND_HEIGHT (node) - 1); @@ -4467,6 +4474,18 @@ gtk_tree_view_deleted (GtkTreeModel *model, /* Ensure we don't have a dangling pointer to a dead node */ ensure_unprelighted (tree_view); + /* If we have a node expanded/collapsed timeout, remove it */ + if (tree_view->priv->expand_collapse_timeout != 0) + { + gtk_timeout_remove (tree_view->priv->expand_collapse_timeout); + tree_view->priv->expand_collapse_timeout = 0; + + /* Reset node */ + GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED); + GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED); + tree_view->priv->expanded_collapsed_node = NULL; + } + if (tree_view->priv->destroy_count_func) { gint child_count = 0; @@ -4739,8 +4758,9 @@ gtk_tree_view_insert_iter_height (GtkTreeView *tree_view, GList *list; gint max_height = 0; gint vertical_separator; - - gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL); + + gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL); + /* do stuff with node */ for (list = tree_view->priv->columns; list; list = list->next) { @@ -4825,10 +4845,10 @@ gtk_tree_view_calc_size (GtkTreeView *tree_view, GtkTreeViewColumn *column; gint max_height; gint vertical_separator; - + TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL); - gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL); + gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL); temp = tree->root; while (temp->left != tree->nil) @@ -4886,7 +4906,7 @@ gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view, GList *list; gboolean retval = FALSE; gint tmpheight; - + if (height) *height = 0; @@ -5460,6 +5480,37 @@ _gtk_tree_view_column_start_drag (GtkTreeView *tree_view, } static void +gtk_tree_view_queue_draw_arrow (GtkTreeView *tree_view, + GtkRBTree *tree, + GtkRBNode *node, + GdkRectangle *clip_rect) +{ + GdkRectangle rect; + + if (!GTK_WIDGET_REALIZED (tree_view)) + return; + + rect.x = 0; + rect.width = MAX (tree_view->priv->tab_offset, GTK_WIDGET (tree_view)->allocation.width); + + rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node); + rect.height = BACKGROUND_HEIGHT (node); + + if (clip_rect) + { + GdkRectangle new_rect; + + gdk_rectangle_intersect (clip_rect, &rect, &new_rect); + + gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE); + } + else + { + gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE); + } +} + +static void gtk_tree_view_queue_draw_node (GtkTreeView *tree_view, GtkRBTree *tree, GtkRBNode *node, @@ -5518,11 +5569,12 @@ gtk_tree_view_draw_arrow (GtkTreeView *tree_view, GtkWidget *widget; gint x_offset = 0; gint vertical_separator; - gint expander_height; - + gint expander_size; + GtkExpanderStyle expander_style; + gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, - "expander_height", &expander_height, + "expander_size", &expander_size, NULL); if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT)) @@ -5534,7 +5586,7 @@ gtk_tree_view_draw_arrow (GtkTreeView *tree_view, area.x = x_offset; area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator); - area.width = tree_view->priv->tab_offset - 2; + area.width = expander_size + 2; area.height = CELL_HEIGHT (node, vertical_separator); if (node == tree_view->priv->button_pressed_node) @@ -5554,15 +5606,24 @@ gtk_tree_view_draw_arrow (GtkTreeView *tree_view, state = GTK_STATE_NORMAL; } + if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED)) + expander_style = GTK_EXPANDER_SEMI_EXPANDED; + else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED)) + expander_style = GTK_EXPANDER_SEMI_COLLAPSED; + else if (node->children != NULL) + expander_style = GTK_EXPANDER_EXPANDED; + else + expander_style = GTK_EXPANDER_COLLAPSED; + gtk_paint_expander (widget->style, tree_view->priv->bin_window, state, &area, widget, "treeview", - area.x, - (area.y + (area.height - expander_height) / 2 - (area.height + 1) % 2), - node->children != NULL); + area.x + area.width / 2, + area.y + area.height / 2, + expander_style); } @@ -7053,6 +7114,76 @@ gtk_tree_view_collapse_all_helper (GtkRBTree *tree, } } +/* Timeout to animate the expander during expands and collapses */ +static gboolean +expand_collapse_timeout (gpointer data) +{ + GtkTreeView *tree_view = data; + GtkRBNode *node; + GtkRBTree *tree; + gboolean expanding; + gboolean redraw; + + GDK_THREADS_ENTER (); + + redraw = FALSE; + expanding = TRUE; + + node = tree_view->priv->expanded_collapsed_node; + tree = tree_view->priv->expanded_collapsed_tree; + + if (node->children == NULL) + expanding = FALSE; + + if (expanding) + { + if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED)) + { + GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED); + GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED); + + redraw = TRUE; + + } + else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED)) + { + GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED); + + redraw = TRUE; + } + } + else + { + if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED)) + { + GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED); + GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED); + + redraw = TRUE; + } + else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED)) + { + GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED); + + redraw = TRUE; + + } + } + + if (redraw) + { + gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL); + + GDK_THREADS_LEAVE (); + + return TRUE; + } + + GDK_THREADS_LEAVE (); + + return FALSE; +} + /** * gtk_tree_view_collapse_all: * @tree_view: A #GtkTreeView. @@ -7117,6 +7248,21 @@ gtk_tree_view_real_expand_row (GtkTreeView *tree_view, open_all, GTK_WIDGET_REALIZED (tree_view)); + if (tree_view->priv->expand_collapse_timeout) + gtk_timeout_remove (tree_view->priv->expand_collapse_timeout); + + if (tree_view->priv->expanded_collapsed_node != NULL) + { + GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED); + GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED); + } + + tree_view->priv->expand_collapse_timeout = gtk_timeout_add (50, expand_collapse_timeout, tree_view); + tree_view->priv->expanded_collapsed_node = node; + tree_view->priv->expanded_collapsed_tree = tree; + + GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED); + if (GTK_WIDGET_MAPPED (tree_view)) { gtk_widget_queue_draw (GTK_WIDGET (tree_view)); @@ -7199,6 +7345,21 @@ gtk_tree_view_real_collapse_row (GtkTreeView *tree_view, g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed", 0); _gtk_rbtree_remove (node->children); + if (tree_view->priv->expand_collapse_timeout) + gtk_timeout_remove (tree_view->priv->expand_collapse_timeout); + + if (tree_view->priv->expanded_collapsed_node != NULL) + { + GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED); + GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED); + } + + tree_view->priv->expand_collapse_timeout = gtk_timeout_add (50, expand_collapse_timeout, tree_view); + tree_view->priv->expanded_collapsed_node = node; + tree_view->priv->expanded_collapsed_tree = tree; + + GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED); + if (GTK_WIDGET_MAPPED (tree_view)) { gtk_widget_queue_draw (GTK_WIDGET (tree_view)); |