[gtk+/treeview-refactor] Implemented focus handling in GtkCellAreaBox



commit 0336838366389dd22d185324f827538638b1b37f
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Sat Nov 6 16:14:38 2010 +0900

    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.

 gtk/gtkcellarea.c    |   11 ++--
 gtk/gtkcellarea.h    |    3 +-
 gtk/gtkcellareabox.c |  138 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 145 insertions(+), 7 deletions(-)
---
diff --git a/gtk/gtkcellarea.c b/gtk/gtkcellarea.c
index d997af0..4032369 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 a0cc50f..0e8a7a9 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 a2f73bd..3cee4cb 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.



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]