[gnome-builder/wip/chergert/perspective] search: implement up/down for omni search result display



commit abb7b0b11732fba5429c35dd2f304d2c1fa65181
Author: Christian Hergert <chergert redhat com>
Date:   Thu Dec 10 13:01:45 2015 -0800

    search: implement up/down for omni search result display

 data/theme/shared.css                   |    7 ++
 libide/search/ide-omni-search-display.c |   77 ++++++++++++++++++++
 libide/search/ide-omni-search-display.h |   10 ++-
 libide/search/ide-omni-search-entry.c   |   34 +++++++++
 libide/search/ide-omni-search-group.c   |  120 +++++++++++++++++++++++++++++++
 libide/search/ide-omni-search-group.h   |    3 +
 6 files changed, 247 insertions(+), 4 deletions(-)
---
diff --git a/data/theme/shared.css b/data/theme/shared.css
index af84c94..0587b1f 100644
--- a/data/theme/shared.css
+++ b/data/theme/shared.css
@@ -124,12 +124,19 @@ workbench IdePreferencesBin entry {
 
 
 omnisearchrow {
+  background-image: none;
+  background-color: transparent;
   padding-top: 9px;
   padding-left: 12px;
   padding-right: 12px;
   padding-bottom: 9px;
 }
 
+omnisearchrow:selected {
+  background-color: @theme_selected_bg_color;
+  color: @theme_selected_fg_color;
+}
+
 
 greeter frame {
   border: 1px solid alpha(@borders, 0.4);
diff --git a/libide/search/ide-omni-search-display.c b/libide/search/ide-omni-search-display.c
index 5f72fab..52b96c5 100644
--- a/libide/search/ide-omni-search-display.c
+++ b/libide/search/ide-omni-search-display.c
@@ -135,6 +135,83 @@ ide_omni_search_display_result_selected (IdeOmniSearchDisplay *self,
     }
 }
 
+void
+ide_omni_search_display_move_next_result (IdeOmniSearchDisplay *self)
+{
+  gint i;
+
+  g_return_if_fail (IDE_IS_OMNI_SEARCH_DISPLAY (self));
+
+  for (i = 0; i < self->providers->len; i++)
+    {
+      ProviderEntry *ptr = g_ptr_array_index (self->providers, i);
+
+      if (ide_omni_search_group_has_selection (ptr->group))
+        {
+          while (ptr && !ide_omni_search_group_move_next (ptr->group))
+            {
+              ide_omni_search_group_unselect (ptr->group);
+
+              if (i < (self->providers->len - 1))
+                ptr = g_ptr_array_index (self->providers, ++i);
+              else
+                ptr = NULL;
+            }
+
+          if (ptr == NULL)
+            break;
+
+          return;
+        }
+    }
+
+  for (i = 0; i < self->providers->len; i++)
+    {
+      ProviderEntry *ptr = g_ptr_array_index (self->providers, i);
+
+      if (ide_omni_search_group_move_next (ptr->group))
+        break;
+    }
+}
+
+void
+ide_omni_search_display_move_previous_result (IdeOmniSearchDisplay *self)
+{
+  gint i;
+
+  g_return_if_fail (IDE_IS_OMNI_SEARCH_DISPLAY (self));
+
+  for (i = self->providers->len - 1; i >= 0; i--)
+    {
+      ProviderEntry *ptr = g_ptr_array_index (self->providers, i);
+
+      if (ide_omni_search_group_has_selection (ptr->group))
+        {
+          while (ptr && !ide_omni_search_group_move_previous (ptr->group))
+            {
+              ide_omni_search_group_unselect (ptr->group);
+              if (i > 0)
+                ptr = g_ptr_array_index (self->providers, --i);
+              else
+                ptr = NULL;
+            }
+
+          if (ptr == NULL)
+            break;
+
+          return;
+        }
+    }
+
+  for (i = self->providers->len - 1; i >= 0; i--)
+    {
+      ProviderEntry *ptr = g_ptr_array_index (self->providers, i);
+
+      if (ide_omni_search_group_move_previous (ptr->group))
+        return;
+    }
+}
+
 static gboolean
 ide_omni_search_display_keynav_failed (IdeOmniSearchDisplay *self,
                                        GtkDirectionType      dir,
diff --git a/libide/search/ide-omni-search-display.h b/libide/search/ide-omni-search-display.h
index cf9a56c..be20f55 100644
--- a/libide/search/ide-omni-search-display.h
+++ b/libide/search/ide-omni-search-display.h
@@ -29,10 +29,12 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeOmniSearchDisplay, ide_omni_search_display, IDE, OMNI_SEARCH_DISPLAY, GtkBin)
 
-IdeSearchContext *ide_omni_search_display_get_context (IdeOmniSearchDisplay *display);
-void              ide_omni_search_display_set_context (IdeOmniSearchDisplay *display,
-                                                       IdeSearchContext     *context);
-guint64           ide_omni_search_display_get_count   (IdeOmniSearchDisplay *display);
+IdeSearchContext *ide_omni_search_display_get_context          (IdeOmniSearchDisplay *self);
+void              ide_omni_search_display_set_context          (IdeOmniSearchDisplay *self,
+                                                                IdeSearchContext     *context);
+guint64           ide_omni_search_display_get_count            (IdeOmniSearchDisplay *self);
+void              ide_omni_search_display_move_next_result     (IdeOmniSearchDisplay *self);
+void              ide_omni_search_display_move_previous_result (IdeOmniSearchDisplay *self);
 
 G_END_DECLS
 
diff --git a/libide/search/ide-omni-search-entry.c b/libide/search/ide-omni-search-entry.c
index 1e9e8d8..23e15c5 100644
--- a/libide/search/ide-omni-search-entry.c
+++ b/libide/search/ide-omni-search-entry.c
@@ -45,6 +45,8 @@ G_DEFINE_TYPE (IdeOmniSearchEntry, ide_omni_search_entry, GTK_TYPE_ENTRY)
 
 enum {
   CLEAR_SEARCH,
+  MOVE_NEXT_RESULT,
+  MOVE_PREVIOUS_RESULT,
   LAST_SIGNAL
 };
 
@@ -234,6 +236,22 @@ ide_omni_search_entry_popover_key_press_event (IdeOmniSearchEntry *self,
 }
 
 static void
+ide_omni_search_entry_move_next_result (IdeOmniSearchEntry *self)
+{
+  g_assert (IDE_IS_OMNI_SEARCH_ENTRY (self));
+
+  ide_omni_search_display_move_next_result (self->display);
+}
+
+static void
+ide_omni_search_entry_move_previous_result (IdeOmniSearchEntry *self)
+{
+  g_assert (IDE_IS_OMNI_SEARCH_ENTRY (self));
+
+  ide_omni_search_display_move_previous_result (self->display);
+}
+
+static void
 ide_omni_search_entry_destroy (GtkWidget *widget)
 {
   IdeOmniSearchEntry *self = (IdeOmniSearchEntry *)widget;
@@ -263,10 +281,26 @@ ide_omni_search_entry_class_init (IdeOmniSearchEntryClass *klass)
                                 G_CALLBACK (ide_omni_search_entry_clear_search),
                                 NULL, NULL, NULL, G_TYPE_NONE, 0);
 
+  signals [MOVE_NEXT_RESULT] =
+    g_signal_new_class_handler ("move-next-result",
+                                G_TYPE_FROM_CLASS (klass),
+                                G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                                G_CALLBACK (ide_omni_search_entry_move_next_result),
+                                NULL, NULL, NULL, G_TYPE_NONE, 0);
+
+  signals [MOVE_PREVIOUS_RESULT] =
+    g_signal_new_class_handler ("move-previous-result",
+                                G_TYPE_FROM_CLASS (klass),
+                                G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                                G_CALLBACK (ide_omni_search_entry_move_previous_result),
+                                NULL, NULL, NULL, G_TYPE_NONE, 0);
+
   binding_set = gtk_binding_set_by_class (klass);
   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "clear-search", 0);
   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "activate", 0);
   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "activate", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Down, 0, "move-next-result", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Up, 0, "move-previous-result", 0);
 }
 
 static void
diff --git a/libide/search/ide-omni-search-group.c b/libide/search/ide-omni-search-group.c
index 1bb5f6a..e9a8e19 100644
--- a/libide/search/ide-omni-search-group.c
+++ b/libide/search/ide-omni-search-group.c
@@ -455,3 +455,123 @@ ide_omni_search_group_get_count (IdeOmniSearchGroup *self)
 
   return self->count;
 }
+
+static void
+find_nth_row_cb (GtkWidget *widget,
+                 gpointer   user_data)
+{
+  struct {
+    GtkListBox    *list;
+    GtkListBoxRow *row;
+    gint           nth;
+    gint           last_n;
+  } *lookup = user_data;
+  gint position;
+
+  /*
+   * This tries to find a matching index, but also handles the special case of
+   * -1, where we are trying to find the last row by position. This would not
+   *  be very efficient if the lists were long, but currently the lists are
+   *  all < 10 items.
+   */
+
+  if ((lookup->row != NULL) && (lookup->nth != -1))
+    return;
+
+  position = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (widget));
+
+  if (position == lookup->nth)
+    lookup->row = GTK_LIST_BOX_ROW (widget);
+  else if ((lookup->nth == -1) && (position > lookup->last_n))
+    {
+      lookup->row = GTK_LIST_BOX_ROW (widget);
+      lookup->last_n = position;
+    }
+}
+
+static GtkListBoxRow *
+find_nth_row (GtkListBox *list,
+              gint        nth)
+{
+  struct {
+    GtkListBox    *list;
+    GtkListBoxRow *row;
+    gint           nth;
+    gint           last_n;
+  } lookup = { list, NULL, nth, -1 };
+
+  g_assert (GTK_IS_LIST_BOX (list));
+  g_assert (nth >= -1);
+
+  gtk_container_foreach (GTK_CONTAINER (list), find_nth_row_cb, &lookup);
+
+  return lookup.row;
+}
+
+gboolean
+ide_omni_search_group_move_next (IdeOmniSearchGroup *self)
+{
+  GtkListBoxRow *row;
+
+  g_return_val_if_fail (IDE_IS_OMNI_SEARCH_GROUP (self), FALSE);
+
+  row = gtk_list_box_get_selected_row (self->rows);
+
+  if (row != NULL)
+    {
+      gint position;
+
+      position = gtk_list_box_row_get_index (row);
+      row = find_nth_row (self->rows, position + 1);
+    }
+  else
+    row = find_nth_row (self->rows, 0);
+
+  if (row != NULL)
+    {
+      gtk_list_box_select_row (self->rows, row);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+gboolean
+ide_omni_search_group_move_previous (IdeOmniSearchGroup *self)
+{
+  GtkListBoxRow *row;
+
+  g_return_val_if_fail (IDE_IS_OMNI_SEARCH_GROUP (self), FALSE);
+
+  row = gtk_list_box_get_selected_row (self->rows);
+
+  if (row != NULL)
+    {
+      gint position;
+
+      position = gtk_list_box_row_get_index (row);
+
+      if (position == 0)
+        return FALSE;
+
+      row = find_nth_row (self->rows, position - 1);
+    }
+  else
+    row = find_nth_row (self->rows, -1);
+
+  if (row != NULL)
+    {
+      gtk_list_box_select_row (self->rows, row);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+gboolean
+ide_omni_search_group_has_selection (IdeOmniSearchGroup *self)
+{
+  g_return_val_if_fail (IDE_IS_OMNI_SEARCH_GROUP (self), FALSE);
+
+  return !!gtk_list_box_get_selected_row (self->rows);
+}
diff --git a/libide/search/ide-omni-search-group.h b/libide/search/ide-omni-search-group.h
index f58d1ec..730c002 100644
--- a/libide/search/ide-omni-search-group.h
+++ b/libide/search/ide-omni-search-group.h
@@ -40,6 +40,9 @@ void               ide_omni_search_group_focus_last    (IdeOmniSearchGroup *grou
 IdeSearchResult   *ide_omni_search_group_get_first     (IdeOmniSearchGroup *group);
 gboolean           ide_omni_search_group_activate      (IdeOmniSearchGroup *group);
 guint64            ide_omni_search_group_get_count     (IdeOmniSearchGroup *self);
+gboolean           ide_omni_search_group_has_selection (IdeOmniSearchGroup *self);
+gboolean           ide_omni_search_group_move_next     (IdeOmniSearchGroup *self);
+gboolean           ide_omni_search_group_move_previous (IdeOmniSearchGroup *self);
 
 G_END_DECLS
 


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