From 1ad5fa3e7a8f41e95057bd8e9ff8c32a5c8b8459 Mon Sep 17 00:00:00 2001 From: Tristan Van Berkom Date: Fri, 5 Nov 2010 13:05:20 +0900 Subject: [PATCH] Committing half-way done focus work. --- gtk/gtkcellarea.c | 183 +++++++++++++++++++++++++++++++++++++++--- gtk/gtkcellarea.h | 4 + gtk/gtkcellareabox.c | 13 +-- gtk/gtkcellrenderer.c | 26 ++++++ gtk/gtkcellrenderer.h | 2 + 5 files changed, 205 insertions(+), 23 deletions(-) diff --git a/gtk/gtkcellarea.c b/gtk/gtkcellarea.c index 634ff4906c..fc30fb88c3 100644 --- a/gtk/gtkcellarea.c +++ b/gtk/gtkcellarea.c @@ -50,18 +50,25 @@ static void gtk_cell_area_get_property (GObject GParamSpec *pspec); /* GtkCellAreaClass */ -static void gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area, - GtkCellAreaIter *iter, - GtkWidget *widget, - gint width, - gint *minimum_height, - gint *natural_height); -static void gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area, - GtkCellAreaIter *iter, - GtkWidget *widget, - gint height, - gint *minimum_width, - gint *natural_width); +static gint gtk_cell_area_real_event (GtkCellArea *area, + GtkCellAreaIter *iter, + GtkWidget *widget, + GdkEvent *event, + const GdkRectangle *cell_area, + GtkCellRendererState flags); +static void gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area, + GtkCellAreaIter *iter, + GtkWidget *widget, + gint width, + gint *minimum_height, + gint *natural_height); +static void gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area, + GtkCellAreaIter *iter, + GtkWidget *widget, + gint height, + gint *minimum_width, + gint *natural_width); +static void gtk_cell_area_real_update_focus (GtkCellArea *area); /* GtkCellLayoutIface */ static void gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface); @@ -196,7 +203,7 @@ gtk_cell_area_class_init (GtkCellAreaClass *class) class->add = NULL; class->remove = NULL; class->forall = NULL; - class->event = NULL; + class->event = gtk_cell_area_real_event; class->render = NULL; /* geometry */ @@ -209,6 +216,7 @@ gtk_cell_area_class_init (GtkCellAreaClass *class) /* focus */ class->grab_focus = NULL; + class->update_focus = gtk_cell_area_real_update_focus; /* Signals */ cell_area_signals[SIGNAL_FOCUS_LEAVE] = @@ -437,6 +445,30 @@ gtk_cell_area_get_property (GObject *object, /************************************************************* * GtkCellAreaClass * *************************************************************/ +static gint +gtk_cell_area_real_event (GtkCellArea *area, + GtkCellAreaIter *iter, + GtkWidget *widget, + GdkEvent *event, + const GdkRectangle *cell_area, + GtkCellRendererState flags) +{ + if (event->type == GDK_KEY_PRESS) + { + GtkCellAreaPrivate *priv = area->priv; + + if (priv->focus_cell) + { + /* Activate of Edit the currently focused cell */ + + + return TRUE; + } + } + + return FALSE; +} + static void gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area, GtkCellAreaIter *iter, @@ -461,6 +493,35 @@ gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area, GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_width, natural_width); } +static void +update_can_focus (GtkCellRenderer *renderer, + gboolean *can_focus) +{ + + if (gtk_cell_renderer_can_focus (renderer)) + *can_focus = TRUE; +} + +static void +gtk_cell_area_real_update_focus (GtkCellArea *area) +{ + gboolean can_focus = FALSE; + + /* Update the area's can focus flag, if any of the renderers can + * focus then the area can focus. + * + * Subclasses can override this in the case that they are also + * rendering widgets as well as renderers. + */ + gtk_cell_area_forall (area, (GtkCellCallback)update_can_focus, &can_focus); + gtk_cell_area_set_can_focus (area, can_focus); + + /* Unset the currently focused cell if the area can not receive + * focus for the given row data */ + if (!can_focus) + gtk_cell_area_set_focus_cell (area, NULL); +} + /************************************************************* * GtkCellLayoutIface * *************************************************************/ @@ -1342,6 +1403,24 @@ gtk_cell_area_cell_get_property (GtkCellArea *area, /************************************************************* * API: Focus * *************************************************************/ + +/** + * gtk_cell_area_grab_focus: + * @area: a #GtkCellArea + * @direction: the #GtkDirectionType from which focus came + * + * This should be called by the @area's owning layout widget + * when focus should be passed to @area for a given row data. + * + * Note that after applying new attributes for @area that + * gtk_cell_area_update_focus() should be called and + * gtk_cell_area_can_focus() should be checked before trying + * to pass focus to @area. + * + * Implementing #GtkCellArea classes should implement this + * method to receive focus in it's own way particular to + * how it lays out cells. + */ void gtk_cell_area_grab_focus (GtkCellArea *area, GtkDirectionType direction) @@ -1359,6 +1438,24 @@ gtk_cell_area_grab_focus (GtkCellArea *area, g_type_name (G_TYPE_FROM_INSTANCE (area))); } +/** + * gtk_cell_area_focus_leave: + * @area: a #GtkCellArea + * @direction: the #GtkDirectionType in which focus + * is to leave @area + * @path: the current #GtkTreePath string for the + * event which was handled by @area + * + * Notifies that focus is to leave @area in the + * given @direction. + * + * This is called by #GtkCellArea implementations upon + * handling a key event that caused focus to leave the + * cell. The resulting signal can be handled by the + * owning layouting widget to decide which new @area + * to pass focus to and from what @direction. Or to + * pass focus along to an entirely new data row. + */ void gtk_cell_area_focus_leave (GtkCellArea *area, GtkDirectionType direction, @@ -1369,6 +1466,35 @@ gtk_cell_area_focus_leave (GtkCellArea *area, g_signal_emit (area, cell_area_signals[SIGNAL_FOCUS_LEAVE], 0, direction, path); } +/** + * gtk_cell_area_update_focus: + * @area: a #GtkCellArea + * + * Updates focus information on @area for a given + * row of data. + * + * After calling gtk_cell_area_apply_attributes() to + * the @area this method should be called to update + * information about whether the @area can focus and + * which is the cell currently in focus. + */ +void +gtk_cell_area_update_focus (GtkCellArea *area) +{ + g_return_if_fail (GTK_IS_CELL_AREA (area)); + + GTK_CELL_AREA_GET_CLASS (area)->update_focus (area); +} + +/** + * gtk_cell_area_set_can_focus: + * @area: a #GtkCellArea + * @can_focus: whether @area can receive focus + * + * This is generally called from GtkCellArea::update_focus() + * implementations to update if the @area can focus after + * applying new row data attributes. + */ void gtk_cell_area_set_can_focus (GtkCellArea *area, gboolean can_focus) @@ -1385,6 +1511,17 @@ gtk_cell_area_set_can_focus (GtkCellArea *area, } } +/** + * gtk_cell_area_get_can_focus: + * @area: a #GtkCellArea + * + * Returns whether the area can receive keyboard focus, + * after applying new attributes to @area, + * gtk_cell_area_update_focus() needs to be called before + * calling this method. + * + * Returns: whether @area can receive focus. + */ gboolean gtk_cell_area_get_can_focus (GtkCellArea *area) { @@ -1397,6 +1534,18 @@ gtk_cell_area_get_can_focus (GtkCellArea *area) return priv->can_focus; } + +/** + * gtk_cell_area_set_focus_cell: + * @area: a #GtkCellArea + * @focus_cell: the #GtkCellRenderer to give focus to + * + * This is generally called from #GtkCellArea implementations + * either gtk_cell_area_grab_focus() or gtk_cell_area_update_focus() + * is called. It's also up to the #GtkCellArea implementation + * to update the focused cell when receiving events from + * gtk_cell_area_event() appropriately. + */ void gtk_cell_area_set_focus_cell (GtkCellArea *area, GtkCellRenderer *renderer) @@ -1420,6 +1569,14 @@ gtk_cell_area_set_focus_cell (GtkCellArea *area, } } +/** + * gtk_cell_area_get_focus_cell: + * @area: a #GtkCellArea + * + * Retrieves the currently focused cell for @area + * + * Returns: the currently focused cell in @area. + */ GtkCellRenderer * gtk_cell_area_get_focus_cell (GtkCellArea *area) { diff --git a/gtk/gtkcellarea.h b/gtk/gtkcellarea.h index 2e804714c5..9c095538bd 100644 --- a/gtk/gtkcellarea.h +++ b/gtk/gtkcellarea.h @@ -133,6 +133,7 @@ struct _GtkCellAreaClass /* Focus */ void (* grab_focus) (GtkCellArea *area, GtkDirectionType direction); + void (* update_focus) (GtkCellArea *area); /* Padding for future expansion */ void (*_gtk_reserved1) (void); @@ -255,6 +256,7 @@ void gtk_cell_area_grab_focus (GtkCellArea void gtk_cell_area_focus_leave (GtkCellArea *area, GtkDirectionType direction, const gchar *path); +void gtk_cell_area_update_focus (GtkCellArea *area); void gtk_cell_area_set_can_focus (GtkCellArea *area, gboolean can_focus); gboolean gtk_cell_area_get_can_focus (GtkCellArea *area); @@ -262,6 +264,8 @@ void gtk_cell_area_set_focus_cell (GtkCellArea 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/gtkcellareabox.c b/gtk/gtkcellareabox.c index 60e4b3a973..ad2f6ee2ef 100644 --- a/gtk/gtkcellareabox.c +++ b/gtk/gtkcellareabox.c @@ -1465,16 +1465,9 @@ gtk_cell_area_box_grab_focus (GtkCellArea *area, for (list = first_cell ? g_list_first (group->cells) : g_list_last (group->cells); list; list = first_cell ? list->next : list->prev) { - GtkCellRendererMode mode; - CellInfo *info = list->data; - - /* XXX This does not handle cases where the cell - * is not visible as it is not row specific, - * that's a problem. - */ - g_object_get (info->renderer, "mode", &mode, NULL); - if (mode == GTK_CELL_RENDERER_MODE_EDITABLE || - mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) + CellInfo *info = list->data; + + if (gtk_cell_renderer_can_focus (info->renderer)) { gtk_cell_area_set_focus_cell (area, info->renderer); break; diff --git a/gtk/gtkcellrenderer.c b/gtk/gtkcellrenderer.c index 3656599483..da6c77ce92 100644 --- a/gtk/gtkcellrenderer.c +++ b/gtk/gtkcellrenderer.c @@ -1058,6 +1058,32 @@ gtk_cell_renderer_get_sensitive (GtkCellRenderer *cell) return cell->priv->sensitive; } + +/** + * gtk_cell_renderer_can_focus: + * @cell: A #GtkCellRenderer + * + * Checks whether the cell renderer can receive focus. + * + * Returns: %TRUE if the cell renderer can do anything with keyboard focus + * + * Since: 3.0 + */ +gboolean +gtk_cell_renderer_can_focus (GtkCellRenderer *cell) +{ + GtkCellRendererPrivate *priv; + + g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), FALSE); + + priv = cell->priv; + + return (cell->priv->visible && + (cell->priv->mode == GTK_CELL_RENDERER_MODE_EDITABLE || + cell->priv->mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)); +} + + /** * gtk_cell_renderer_stop_editing: * @cell: A #GtkCellRenderer diff --git a/gtk/gtkcellrenderer.h b/gtk/gtkcellrenderer.h index 44362778ce..407d35730e 100644 --- a/gtk/gtkcellrenderer.h +++ b/gtk/gtkcellrenderer.h @@ -213,6 +213,8 @@ void gtk_cell_renderer_set_sensitive (GtkCellRenderer *cell, gboolean sensitive); gboolean gtk_cell_renderer_get_sensitive (GtkCellRenderer *cell); +gboolean gtk_cell_renderer_can_focus (GtkCellRenderer *cell); + /* For use by cell renderer implementations only */ void gtk_cell_renderer_stop_editing (GtkCellRenderer *cell, gboolean canceled);