summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTristan Van Berkom <tristan.van.berkom@gmail.com>2010-11-06 16:14:38 +0900
committerTristan Van Berkom <tristan.van.berkom@gmail.com>2010-11-08 11:31:03 +0900
commit0336838366389dd22d185324f827538638b1b37f (patch)
treea5cbb77f33c7accdacdb0629bc818a6d354d1efe
parent09e3d9d3aaafa1b756120afcd5d2a80f4ae13439 (diff)
downloadgtk+-0336838366389dd22d185324f827538638b1b37f.tar.gz
Implemented focus handling in GtkCellAreaBox
Now when the GtkCellAreaBox receives key events it cycles the currently focused cell to the next focusable cell in the box while observing the navigation direction, it then emits "focus-leave" when hitting the boundries of the area.
-rw-r--r--gtk/gtkcellarea.c11
-rw-r--r--gtk/gtkcellarea.h3
-rw-r--r--gtk/gtkcellareabox.c138
3 files changed, 145 insertions, 7 deletions
diff --git a/gtk/gtkcellarea.c b/gtk/gtkcellarea.c
index d997af06a3..4032369131 100644
--- a/gtk/gtkcellarea.c
+++ b/gtk/gtkcellarea.c
@@ -1725,8 +1725,6 @@ gtk_cell_area_grab_focus (GtkCellArea *area,
* @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.
@@ -1740,12 +1738,15 @@ gtk_cell_area_grab_focus (GtkCellArea *area,
*/
void
gtk_cell_area_focus_leave (GtkCellArea *area,
- GtkDirectionType direction,
- const gchar *path)
+ GtkDirectionType direction)
{
+ GtkCellAreaPrivate *priv;
+
g_return_if_fail (GTK_IS_CELL_AREA (area));
- g_signal_emit (area, cell_area_signals[SIGNAL_FOCUS_LEAVE], 0, direction, path);
+ priv = area->priv;
+
+ g_signal_emit (area, cell_area_signals[SIGNAL_FOCUS_LEAVE], 0, direction, priv->current_path);
}
/**
diff --git a/gtk/gtkcellarea.h b/gtk/gtkcellarea.h
index a0cc50f005..0e8a7a9e45 100644
--- a/gtk/gtkcellarea.h
+++ b/gtk/gtkcellarea.h
@@ -268,8 +268,7 @@ void gtk_cell_area_cell_get_property (GtkCellArea
void gtk_cell_area_grab_focus (GtkCellArea *area,
GtkDirectionType direction);
void gtk_cell_area_focus_leave (GtkCellArea *area,
- GtkDirectionType direction,
- const gchar *path);
+ GtkDirectionType direction);
void gtk_cell_area_update_focus (GtkCellArea *area);
void gtk_cell_area_set_can_focus (GtkCellArea *area,
gboolean can_focus);
diff --git a/gtk/gtkcellareabox.c b/gtk/gtkcellareabox.c
index a2f73bd4fe..3cee4cb3ec 100644
--- a/gtk/gtkcellareabox.c
+++ b/gtk/gtkcellareabox.c
@@ -862,6 +862,97 @@ gtk_cell_area_box_get_cell_allocation (GtkCellArea *area,
g_slist_free (allocated_cells);
}
+enum {
+ FOCUS_NONE,
+ FOCUS_PREV,
+ FOCUS_NEXT
+};
+
+static void
+gtk_cell_area_cycle_focus (GtkCellAreaBox *box,
+ GtkCellRenderer *focus_cell,
+ GtkDirectionType direction)
+{
+ GtkCellAreaBoxPrivate *priv = box->priv;
+ GtkCellArea *area = GTK_CELL_AREA (box);
+ gint cycle = FOCUS_NONE;
+
+ switch (direction)
+ {
+ case GTK_DIR_TAB_FORWARD:
+ cycle = FOCUS_NEXT;
+ break;
+ case GTK_DIR_TAB_BACKWARD:
+ cycle = FOCUS_PREV;
+ break;
+ case GTK_DIR_UP:
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ gtk_cell_area_focus_leave (area, direction);
+ else
+ cycle = FOCUS_PREV;
+ break;
+ case GTK_DIR_DOWN:
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ gtk_cell_area_focus_leave (area, direction);
+ else
+ cycle = FOCUS_NEXT;
+ break;
+ case GTK_DIR_LEFT:
+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+ gtk_cell_area_focus_leave (area, direction);
+ else
+ cycle = FOCUS_PREV;
+ break;
+ case GTK_DIR_RIGHT:
+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+ gtk_cell_area_focus_leave (area, direction);
+ else
+ cycle = FOCUS_NEXT;
+ break;
+ default:
+ break;
+ }
+
+ if (cycle != FOCUS_NONE)
+ {
+ gboolean found_cell = FALSE;
+ gboolean cycled_focus = FALSE;
+ GList *list;
+ gint i;
+
+ for (i = (cycle == FOCUS_NEXT) ? 0 : priv->groups->len -1;
+ i >= 0 && i < priv->groups->len;
+ i = (cycle == FOCUS_NEXT) ? i + 1 : i - 1)
+ {
+ CellGroup *group = &g_array_index (priv->groups, CellGroup, i);
+
+ for (list = (cycle == FOCUS_NEXT) ? g_list_first (group->cells) : g_list_last (group->cells);
+ list; list = (cycle == FOCUS_NEXT) ? list->next : list->prev)
+ {
+ CellInfo *info = list->data;
+
+ if (!found_cell && info->renderer == focus_cell)
+ found_cell = TRUE;
+ else if (found_cell)
+ {
+ if (gtk_cell_renderer_can_focus (info->renderer))
+ {
+ gtk_cell_area_set_focus_cell (area, info->renderer);
+
+ cycled_focus = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ /* We cycled right out of the area, signal the parent we
+ * need to focus out of the area */
+ if (!cycled_focus)
+ gtk_cell_area_focus_leave (area, direction);
+ }
+}
+
static gint
gtk_cell_area_box_event (GtkCellArea *area,
GtkCellAreaIter *iter,
@@ -887,6 +978,53 @@ gtk_cell_area_box_event (GtkCellArea *area,
* observe the orientation and push focus along to the next cell
* or signal that focus should leave the area.
*/
+ if (event->type == GDK_KEY_PRESS && (flags & GTK_CELL_RENDERER_FOCUSED) != 0)
+ {
+ GdkEventKey *key_event = (GdkEventKey *)event;
+ GtkCellRenderer *focus_cell;
+
+ focus_cell = gtk_cell_area_get_focus_cell (area);
+
+ if (focus_cell)
+ {
+ GtkCellAreaBox *box = GTK_CELL_AREA_BOX (area);
+ GtkDirectionType direction = GTK_DIR_TAB_FORWARD;
+ gboolean have_direction = FALSE;
+
+ /* Check modifiers and TAB keys ! */
+ switch (key_event->keyval)
+ {
+ case GDK_KEY_KP_Up:
+ case GDK_KEY_Up:
+ direction = GTK_DIR_UP;
+ have_direction = TRUE;
+ break;
+ case GDK_KEY_KP_Down:
+ case GDK_KEY_Down:
+ direction = GTK_DIR_DOWN;
+ have_direction = TRUE;
+ break;
+ case GDK_KEY_KP_Left:
+ case GDK_KEY_Left:
+ direction = GTK_DIR_LEFT;
+ have_direction = TRUE;
+ break;
+ case GDK_KEY_KP_Right:
+ case GDK_KEY_Right:
+ direction = GTK_DIR_RIGHT;
+ have_direction = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ if (have_direction)
+ {
+ gtk_cell_area_cycle_focus (box, focus_cell, direction);
+ return TRUE;
+ }
+ }
+ }
/* Also detect mouse events, for mouse events we need to allocate the renderers
* and find which renderer needs to be activated.