From e94a17777470ac47ad76416906426118b6cc483e Mon Sep 17 00:00:00 2001 From: Tristan Van Berkom Date: Mon, 1 Nov 2010 16:01:25 +0900 Subject: [PATCH] Added cell focus apis to GtkCellArea. --- gtk/gtkcellarea.c | 159 +++++++++++++++++++++++++++++++++++++---- gtk/gtkcellarea.h | 18 +++++ gtk/gtkmarshalers.list | 1 + 3 files changed, 165 insertions(+), 13 deletions(-) diff --git a/gtk/gtkcellarea.c b/gtk/gtkcellarea.c index cd41fc6cfa..e77c2280ce 100644 --- a/gtk/gtkcellarea.c +++ b/gtk/gtkcellarea.c @@ -31,6 +31,7 @@ #include "gtkcelllayout.h" #include "gtkcellarea.h" #include "gtkcellareaiter.h" +#include "gtkmarshalers.h" #include "gtkprivate.h" #include @@ -120,18 +121,15 @@ typedef struct { struct _GtkCellAreaPrivate { - GHashTable *cell_info; + GHashTable *cell_info; + + GtkBorder cell_border; + + GtkCellRenderer *focus_cell; + guint can_focus : 1; - GtkBorder cell_border; }; -/* Keep the paramspec pool internal, no need to deliver notifications - * on cells. at least no percieved need for now */ -static GParamSpecPool *cell_property_pool = NULL; - -#define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id) -#define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id)) - enum { PROP_0, PROP_CELL_MARGIN_LEFT, @@ -140,6 +138,20 @@ enum { PROP_CELL_MARGIN_BOTTOM }; +enum { + SIGNAL_FOCUS_LEAVE, + LAST_SIGNAL +}; + +/* Keep the paramspec pool internal, no need to deliver notifications + * on cells. at least no percieved need for now */ +static GParamSpecPool *cell_property_pool = NULL; +static guint cell_area_signals[LAST_SIGNAL] = { 0 }; + +#define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id) +#define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id)) + + G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED, G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT, gtk_cell_area_cell_layout_init)); @@ -163,6 +175,8 @@ gtk_cell_area_init (GtkCellArea *area) priv->cell_border.right = 0; priv->cell_border.top = 0; priv->cell_border.bottom = 0; + + priv->focus_cell = NULL; } static void @@ -191,6 +205,21 @@ gtk_cell_area_class_init (GtkCellAreaClass *class) class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width; class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height; + /* focus */ + class->grab_focus = NULL; + + /* Signals */ + cell_area_signals[SIGNAL_FOCUS_LEAVE] = + g_signal_new (I_("focus-leave"), + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, /* Class offset (just a notification, no class handler) */ + NULL, NULL, + _gtk_marshal_VOID__ENUM_STRING, + G_TYPE_NONE, 2, + GTK_TYPE_DIRECTION_TYPE, G_TYPE_STRING); + + /* Properties */ g_object_class_install_property (object_class, PROP_CELL_MARGIN_LEFT, @@ -340,6 +369,9 @@ gtk_cell_area_dispose (GObject *object) */ gtk_cell_layout_clear (GTK_CELL_LAYOUT (object)); + /* Remove any ref to a focused cell */ + gtk_cell_area_set_focus_cell (GTK_CELL_AREA (object), NULL); + G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object); } @@ -678,7 +710,9 @@ gtk_cell_area_render (GtkCellArea *area, g_type_name (G_TYPE_FROM_INSTANCE (area))); } -/* Geometry */ +/************************************************************* + * API: Geometry * + *************************************************************/ GtkCellAreaIter * gtk_cell_area_create_iter (GtkCellArea *area) { @@ -793,7 +827,9 @@ gtk_cell_area_get_preferred_width_for_height (GtkCellArea *area, class->get_preferred_width_for_height (area, iter, widget, height, minimum_width, natural_width); } -/* Attributes */ +/************************************************************* + * API: Attributes * + *************************************************************/ void gtk_cell_area_attribute_connect (GtkCellArea *area, GtkCellRenderer *renderer, @@ -927,7 +963,9 @@ gtk_cell_area_apply_attributes (GtkCellArea *area, g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data); } -/* Cell Properties */ +/************************************************************* + * API: Cell Properties * + *************************************************************/ void gtk_cell_area_class_install_cell_property (GtkCellAreaClass *aclass, guint property_id, @@ -1272,7 +1310,102 @@ gtk_cell_area_cell_get_property (GtkCellArea *area, } } -/* Margins */ +/************************************************************* + * API: Focus * + *************************************************************/ +void +gtk_cell_area_grab_focus (GtkCellArea *area, + GtkDirectionType direction) +{ + GtkCellAreaClass *class; + + g_return_if_fail (GTK_IS_CELL_AREA (area)); + + class = GTK_CELL_AREA_GET_CLASS (area); + + if (class->grab_focus) + class->grab_focus (area, direction); + else + g_warning ("GtkCellAreaClass::grab_focus not implemented for `%s'", + g_type_name (G_TYPE_FROM_INSTANCE (area))); +} + +void +gtk_cell_area_focus_leave (GtkCellArea *area, + GtkDirectionType direction, + const gchar *path) +{ + g_return_if_fail (GTK_IS_CELL_AREA (area)); + + g_signal_emit (area, cell_area_signals[SIGNAL_FOCUS_LEAVE], 0, direction, path); +} + +void +gtk_cell_area_set_can_focus (GtkCellArea *area, + gboolean can_focus) +{ + GtkCellAreaPrivate *priv; + + g_return_if_fail (GTK_IS_CELL_AREA (area)); + + priv = area->priv; + + if (priv->can_focus != can_focus) + { + priv->can_focus = can_focus; + } +} + +gboolean +gtk_cell_area_get_can_focus (GtkCellArea *area) +{ + GtkCellAreaPrivate *priv; + + g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE); + + priv = area->priv; + + return priv->can_focus; +} + +void +gtk_cell_area_set_focus_cell (GtkCellArea *area, + GtkCellRenderer *renderer) +{ + GtkCellAreaPrivate *priv; + + g_return_if_fail (GTK_IS_CELL_AREA (area)); + g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer)); + + priv = area->priv; + + if (priv->focus_cell != renderer) + { + if (priv->focus_cell) + g_object_unref (priv->focus_cell); + + priv->focus_cell = renderer; + + if (priv->focus_cell) + g_object_ref (priv->focus_cell); + } +} + +GtkCellRenderer * +gtk_cell_area_get_focus_cell (GtkCellArea *area) +{ + GtkCellAreaPrivate *priv; + + g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL); + + priv = area->priv; + + return priv->focus_cell; +} + +/************************************************************* + * API: Margins * + *************************************************************/ gint gtk_cell_area_get_cell_margin_left (GtkCellArea *area) { diff --git a/gtk/gtkcellarea.h b/gtk/gtkcellarea.h index 39bf8eb724..c45977fb29 100644 --- a/gtk/gtkcellarea.h +++ b/gtk/gtkcellarea.h @@ -130,6 +130,10 @@ struct _GtkCellAreaClass GValue *value, GParamSpec *pspec); + /* Focus */ + void (* grab_focus) (GtkCellArea *area, + GtkDirectionType direction); + /* Padding for future expansion */ void (*_gtk_reserved1) (void); void (*_gtk_reserved2) (void); @@ -242,6 +246,20 @@ void gtk_cell_area_cell_get_property (GtkCellArea #define GTK_CELL_AREA_WARN_INVALID_CHILD_PROPERTY_ID(object, property_id, pspec) \ G_OBJECT_WARN_INVALID_PSPEC ((object), "cell property id", (property_id), (pspec)) + +/* Focus */ +void gtk_cell_area_grab_focus (GtkCellArea *area, + GtkDirectionType direction); +void gtk_cell_area_focus_leave (GtkCellArea *area, + GtkDirectionType direction, + const gchar *path); +void gtk_cell_area_set_can_focus (GtkCellArea *area, + gboolean can_focus); +gboolean gtk_cell_area_get_can_focus (GtkCellArea *area); +void gtk_cell_area_set_focus_cell (GtkCellArea *area, + GtkCellRenderer *renderer); +GtkCellRenderer *gtk_cell_area_get_focus_cell (GtkCellArea *area); + /* Margins */ gint gtk_cell_area_get_cell_margin_left (GtkCellArea *area); void gtk_cell_area_set_cell_margin_left (GtkCellArea *area, diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list index 22af46d610..88e870f052 100644 --- a/gtk/gtkmarshalers.list +++ b/gtk/gtkmarshalers.list @@ -69,6 +69,7 @@ VOID:ENUM,FLOAT,BOOLEAN VOID:ENUM,INT VOID:ENUM,INT,BOOLEAN VOID:ENUM,BOXED +VOID:ENUM,STRING VOID:INT VOID:INT,BOOLEAN VOID:INT,INT