Compare commits

...

10 Commits

Author SHA1 Message Date
Carlos Garnacho
1914b0ce9e gtk-demo: Remove now useless code in treeview/list-store demo
There's no need anymore to pulse on spinner cellrenderers, so
demo this with several rows, and no timeouts to pulse on a row.
2011-05-27 14:26:35 +02:00
Carlos Garnacho
f1bf62c1b0 treeview: use GtkCellArea animation APIs
GtkTreeViewColumn has been added some helper API to interface
with GtkTreeView. The tree view handles (recursive) cancellation
of animations if:

  - A row is deleted
  - A row is collapsed
  - A row is scrolled outside of the visible range
  - The model is removed
2011-05-27 14:26:35 +02:00
Carlos Garnacho
42a6a49281 iconview: Use GtkCellArea animation APIs
This enables transition animations for cell renderers in iconviews
2011-05-27 13:25:53 +02:00
Carlos Garnacho
5827f8d21f cellrendererspinner: Modify to use GtkStyleContext
the ::pulse property has been deprecated, since now the animation
is handled by the theme itself, as it happens with GtkSpinner.
2011-05-27 13:25:53 +02:00
Carlos Garnacho
7742259a1c cellrenderertoggle: Implement methods to handle animations
By implementing get_current_state() and apply_style(), GtkCellArea
has all the necessary information to handle state transitions in
toggle cell renderers.
2011-05-27 13:25:53 +02:00
Carlos Garnacho
d306a6216b cellarea: Add API to keep track of state transitions
GtkCellArea is now able to cache cell renderer states for a number
of rows, starting animations if needed. those cached states can
be told to be forgotten by the rendering widget, in case a row
is hidden, destroyed, or not viewable anymore.
2011-05-27 13:25:53 +02:00
Carlos Garnacho
cc8463c665 cellrenderer: Add gtk_cell_renderer_apply_style()
Through the vfunc, cell renderer implementations may provide
the style properties (classes, regions and such) applying to
a cell renderer.
2011-05-27 13:25:52 +02:00
Carlos Garnacho
8b2dce540a cellrenderer: add get_current_state() vmethod
This method is called in gtk_cell_renderer_get_state() and
will be implemented by cell renderers to return the GtkStateFlags
applying to the current cell renderer implementation state (i.e.
a checked GtkCellRendererToggle would return GTK_STATE_FLAG_ACTIVE)
2011-05-27 13:25:52 +02:00
Carlos Garnacho
7e6cd377f9 stylecontext: only coalesce transitions after they're referenced by a draw()
If after calling _gtk_style_context_invalidate_animation_areas(), a widget
happened to draw() with a clipping area that left out some transition, it
would be left stuck with a NULL invalidation area.
2011-05-27 13:25:52 +02:00
Carlos Garnacho
95118d235b stylecontext: store device space coordinates for transitions
This is so transitions take into account user-space transforms
on the cairo_t at the gtk_render_*() call time.
2011-05-27 13:25:52 +02:00
13 changed files with 849 additions and 139 deletions

View File

@@ -11,11 +11,11 @@
static GtkWidget *window = NULL;
static GtkTreeModel *model = NULL;
static guint timeout = 0;
typedef struct
{
const gboolean fixed;
const gboolean active;
const guint number;
const gchar *severity;
const gchar *description;
@@ -28,7 +28,6 @@ enum
COLUMN_NUMBER,
COLUMN_SEVERITY,
COLUMN_DESCRIPTION,
COLUMN_PULSE,
COLUMN_ICON,
COLUMN_ACTIVE,
COLUMN_SENSITIVE,
@@ -37,49 +36,22 @@ enum
static Bug data[] =
{
{ FALSE, 60482, "Normal", "scrollable notebooks and hidden tabs" },
{ FALSE, 60620, "Critical", "gdk_window_clear_area (gdkwindow-win32.c) is not thread-safe" },
{ FALSE, 50214, "Major", "Xft support does not clean up correctly" },
{ TRUE, 52877, "Major", "GtkFileSelection needs a refresh method. " },
{ FALSE, 56070, "Normal", "Can't click button after setting in sensitive" },
{ TRUE, 56355, "Normal", "GtkLabel - Not all changes propagate correctly" },
{ FALSE, 50055, "Normal", "Rework width/height computations for TreeView" },
{ FALSE, 58278, "Normal", "gtk_dialog_set_response_sensitive () doesn't work" },
{ FALSE, 55767, "Normal", "Getters for all setters" },
{ FALSE, 56925, "Normal", "Gtkcalender size" },
{ FALSE, 56221, "Normal", "Selectable label needs right-click copy menu" },
{ TRUE, 50939, "Normal", "Add shift clicking to GtkTextView" },
{ FALSE, 6112, "Enhancement","netscape-like collapsable toolbars" },
{ FALSE, 1, "Normal", "First bug :=)" },
{ FALSE, TRUE, 60482, "Normal", "scrollable notebooks and hidden tabs" },
{ FALSE, FALSE, 60620, "Critical", "gdk_window_clear_area (gdkwindow-win32.c) is not thread-safe" },
{ FALSE, FALSE, 50214, "Major", "Xft support does not clean up correctly" },
{ TRUE, FALSE, 52877, "Major", "GtkFileSelection needs a refresh method. " },
{ FALSE, TRUE, 56070, "Normal", "Can't click button after setting in sensitive" },
{ TRUE, FALSE, 56355, "Normal", "GtkLabel - Not all changes propagate correctly" },
{ FALSE, FALSE, 50055, "Normal", "Rework width/height computations for TreeView" },
{ FALSE, TRUE, 58278, "Normal", "gtk_dialog_set_response_sensitive () doesn't work" },
{ FALSE, FALSE, 55767, "Normal", "Getters for all setters" },
{ FALSE, TRUE, 56925, "Normal", "Gtkcalender size" },
{ FALSE, TRUE, 56221, "Normal", "Selectable label needs right-click copy menu" },
{ TRUE, FALSE, 50939, "Normal", "Add shift clicking to GtkTextView" },
{ FALSE, FALSE, 6112, "Enhancement","netscape-like collapsable toolbars" },
{ FALSE, FALSE, 1, "Normal", "First bug :=)" },
};
static gboolean
spinner_timeout (gpointer data)
{
GtkTreeIter iter;
guint pulse;
if (model == NULL)
return FALSE;
gtk_tree_model_get_iter_first (model, &iter);
gtk_tree_model_get (model, &iter,
COLUMN_PULSE, &pulse,
-1);
if (pulse == G_MAXUINT)
pulse = 0;
else
pulse++;
gtk_list_store_set (GTK_LIST_STORE (model),
&iter,
COLUMN_PULSE, pulse,
COLUMN_ACTIVE, TRUE,
-1);
return TRUE;
}
static GtkTreeModel *
create_model (void)
{
@@ -93,7 +65,6 @@ create_model (void)
G_TYPE_UINT,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_UINT,
G_TYPE_STRING,
G_TYPE_BOOLEAN,
G_TYPE_BOOLEAN);
@@ -118,9 +89,8 @@ create_model (void)
COLUMN_NUMBER, data[i].number,
COLUMN_SEVERITY, data[i].severity,
COLUMN_DESCRIPTION, data[i].description,
COLUMN_PULSE, 0,
COLUMN_ICON, icon_name,
COLUMN_ACTIVE, FALSE,
COLUMN_ACTIVE, data[i].active,
COLUMN_SENSITIVE, sensitive,
-1);
}
@@ -209,12 +179,10 @@ add_columns (GtkTreeView *treeview)
renderer = gtk_cell_renderer_spinner_new ();
column = gtk_tree_view_column_new_with_attributes ("Spinning",
renderer,
"pulse",
COLUMN_PULSE,
"active",
COLUMN_ACTIVE,
NULL);
gtk_tree_view_column_set_sort_column_id (column, COLUMN_PULSE);
gtk_tree_view_column_set_sort_column_id (column, COLUMN_ACTIVE);
gtk_tree_view_append_column (treeview, column);
/* column for symbolic icon */
@@ -238,11 +206,7 @@ window_closed (GtkWidget *widget,
{
model = NULL;
window = NULL;
if (timeout != 0)
{
g_source_remove (timeout);
timeout = 0;
}
return FALSE;
}
@@ -303,22 +267,11 @@ do_list_store (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
{
gtk_widget_show_all (window);
if (timeout == 0) {
/* FIXME this should use the animation-duration instead */
timeout = g_timeout_add (80, spinner_timeout, NULL);
}
}
gtk_widget_show_all (window);
else
{
gtk_widget_destroy (window);
window = NULL;
if (timeout != 0)
{
g_source_remove (timeout);
timeout = 0;
}
}
return window;

View File

@@ -4475,6 +4475,8 @@ gtk_cell_area_activate_cell
gtk_cell_area_stop_editing
gtk_cell_area_inner_cell_area
gtk_cell_area_request_renderer
gtk_cell_area_set_animation_id
gtk_cell_area_forget_animation_id
<SUBSECTION Standard>
GTK_CELL_AREA
GTK_IS_CELL_AREA
@@ -4566,6 +4568,7 @@ gtk_cell_renderer_set_alignment
gtk_cell_renderer_get_padding
gtk_cell_renderer_set_padding
gtk_cell_renderer_get_state
gtk_cell_renderer_apply_style
gtk_cell_renderer_is_activatable
<SUBSECTION Width-for-height>

View File

@@ -365,6 +365,7 @@
#include "gtkcellarea.h"
#include "gtkcellareacontext.h"
#include "gtkmarshalers.h"
#include "gtkanimationdescription.h"
#include "gtkprivate.h"
#include <gobject/gvaluecollector.h>
@@ -531,6 +532,17 @@ typedef struct {
GtkCellLayout *proxy;
} CellInfo;
typedef struct {
GtkCellRenderer *renderer;
gpointer anim_id;
guint rendered : 1;
} AnimationKey;
typedef struct {
GtkStyleContext *context;
gpointer anim_id;
} ForgetAnimationData;
static CellInfo *cell_info_new (GtkCellLayoutDataFunc func,
gpointer data,
GDestroyNotify destroy);
@@ -542,6 +554,11 @@ static void cell_attribute_free (CellAttribute *attribute);
static gint cell_attribute_find (CellAttribute *cell_attribute,
const gchar *attribute);
static void animation_key_free (AnimationKey *key);
static guint animation_key_hash (gconstpointer p);
static gboolean animation_key_equal (gconstpointer p1,
gconstpointer p2);
/* Internal functions/signal emissions */
static void gtk_cell_area_add_editable (GtkCellArea *area,
GtkCellRenderer *renderer,
@@ -591,6 +608,10 @@ struct _GtkCellAreaPrivate
/* Tracking which cells are focus siblings of focusable cells */
GHashTable *focus_siblings;
/* GtkStateFlags tracking for transitions */
gpointer parent_anim_id;
GHashTable *cell_states;
};
enum {
@@ -643,6 +664,10 @@ gtk_cell_area_init (GtkCellArea *area)
NULL,
(GDestroyNotify)g_list_free);
priv->cell_states = g_hash_table_new_full (animation_key_hash,
animation_key_equal,
(GDestroyNotify) animation_key_free,
NULL);
priv->focus_cell = NULL;
priv->edited_cell = NULL;
priv->edit_widget = NULL;
@@ -933,6 +958,7 @@ gtk_cell_area_finalize (GObject *object)
*/
g_hash_table_destroy (priv->cell_info);
g_hash_table_destroy (priv->focus_siblings);
g_hash_table_destroy (priv->cell_states);
g_free (priv->current_path);
@@ -1124,6 +1150,192 @@ gtk_cell_area_real_event (GtkCellArea *area,
return retval;
}
static AnimationKey *
animation_key_new (GtkCellRenderer *renderer,
gpointer anim_id)
{
AnimationKey *key;
key = g_slice_new (AnimationKey);
key->renderer = renderer;
key->anim_id = anim_id;
key->rendered = FALSE;
return key;
}
static void
animation_key_free (AnimationKey *key)
{
g_slice_free (AnimationKey, key);
}
static guint
animation_key_hash (gconstpointer p)
{
const AnimationKey *key = p;
guint h;
h = GPOINTER_TO_UINT (key->anim_id) < 16;
h |= GPOINTER_TO_UINT (key->renderer) & 0xFFFF;
return h;
}
static gboolean
animation_key_equal (gconstpointer p1,
gconstpointer p2)
{
const AnimationKey *key1, *key2;
key1 = p1;
key2 = p2;
return (key1->renderer == key2->renderer &&
key1->anim_id == key2->anim_id);
}
static void
_gtk_cell_area_set_state (GtkCellArea *area,
GtkCellRenderer *renderer,
gpointer anim_id,
GtkStateFlags flags)
{
GtkCellAreaPrivate *priv;
AnimationKey *key;
priv = area->priv;
key = animation_key_new (renderer, anim_id);
g_hash_table_insert (priv->cell_states, key, GUINT_TO_POINTER (flags));
}
static AnimationKey *
_gtk_cell_area_lookup_state (GtkCellArea *area,
GtkCellRenderer *renderer,
gpointer anim_id,
GtkStateFlags *flags)
{
GtkCellAreaPrivate *priv;
gpointer orig_key, value;
AnimationKey key;
priv = area->priv;
key.renderer = renderer;
key.anim_id = anim_id;
if (!g_hash_table_lookup_extended (priv->cell_states, &key, &orig_key, &value))
return NULL;
if (flags)
*flags = GPOINTER_TO_UINT (value);
return orig_key;
}
static AnimationKey *
apply_renderer_transition (GtkCellArea *area,
GdkWindow *window,
GtkWidget *widget,
GtkCellRendererState cell_state,
GtkCellRenderer *renderer)
{
GtkCellAreaPrivate *priv;
GtkStateFlags state, old_state, flag;
GtkStyleContext *style_context;
AnimationKey *anim_key;
gboolean is_cached;
priv = area->priv;
if (!priv->parent_anim_id)
return NULL;
state = gtk_cell_renderer_get_state (renderer, widget, cell_state);
anim_key = _gtk_cell_area_lookup_state (area, renderer, priv->parent_anim_id, &old_state);
is_cached = (anim_key != NULL);
if (is_cached && state == old_state)
return anim_key;
else
{
_gtk_cell_area_set_state (area, renderer, priv->parent_anim_id, state);
/* Fetch the just created anim ID if needed */
if (!anim_key)
anim_key = _gtk_cell_area_lookup_state (area, renderer, priv->parent_anim_id, NULL);
}
style_context = gtk_widget_get_style_context (widget);
flag = GTK_STATE_FLAG_FOCUSED;
while (flag)
{
GtkAnimationDescription *animation_desc;
if (is_cached && ((state & flag) == (old_state & flag)))
{
/* Flag didn't change since it was last cached */
flag >>= 1;
continue;
}
gtk_style_context_get (style_context, flag,
"transition", &animation_desc,
NULL);
if (animation_desc)
{
/* Only notify state transition on changes over previously cached
* states (Which means a viewable renderer has changed) and those
* with a looping animation.
*/
if (is_cached ||
((state & flag) != 0 &&
_gtk_animation_description_get_loop (animation_desc)))
{
GtkStateType anim_state;
switch (flag)
{
case GTK_STATE_FLAG_ACTIVE:
anim_state = GTK_STATE_ACTIVE;
break;
case GTK_STATE_FLAG_PRELIGHT:
anim_state = GTK_STATE_PRELIGHT;
break;
case GTK_STATE_FLAG_SELECTED:
anim_state = GTK_STATE_SELECTED;
break;
case GTK_STATE_FLAG_INSENSITIVE:
anim_state = GTK_STATE_INSENSITIVE;
break;
case GTK_STATE_FLAG_INCONSISTENT:
anim_state = GTK_STATE_INCONSISTENT;
break;
case GTK_STATE_FLAG_FOCUSED:
anim_state = GTK_STATE_FOCUSED;
break;
default:
g_assert_not_reached ();
break;
}
gtk_style_context_notify_state_change (style_context, window,
anim_key, anim_state,
(state & flag) != 0);
}
_gtk_animation_description_unref (animation_desc);
}
flag >>= 1;
}
return anim_key;
}
static gboolean
render_cell (GtkCellRenderer *renderer,
const GdkRectangle *cell_area,
@@ -1133,10 +1345,33 @@ render_cell (GtkCellRenderer *renderer,
GtkCellRenderer *focus_cell;
GtkCellRendererState flags;
GdkRectangle inner_area;
GtkStyleContext *style_context;
GdkEventExpose *expose;
AnimationKey *anim_key = NULL;
focus_cell = gtk_cell_area_get_focus_cell (data->area);
flags = data->render_flags;
expose = _gtk_cairo_get_event (data->cr);
style_context = gtk_widget_get_style_context (data->widget);
gtk_style_context_save (style_context);
gtk_cell_renderer_apply_style (renderer, style_context);
if (expose)
anim_key = apply_renderer_transition (data->area, expose->window, data->widget,
flags, renderer);
if (anim_key)
{
/* Mark this animation as rendered, this is so we can keep
* track after rendering of stale states, due to removed or
* hidden cell renderers.
*/
anim_key->rendered = TRUE;
gtk_style_context_push_animatable_region (style_context, anim_key);
}
gtk_cell_area_inner_cell_area (data->area, data->widget, cell_area, &inner_area);
if ((flags & GTK_CELL_RENDERER_FOCUSED) &&
@@ -1174,9 +1409,46 @@ render_cell (GtkCellRenderer *renderer,
gtk_cell_renderer_render (renderer, data->cr, data->widget,
cell_background, &inner_area, flags);
if (anim_key)
gtk_style_context_pop_animatable_region (style_context);
gtk_style_context_restore (style_context);
return FALSE;
}
static gboolean
maybe_dispose_animation_foreach (gpointer key,
gpointer value,
gpointer user_data)
{
AnimationKey *anim_key = key;
CellRenderData *render_data = user_data;
GtkCellAreaPrivate *priv = render_data->area->priv;
if (anim_key->anim_id != priv->parent_anim_id)
return FALSE;
/* Stop tracking all animations that weren't rendered
* this time, this usually means the cell renderer has
* been hidden or removed.
*/
if (!anim_key->rendered)
{
GtkStyleContext *context;
context = gtk_widget_get_style_context (render_data->widget);
gtk_style_context_cancel_animations (context, anim_key);
return TRUE;
}
else
{
anim_key->rendered = FALSE;
return FALSE;
}
}
static void
gtk_cell_area_real_render (GtkCellArea *area,
GtkCellAreaContext *context,
@@ -1187,6 +1459,8 @@ gtk_cell_area_real_render (GtkCellArea *area,
GtkCellRendererState flags,
gboolean paint_focus)
{
GtkCellAreaPrivate *priv;
GtkStyleContext *style_context;
CellRenderData render_data =
{
area,
@@ -1210,9 +1484,17 @@ gtk_cell_area_real_render (GtkCellArea *area,
!gtk_cell_area_is_activatable (area))
render_data.focus_all = TRUE;
priv = area->priv;
style_context = gtk_widget_get_style_context (widget);
if (priv->parent_anim_id)
gtk_style_context_push_animatable_region (style_context, priv->parent_anim_id);
gtk_cell_area_foreach_alloc (area, context, widget, cell_area, background_area,
(GtkCellAllocCallback)render_cell, &render_data);
g_hash_table_foreach_remove (priv->cell_states, maybe_dispose_animation_foreach, &render_data);
if (render_data.paint_focus &&
render_data.focus_rect.width != 0 &&
render_data.focus_rect.height != 0)
@@ -1238,6 +1520,9 @@ gtk_cell_area_real_render (GtkCellArea *area,
gtk_style_context_restore (style_context);
cairo_restore (cr);
}
if (priv->parent_anim_id)
gtk_style_context_pop_animatable_region (style_context);
}
static void
@@ -3660,3 +3945,85 @@ _gtk_cell_area_set_cell_data_func_with_proxy (GtkCellArea *area,
g_hash_table_insert (priv->cell_info, cell, info);
}
}
/**
* gtk_cell_area_set_animation_id:
* @area: a #GtkCellArea
* @anim_id: identifier for the animatable region, or %NULL.
* See gtk_style_context_notify_state_change().
*
* Sets the identifier for the animatable region affecting the
* subsequent gtk_cell_area_render() call. @area will compose
* internal identificators for each contained cell renderer
* using this information.
*
* Widgets caring about state transitions in #GtkCellArea
* managed rendering should set a different animation
* identificator for each row rendered.
*
* Since: 3.2
**/
void
gtk_cell_area_set_animation_id (GtkCellArea *area,
gpointer anim_id)
{
GtkCellAreaPrivate *priv;
g_return_if_fail (GTK_IS_CELL_AREA (area));
priv = area->priv;
priv->parent_anim_id = anim_id;
}
static gboolean
forget_animation_foreach (gpointer key,
gpointer value,
gpointer user_data)
{
AnimationKey *anim_key = key;
ForgetAnimationData *data = user_data;
if (!data->anim_id ||
anim_key->anim_id == data->anim_id)
{
gtk_style_context_cancel_animations (data->context,
anim_key->anim_id);
return TRUE;
}
else
return FALSE;
}
/**
* gtk_cell_area_forget_animation_id:
* @area: a #GtkCellArea
* @widget: the renderer #GtkWidget
* @anim_id: identifier for the animatable region, or %NULL.
*
* Drops any cached data on an animatable region identifier
* passed through gtk_cell_area_set_animation_id(), and
* cancels any ongoing animation there. A %NULL @anim_id
* will drop every cached state.
*
* Since: 3.2
**/
void
gtk_cell_area_forget_animation_id (GtkCellArea *area,
GtkWidget *widget,
gpointer anim_id)
{
GtkCellAreaPrivate *priv;
GtkStyleContext *context;
ForgetAnimationData data;
g_return_if_fail (GTK_IS_CELL_AREA (area));
g_return_if_fail (GTK_IS_WIDGET (widget));
priv = area->priv;
data.context = gtk_widget_get_style_context (widget);
data.anim_id = anim_id;
g_hash_table_foreach_remove (priv->cell_states,
forget_animation_foreach,
&data);
}

View File

@@ -370,6 +370,14 @@ void gtk_cell_area_attribute_disconnect (GtkCellArea
GtkCellRenderer *renderer,
const gchar *attribute);
/* State tracking */
void gtk_cell_area_set_animation_id (GtkCellArea *area,
gpointer anim_id);
void gtk_cell_area_forget_animation_id (GtkCellArea *area,
GtkWidget *widget,
gpointer anim_id);
/* Cell Properties */
void gtk_cell_area_class_install_cell_property (GtkCellAreaClass *aclass,
guint property_id,

View File

@@ -104,6 +104,7 @@ static void gtk_cell_renderer_real_get_aligned_area (GtkCellRendere
GtkCellRendererState flags,
const GdkRectangle *cell_area,
GdkRectangle *aligned_area);
static GtkStateFlags gtk_cell_renderer_real_get_current_state (GtkCellRenderer *cell);
struct _GtkCellRendererPrivate
@@ -200,6 +201,7 @@ gtk_cell_renderer_class_init (GtkCellRendererClass *class)
class->get_preferred_width_for_height = gtk_cell_renderer_real_get_preferred_width_for_height;
class->get_preferred_height_for_width = gtk_cell_renderer_real_get_preferred_height_for_width;
class->get_aligned_area = gtk_cell_renderer_real_get_aligned_area;
class->get_current_state = gtk_cell_renderer_real_get_current_state;
/**
* GtkCellRenderer::editing-canceled:
@@ -1324,6 +1326,11 @@ gtk_cell_renderer_real_get_aligned_area (GtkCellRenderer *cell,
aligned_area->y += y_offset;
}
static GtkStateFlags
gtk_cell_renderer_real_get_current_state (GtkCellRenderer *cell)
{
return GTK_STATE_FLAG_NORMAL;
}
/* An internal convenience function for some containers to peek at the
* cell alignment in a target allocation (used to draw focus and align
@@ -1700,13 +1707,19 @@ gtk_cell_renderer_get_state (GtkCellRenderer *cell,
g_return_val_if_fail (!cell || GTK_IS_CELL_RENDERER (cell), 0);
g_return_val_if_fail (!widget || GTK_IS_WIDGET (widget), 0);
if ((widget && !gtk_widget_is_sensitive (widget)) ||
(cell && !gtk_cell_renderer_get_sensitive (cell)) ||
(cell_state & GTK_CELL_RENDERER_INSENSITIVE) != 0)
if (cell)
{
state |= GTK_STATE_FLAG_INSENSITIVE;
state = GTK_CELL_RENDERER_GET_CLASS (cell)->get_current_state (cell);
if (!gtk_cell_renderer_get_sensitive (cell))
state |= GTK_STATE_FLAG_INSENSITIVE;
}
else
if ((widget && !gtk_widget_is_sensitive (widget)) ||
(cell_state & GTK_CELL_RENDERER_INSENSITIVE) != 0)
state |= GTK_STATE_FLAG_INSENSITIVE;
if ((state & GTK_STATE_FLAG_INSENSITIVE) == 0)
{
if ((widget && gtk_widget_has_focus (widget)) &&
(cell_state & GTK_CELL_RENDERER_FOCUSED) != 0)
@@ -1721,3 +1734,25 @@ gtk_cell_renderer_get_state (GtkCellRenderer *cell,
return state;
}
/**
* gtk_cell_renderer_apply_style:
* @cell: a #GtkCellRenderer
* @style_context: a #GtkStyleContext
*
* Applies into @style_context the style properties affecting
* @cell. This should be called between a
* gtk_style_context_save()/gtk_style_context_restore() pair.
*
* Since: 3.2
**/
void
gtk_cell_renderer_apply_style (GtkCellRenderer *cell,
GtkStyleContext *style_context)
{
g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
g_return_if_fail (GTK_IS_STYLE_CONTEXT (style_context));
if (GTK_CELL_RENDERER_GET_CLASS (cell)->apply_style)
GTK_CELL_RENDERER_GET_CLASS (cell)->apply_style (cell, style_context);
}

View File

@@ -150,11 +150,13 @@ struct _GtkCellRendererClass
GtkCellEditable *editable,
const gchar *path);
GtkStateFlags (* get_current_state) (GtkCellRenderer *cell);
void (* apply_style) (GtkCellRenderer *cell,
GtkStyleContext *style_context);
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
};
GType gtk_cell_renderer_get_type (void) G_GNUC_CONST;
@@ -265,6 +267,8 @@ void _gtk_cell_renderer_calc_offset (GtkCellRenderer *cell,
GtkStateFlags gtk_cell_renderer_get_state (GtkCellRenderer *cell,
GtkWidget *widget,
GtkCellRendererState cell_state);
void gtk_cell_renderer_apply_style (GtkCellRenderer *cell,
GtkStyleContext *style_context);
G_END_DECLS

View File

@@ -92,6 +92,10 @@ static void gtk_cell_renderer_spinner_render (GtkCellRenderer *cell,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
GtkCellRendererState flags);
static GtkStateFlags gtk_cell_renderer_spinner_get_current_state (GtkCellRenderer *cell);
static void gtk_cell_renderer_spinner_apply_style (GtkCellRenderer *cell,
GtkStyleContext *context);
G_DEFINE_TYPE (GtkCellRendererSpinner, gtk_cell_renderer_spinner, GTK_TYPE_CELL_RENDERER)
@@ -106,6 +110,8 @@ gtk_cell_renderer_spinner_class_init (GtkCellRendererSpinnerClass *klass)
cell_class->get_size = gtk_cell_renderer_spinner_get_size;
cell_class->render = gtk_cell_renderer_spinner_render;
cell_class->get_current_state = gtk_cell_renderer_spinner_get_current_state;
cell_class->apply_style = gtk_cell_renderer_spinner_apply_style;
/* GtkCellRendererSpinner:active:
*
@@ -130,6 +136,9 @@ gtk_cell_renderer_spinner_class_init (GtkCellRendererSpinnerClass *klass)
* consisting of 12 frames, in 750 milliseconds.
*
* Since: 2.20
*
* Deprecated: 3.2. The ::active property is sufficient, animation
* details are handled by theming.
*/
g_object_class_install_property (object_class,
PROP_PULSE,
@@ -325,7 +334,8 @@ gtk_cell_renderer_spinner_render (GtkCellRenderer *cellr,
{
GtkCellRendererSpinner *cell = GTK_CELL_RENDERER_SPINNER (cellr);
GtkCellRendererSpinnerPrivate *priv = cell->priv;
GtkStateType state;
GtkStyleContext *context;
GtkStateFlags state;
GdkRectangle pix_rect;
GdkRectangle draw_rect;
gint xpad, ypad;
@@ -349,38 +359,45 @@ gtk_cell_renderer_spinner_render (GtkCellRenderer *cellr,
if (!gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect))
return;
state = GTK_STATE_NORMAL;
if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE ||
!gtk_cell_renderer_get_sensitive (cellr))
{
state = GTK_STATE_INSENSITIVE;
}
else
{
if ((flags & GTK_CELL_RENDERER_SELECTED) != 0)
{
if (gtk_widget_has_focus (widget))
state = GTK_STATE_SELECTED;
else
state = GTK_STATE_ACTIVE;
}
else
state = GTK_STATE_PRELIGHT;
}
context = gtk_widget_get_style_context (widget);
gtk_style_context_save (context);
gtk_cell_renderer_apply_style (cellr, context);
state = gtk_cell_renderer_get_state (cellr, widget, flags);
gtk_style_context_set_state (context, state);
cairo_save (cr);
gdk_cairo_rectangle (cr, cell_area);
cairo_clip (cr);
gtk_paint_spinner (gtk_widget_get_style (widget),
cr,
state,
widget,
"cell",
priv->pulse,
draw_rect.x, draw_rect.y,
draw_rect.width, draw_rect.height);
gtk_render_activity (context, cr,
draw_rect.x,
draw_rect.y,
draw_rect.width,
draw_rect.height);
gtk_style_context_restore (context);
cairo_restore (cr);
}
static GtkStateFlags
gtk_cell_renderer_spinner_get_current_state (GtkCellRenderer *cellr)
{
GtkCellRendererSpinner *cell = GTK_CELL_RENDERER_SPINNER (cellr);
GtkCellRendererSpinnerPrivate *priv = cell->priv;
GtkStateFlags state = 0;
if (priv->active)
state |= GTK_STATE_FLAG_ACTIVE;
return state;
}
static void
gtk_cell_renderer_spinner_apply_style (GtkCellRenderer *cell,
GtkStyleContext *context)
{
gtk_style_context_add_class (context, GTK_STYLE_CLASS_SPINNER);
}

View File

@@ -67,6 +67,10 @@ static gboolean gtk_cell_renderer_toggle_activate (GtkCellRenderer *
const GdkRectangle *cell_area,
GtkCellRendererState flags);
static GtkStateFlags gtk_cell_renderer_toggle_get_current_state (GtkCellRenderer *cell);
static void gtk_cell_renderer_toggle_apply_style (GtkCellRenderer *cell,
GtkStyleContext *context);
enum {
TOGGLED,
@@ -133,7 +137,9 @@ gtk_cell_renderer_toggle_class_init (GtkCellRendererToggleClass *class)
cell_class->get_size = gtk_cell_renderer_toggle_get_size;
cell_class->render = gtk_cell_renderer_toggle_render;
cell_class->activate = gtk_cell_renderer_toggle_activate;
cell_class->get_current_state = gtk_cell_renderer_toggle_get_current_state;
cell_class->apply_style = gtk_cell_renderer_toggle_apply_style;
g_object_class_install_property (object_class,
PROP_ACTIVE,
g_param_spec_boolean ("active",
@@ -423,6 +429,36 @@ gtk_cell_renderer_toggle_activate (GtkCellRenderer *cell,
return FALSE;
}
static GtkStateFlags
gtk_cell_renderer_toggle_get_current_state (GtkCellRenderer *cell)
{
GtkCellRendererTogglePrivate *priv;
GtkStateFlags state = 0;
priv = GTK_CELL_RENDERER_TOGGLE (cell)->priv;
if (priv->inconsistent)
state |= GTK_STATE_FLAG_INCONSISTENT;
else if (priv->active)
state |= GTK_STATE_FLAG_ACTIVE;
return state;
}
static void
gtk_cell_renderer_toggle_apply_style (GtkCellRenderer *cell,
GtkStyleContext *context)
{
GtkCellRendererTogglePrivate *priv;
priv = GTK_CELL_RENDERER_TOGGLE (cell)->priv;
if (priv->radio)
gtk_style_context_add_class (context, GTK_STYLE_CLASS_RADIO);
else
gtk_style_context_add_class (context, GTK_STYLE_CLASS_CHECK);
}
/**
* gtk_cell_renderer_toggle_set_radio:
* @toggle: a #GtkCellRendererToggle

View File

@@ -2962,11 +2962,14 @@ gtk_icon_view_paint_item (GtkIconView *icon_view,
cell_area.width = item->cell_area.width;
cell_area.height = item->cell_area.height;
gtk_cell_area_set_animation_id (priv->cell_area, item);
context = g_ptr_array_index (priv->row_contexts, item->row);
gtk_cell_area_render (priv->cell_area, context,
widget, cr, &cell_area, &cell_area, flags,
draw_focus);
gtk_cell_area_set_animation_id (priv->cell_area, NULL);
gtk_style_context_restore (style_context);
}
@@ -3355,7 +3358,11 @@ gtk_icon_view_row_deleted (GtkTreeModel *model,
item = list->data;
if (icon_view->priv->cell_area)
gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
{
gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
gtk_cell_area_forget_animation_id (icon_view->priv->cell_area,
GTK_WIDGET (data), item);
}
if (item == icon_view->priv->anchor_item)
icon_view->priv->anchor_item = NULL;

View File

@@ -3155,6 +3155,7 @@ _gtk_style_context_coalesce_animation_areas (GtkStyleContext *context,
GtkWidget *widget)
{
GtkStyleContextPrivate *priv;
gboolean validate = TRUE;
GSList *l;
priv = context->priv;
@@ -3167,7 +3168,6 @@ _gtk_style_context_coalesce_animation_areas (GtkStyleContext *context,
while (l)
{
AnimationInfo *info;
gint rel_x, rel_y;
GSList *cur;
guint i;
@@ -3179,34 +3179,31 @@ _gtk_style_context_coalesce_animation_areas (GtkStyleContext *context,
continue;
if (info->rectangles->len == 0)
continue;
{
validate = FALSE;
continue;
}
info->invalidation_region = cairo_region_create ();
_gtk_widget_get_translation_to_window (widget, info->window, &rel_x, &rel_y);
for (i = 0; i < info->rectangles->len; i++)
{
cairo_rectangle_int_t *rect;
rect = &g_array_index (info->rectangles, cairo_rectangle_int_t, i);
/* These are widget relative coordinates,
* so have them inverted to be window relative
*/
rect->x -= rel_x;
rect->y -= rel_y;
cairo_region_union_rectangle (info->invalidation_region, rect);
}
g_array_remove_range (info->rectangles, 0, info->rectangles->len);
}
priv->animations_invalidated = FALSE;
if (validate)
priv->animations_invalidated = FALSE;
}
static void
store_animation_region (GtkStyleContext *context,
cairo_t *cr,
gdouble x,
gdouble y,
gdouble width,
@@ -3236,6 +3233,12 @@ store_animation_region (GtkStyleContext *context,
{
cairo_rectangle_int_t rect;
/* store device coordinates so the coordinates
* can be used right away in window invalidation
*/
cairo_user_to_device (cr, &x, &y);
cairo_user_to_device_distance (cr, &width, &height);
rect.x = (gint) x;
rect.y = (gint) y;
rect.width = (gint) width;
@@ -3711,7 +3714,7 @@ gtk_render_check (GtkStyleContext *context,
cairo_save (cr);
store_animation_region (context, x, y, width, height);
store_animation_region (context, cr, x, y, width, height);
_gtk_theming_engine_set_context (priv->theming_engine, context);
engine_class->render_check (priv->theming_engine, cr,
@@ -3762,7 +3765,7 @@ gtk_render_option (GtkStyleContext *context,
cairo_save (cr);
store_animation_region (context, x, y, width, height);
store_animation_region (context, cr, x, y, width, height);
_gtk_theming_engine_set_context (priv->theming_engine, context);
engine_class->render_option (priv->theming_engine, cr,
@@ -3811,7 +3814,7 @@ gtk_render_arrow (GtkStyleContext *context,
cairo_save (cr);
store_animation_region (context, x, y, size, size);
store_animation_region (context, cr, x, y, size, size);
_gtk_theming_engine_set_context (priv->theming_engine, context);
engine_class->render_arrow (priv->theming_engine, cr,
@@ -3863,7 +3866,7 @@ gtk_render_background (GtkStyleContext *context,
cairo_save (cr);
store_animation_region (context, x, y, width, height);
store_animation_region (context, cr, x, y, width, height);
_gtk_theming_engine_set_context (priv->theming_engine, context);
engine_class->render_background (priv->theming_engine, cr, x, y, width, height);
@@ -3916,7 +3919,7 @@ gtk_render_frame (GtkStyleContext *context,
cairo_save (cr);
store_animation_region (context, x, y, width, height);
store_animation_region (context, cr, x, y, width, height);
_gtk_theming_engine_set_context (priv->theming_engine, context);
engine_class->render_frame (priv->theming_engine, cr, x, y, width, height);
@@ -3966,7 +3969,7 @@ gtk_render_expander (GtkStyleContext *context,
cairo_save (cr);
store_animation_region (context, x, y, width, height);
store_animation_region (context, cr, x, y, width, height);
_gtk_theming_engine_set_context (priv->theming_engine, context);
engine_class->render_expander (priv->theming_engine, cr, x, y, width, height);
@@ -4013,7 +4016,7 @@ gtk_render_focus (GtkStyleContext *context,
cairo_save (cr);
store_animation_region (context, x, y, width, height);
store_animation_region (context, cr, x, y, width, height);
_gtk_theming_engine_set_context (priv->theming_engine, context);
engine_class->render_focus (priv->theming_engine, cr, x, y, width, height);
@@ -4055,7 +4058,7 @@ gtk_render_layout (GtkStyleContext *context,
pango_layout_get_extents (layout, &extents, NULL);
store_animation_region (context,
store_animation_region (context, cr,
x + extents.x,
y + extents.y,
extents.width,
@@ -4149,7 +4152,7 @@ gtk_render_slider (GtkStyleContext *context,
cairo_save (cr);
store_animation_region (context, x, y, width, height);
store_animation_region (context, cr, x, y, width, height);
_gtk_theming_engine_set_context (priv->theming_engine, context);
engine_class->render_slider (priv->theming_engine, cr, x, y, width, height, orientation);
@@ -4214,7 +4217,7 @@ gtk_render_frame_gap (GtkStyleContext *context,
cairo_save (cr);
store_animation_region (context, x, y, width, height);
store_animation_region (context, cr, x, y, width, height);
_gtk_theming_engine_set_context (priv->theming_engine, context);
engine_class->render_frame_gap (priv->theming_engine, cr,
@@ -4268,7 +4271,7 @@ gtk_render_extension (GtkStyleContext *context,
cairo_save (cr);
store_animation_region (context, x, y, width, height);
store_animation_region (context, cr, x, y, width, height);
_gtk_theming_engine_set_context (priv->theming_engine, context);
engine_class->render_extension (priv->theming_engine, cr, x, y, width, height, gap_side);
@@ -4318,7 +4321,7 @@ gtk_render_handle (GtkStyleContext *context,
cairo_save (cr);
store_animation_region (context, x, y, width, height);
store_animation_region (context, cr, x, y, width, height);
_gtk_theming_engine_set_context (priv->theming_engine, context);
engine_class->render_handle (priv->theming_engine, cr, x, y, width, height);
@@ -4363,7 +4366,7 @@ gtk_render_activity (GtkStyleContext *context,
cairo_save (cr);
store_animation_region (context, x, y, width, height);
store_animation_region (context, cr, x, y, width, height);
_gtk_theming_engine_set_context (priv->theming_engine, context);
engine_class->render_activity (priv->theming_engine, cr, x, y, width, height);

View File

@@ -133,11 +133,15 @@ gboolean _gtk_tree_view_column_is_blank_at_pos (GtkTreeViewColumn *co
gint y);
void _gtk_tree_view_column_cell_render (GtkTreeViewColumn *tree_column,
cairo_t *cr,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
guint flags,
gboolean draw_focus);
cairo_t *cr,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
guint flags,
gboolean draw_focus,
gpointer anim_id);
void _gtk_tree_view_column_cancel_animations (GtkTreeViewColumn *tree_column,
gpointer anim_id);
void _gtk_tree_view_column_cell_set_dirty (GtkTreeViewColumn *tree_column,
gboolean install_handler);
gboolean _gtk_tree_view_column_cell_get_dirty (GtkTreeViewColumn *tree_column);

View File

@@ -298,6 +298,7 @@ struct _GtkTreeViewPrivate
/* Scroll position state keeping */
GtkTreeRowReference *top_row;
GtkTreeRowReference *bottom_row;
gint top_row_dy;
/* dy == y pos of top_row + top_row_dy */
/* we cache it for simplicity of the code */
@@ -721,6 +722,9 @@ static void gtk_tree_view_set_top_row (GtkTreeView *tree_view,
gint offset);
static void gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
static void gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
static GtkTreePath * gtk_tree_view_get_bottom_row (GtkTreeView *tree_view,
GtkTreePath *top_row);
static void invalidate_empty_focus (GtkTreeView *tree_view);
/* Internal functions */
@@ -883,6 +887,10 @@ static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView *tree
GtkTreeViewColumn *column,
gint drop_position);
static void gtk_tree_view_cancel_row_animations (GtkTreeView *tree_view,
GtkTreePath *top_row,
GtkTreePath *bottom_row);
/* GtkBuildable */
static void gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
GtkBuilder *builder,
@@ -2815,6 +2823,26 @@ gtk_tree_view_size_allocate (GtkWidget *widget,
tree_view->priv->prev_width_before_expander = width_before_expander;
}
}
if (tree_view->priv->top_row &&
tree_view->priv->bottom_row)
{
GtkTreePath *top_path, *bottom_path;
top_path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
bottom_path = gtk_tree_view_get_bottom_row (tree_view, top_path);
gtk_tree_view_cancel_row_animations (tree_view, top_path, bottom_path);
gtk_tree_path_free (top_path);
/* Update bottom row */
gtk_tree_row_reference_free (tree_view->priv->bottom_row);
tree_view->priv->bottom_row = gtk_tree_row_reference_new (tree_view->priv->model,
bottom_path);
gtk_tree_path_free (bottom_path);
}
}
/* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
@@ -5036,7 +5064,8 @@ gtk_tree_view_bin_draw (GtkWidget *widget,
&background_area,
&cell_area,
flags,
draw_focus);
draw_focus,
node);
if (gtk_tree_view_draw_expanders (tree_view)
&& (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
{
@@ -5075,7 +5104,8 @@ gtk_tree_view_bin_draw (GtkWidget *widget,
&background_area,
&cell_area,
flags,
draw_focus);
draw_focus,
node);
}
if (draw_hgrid_lines)
@@ -6856,13 +6886,195 @@ install_scroll_sync_handler (GtkTreeView *tree_view)
}
}
/* Gets the bottom row for a given top_row, taking
* into account current treeview allocation.
*/
static GtkTreePath *
gtk_tree_view_get_bottom_row (GtkTreeView *tree_view,
GtkTreePath *top_row)
{
GtkRBTree *tree, *bottom_row_tree;
GtkRBNode *node, *bottom_row_node;
gint y;
if (!top_row)
return NULL;
_gtk_tree_view_find_node (tree_view, top_row, &tree, &node);
if (!tree)
return NULL;
y = _gtk_rbtree_node_find_offset (tree, node);
y += gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
y = CLAMP (y,
(gint) gtk_adjustment_get_lower (tree_view->priv->vadjustment),
(gint) gtk_adjustment_get_upper (tree_view->priv->vadjustment));
if (y >= tree_view->priv->height)
y = tree_view->priv->height - 1;
_gtk_rbtree_find_offset (tree_view->priv->tree, y,
&bottom_row_tree,
&bottom_row_node);
if (!bottom_row_tree)
return NULL;
return _gtk_tree_view_find_path (tree_view,
bottom_row_tree,
bottom_row_node);
}
static void
gtk_tree_view_cancel_row_range (GtkTreeView *tree_view,
GtkTreePath *from,
GtkTreePath *to)
{
GtkRBNode *from_node, *to_node;
GtkRBTree *tree;
if (gtk_tree_path_compare (from, to) > 0)
{
GtkTreePath *tmp;
tmp = from;
from = to;
to = tmp;
}
_gtk_tree_view_find_node (tree_view, to, &tree, &to_node);
_gtk_tree_view_find_node (tree_view, from, &tree, &from_node);
if (!from_node || !to_node)
return;
while (from_node)
{
GList *columns;
for (columns = tree_view->priv->columns; columns; columns = columns->next)
{
GtkTreeViewColumn *column;
column = columns->data;
_gtk_tree_view_column_cancel_animations (column, from_node);
}
if (from_node != to_node)
_gtk_rbtree_next_full (tree, from_node, &tree, &from_node);
else
from_node = NULL;
}
}
static void
gtk_tree_view_cancel_row_animations (GtkTreeView *tree_view,
GtkTreePath *top_row,
GtkTreePath *bottom_row)
{
GtkTreePath *old_top_row, *old_bottom_row;
GtkTreePath *start_path = NULL;
GtkRBNode *node;
GtkRBTree *tree;
if (!tree_view->priv->top_row &&
!tree_view->priv->bottom_row)
return;
old_top_row = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
old_bottom_row = gtk_tree_row_reference_get_path (tree_view->priv->bottom_row);
if (gtk_tree_path_compare (old_top_row, top_row) < 0)
{
/* If the top row moved downwards, cancel all running animations
* from the new top row upwards, or optionally cancel all previous
* view contents if it's been scrolled to a completely disconnected
* place.
*/
if (gtk_tree_path_compare (top_row, old_bottom_row) < 0)
{
/* Top row is in the viewable range,
* start from the one right above it
*/
_gtk_tree_view_find_node (tree_view, top_row, &tree, &node);
if (tree)
{
_gtk_rbtree_prev_full (tree, node, &tree, &node);
if (tree)
start_path = _gtk_tree_view_find_path (tree_view, tree, node);
}
}
else
start_path = gtk_tree_path_copy (old_bottom_row);
if (start_path)
{
gtk_tree_view_cancel_row_range (tree_view, start_path, old_top_row);
gtk_tree_path_free (start_path);
start_path = NULL;
}
}
if (gtk_tree_path_compare (old_bottom_row, bottom_row) > 0)
{
/* If the bottom row moved upwards, cancel all running
* animations from the bottom row downwards, handling
* also jumps through the view.
*/
if (gtk_tree_path_compare (bottom_row, old_top_row) > 0)
{
/* Bottom row is in the viewable range,
* start from the one right above it
*/
_gtk_tree_view_find_node (tree_view, bottom_row, &tree, &node);
if (tree)
{
_gtk_rbtree_next_full (tree, node, &tree, &node);
if (tree)
start_path = _gtk_tree_view_find_path (tree_view, tree, node);
}
}
else
start_path = gtk_tree_path_copy (old_top_row);
if (start_path)
{
gtk_tree_view_cancel_row_range (tree_view, start_path, old_bottom_row);
gtk_tree_path_free (start_path);
}
}
gtk_tree_path_free (old_top_row);
gtk_tree_path_free (old_bottom_row);
}
static void
gtk_tree_view_set_top_row (GtkTreeView *tree_view,
GtkTreePath *path,
gint offset)
{
GtkTreePath *bottom_path = NULL;
if (path)
bottom_path = gtk_tree_view_get_bottom_row (tree_view, path);
if (tree_view->priv->top_row &&
tree_view->priv->bottom_row)
gtk_tree_view_cancel_row_animations (tree_view, path, bottom_path);
gtk_tree_row_reference_free (tree_view->priv->top_row);
if (tree_view->priv->bottom_row)
{
gtk_tree_row_reference_free (tree_view->priv->bottom_row);
tree_view->priv->bottom_row = NULL;
}
if (!path)
{
tree_view->priv->top_row = NULL;
@@ -6872,6 +7084,9 @@ gtk_tree_view_set_top_row (GtkTreeView *tree_view,
{
tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
tree_view->priv->top_row_dy = offset;
if (bottom_path)
tree_view->priv->bottom_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, bottom_path);
}
}
@@ -8972,6 +9187,29 @@ check_selection_helper (GtkRBTree *tree,
_gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
}
static void
cancel_row_animation_helper (GtkRBTree *tree,
GtkRBNode *node,
gpointer user_data)
{
GtkTreeView *tree_view = user_data;
GList *columns;
for (columns = tree_view->priv->columns;
columns;
columns = columns->next)
{
GtkTreeViewColumn *column;
column = columns->data;
_gtk_tree_view_column_cancel_animations (column, node);
}
if (node->children)
_gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER,
cancel_row_animation_helper, user_data);
}
static void
gtk_tree_view_row_deleted (GtkTreeModel *model,
GtkTreePath *path,
@@ -8994,6 +9232,10 @@ gtk_tree_view_row_deleted (GtkTreeModel *model,
if (tree == NULL)
return;
_gtk_rbtree_traverse (tree, node, G_POST_ORDER,
cancel_row_animation_helper,
tree_view);
/* check if the selection has been changed */
_gtk_rbtree_traverse (tree, node, G_POST_ORDER,
check_selection_helper, &selection_changed);
@@ -11315,6 +11557,8 @@ void
gtk_tree_view_set_model (GtkTreeView *tree_view,
GtkTreeModel *model)
{
GList *columns;
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
@@ -11327,6 +11571,15 @@ gtk_tree_view_set_model (GtkTreeView *tree_view,
tree_view->priv->scroll_to_path = NULL;
}
/* Have all columns cancel every animation */
for (columns = tree_view->priv->columns; columns; columns = columns->next)
{
GtkTreeViewColumn *column;
column = columns->data;
_gtk_tree_view_column_cancel_animations (column, NULL);
}
if (tree_view->priv->model)
{
GList *tmplist = tree_view->priv->columns;
@@ -12852,6 +13105,8 @@ gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
tree_view->priv->last_button_x = -1;
tree_view->priv->last_button_y = -1;
_gtk_rbtree_traverse (node->children, node->children->root, G_PRE_ORDER, cancel_row_animation_helper, tree_view);
if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
{
_gtk_rbtree_remove (node->children);
@@ -14591,7 +14846,7 @@ gtk_tree_view_create_row_drag_icon (GtkTreeView *tree_view,
cr,
&background_area,
&cell_area,
0, FALSE);
0, FALSE, NULL);
}
cell_offset += gtk_tree_view_column_get_width (column);
}

View File

@@ -2891,11 +2891,12 @@ gtk_tree_view_column_cell_get_size (GtkTreeViewColumn *tree_column,
**/
void
_gtk_tree_view_column_cell_render (GtkTreeViewColumn *tree_column,
cairo_t *cr,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
guint flags,
gboolean draw_focus)
cairo_t *cr,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
guint flags,
gboolean draw_focus,
gpointer anim_id)
{
GtkTreeViewColumnPrivate *priv;
@@ -2907,15 +2908,32 @@ _gtk_tree_view_column_cell_render (GtkTreeViewColumn *tree_column,
priv = tree_column->priv;
cairo_save (cr);
gtk_cell_area_set_animation_id (priv->cell_area, anim_id);
gtk_cell_area_render (priv->cell_area, priv->cell_area_context,
priv->tree_view, cr,
background_area, cell_area, flags,
draw_focus);
gtk_cell_area_set_animation_id (priv->cell_area, NULL);
cairo_restore (cr);
}
void
_gtk_tree_view_column_cancel_animations (GtkTreeViewColumn *tree_column,
gpointer anim_id)
{
GtkTreeViewColumnPrivate *priv;
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
priv = tree_column->priv;
gtk_cell_area_forget_animation_id (priv->cell_area,
priv->tree_view,
anim_id);
}
gboolean
_gtk_tree_view_column_cell_event (GtkTreeViewColumn *tree_column,
GdkEvent *event,