[gnome-builder/wip/libide-merge] editor: bring back rubberbanding search



commit 00216a5801f3fac4bf1ad1a12ede5bac94773fc8
Author: Christian Hergert <christian hergert me>
Date:   Mon Mar 23 16:09:12 2015 -0700

    editor: bring back rubberbanding search

 libide/ide-source-view.c             |  169 +++++++++++++++++++++++++++++++++-
 libide/ide-source-view.h             |    4 +
 src/editor/gb-editor-frame-actions.c |    4 +
 src/editor/gb-editor-frame.c         |   14 +++
 4 files changed, 187 insertions(+), 4 deletions(-)
---
diff --git a/libide/ide-source-view.c b/libide/ide-source-view.c
index e16dfda..c2d8549 100644
--- a/libide/ide-source-view.c
+++ b/libide/ide-source-view.c
@@ -88,6 +88,8 @@ typedef struct
   IdeSourceViewCapture        *capture;
   IdeSourceViewMode           *mode;
   GList                       *providers;
+  GtkTextMark                 *rubberband_mark;
+  GtkTextMark                 *rubberband_insert_mark;
   gchar                       *saved_search_text;
   GQueue                      *selections;
   GQueue                      *snippets;
@@ -138,6 +140,7 @@ typedef struct
   guint                        insert_matching_brace : 1;
   guint                        overwrite_braces : 1;
   guint                        recording_macro : 1;
+  guint                        rubberband_search : 1;
   guint                        show_grid_lines : 1;
   guint                        show_line_changes : 1;
   guint                        show_search_bubbles : 1;
@@ -173,6 +176,7 @@ enum {
   PROP_INSERT_MATCHING_BRACE,
   PROP_OVERWRITE,
   PROP_OVERWRITE_BRACES,
+  PROP_RUBBERBAND_SEARCH,
   PROP_SCROLL_OFFSET,
   PROP_SEARCH_CONTEXT,
   PROP_SHOW_GRID_LINES,
@@ -1055,6 +1059,40 @@ ide_source_view__buffer_changed_cb (IdeSourceView *self,
 }
 
 static void
+ide_source_view__search_settings_notify_search_text (IdeSourceView           *self,
+                                                     GParamSpec              *pspec,
+                                                     GtkSourceSearchSettings *search_settings)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+  const gchar *search_text;
+
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+  g_assert (GTK_SOURCE_IS_SEARCH_SETTINGS (search_settings));
+
+  search_text = gtk_source_search_settings_get_search_text (search_settings);
+
+  /*
+   * If we have IdeSourceView:rubberband-search enabled, then we should try to
+   * autoscroll to the next search result starting from our saved search mark.
+   */
+  if ((search_text != NULL) && (search_text [0] != '\0') &&
+      priv->rubberband_search && (priv->rubberband_insert_mark != NULL))
+    {
+      GtkTextBuffer *buffer;
+      GtkTextIter begin_iter;
+      GtkTextIter match_begin;
+      GtkTextIter match_end;
+
+      buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self));
+      gtk_text_buffer_get_iter_at_mark (buffer, &begin_iter, priv->rubberband_insert_mark);
+
+      if (gtk_source_search_context_forward (priv->search_context, &begin_iter,
+                                             &match_begin, &match_end))
+        ide_source_view_scroll_to_iter (self, &match_begin, 0.25, TRUE, 1.0, 0.5, TRUE);
+    }
+}
+
+static void
 ide_source_view_rebuild_css (IdeSourceView *self)
 {
   IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
@@ -1402,11 +1440,26 @@ ide_source_view_connect_buffer (IdeSourceView *self,
                                        "highlight", TRUE,
                                        "settings", search_settings,
                                        NULL);
+
+  g_signal_connect_object (search_settings,
+                           "notify::search-text",
+                           G_CALLBACK (ide_source_view__search_settings_notify_search_text),
+                           self,
+                           G_CONNECT_SWAPPED);
+
   g_clear_object (&search_settings);
 
+  /* Create scroll mark used by movements */
   gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
   gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (buffer), "scroll-mark", &iter, TRUE);
 
+  /* Create rubberband mark used by search rubberbanding */
+  priv->rubberband_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (buffer),
+                                                       "rubberband-search", &iter, TRUE);
+  priv->rubberband_insert_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (buffer),
+                                                              "rubberband-search-insert",
+                                                              &iter, TRUE);
+
   ide_source_view__buffer_notify_language_cb (self, NULL, buffer);
   ide_source_view__buffer_notify_file_cb (self, NULL, buffer);
   ide_source_view__buffer_notify_highlight_diagnostics_cb (self, NULL, buffer);
@@ -3072,6 +3125,7 @@ ide_source_view__search_forward_cb (GObject      *object,
                                     gpointer      user_data)
 {
   GtkSourceSearchContext *search_context = (GtkSourceSearchContext *)object;
+  IdeSourceViewPrivate *priv;
   GtkTextBuffer *buffer;
   GtkTextMark *insert;
   GtkTextIter begin;
@@ -3083,12 +3137,23 @@ ide_source_view__search_forward_cb (GObject      *object,
   g_assert (mv);
   g_assert (IDE_IS_SOURCE_VIEW (mv->self));
 
+  priv = ide_source_view_get_instance_private (mv->self);
+
   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (mv->self));
   insert = gtk_text_buffer_get_insert (buffer);
 
-  /* todo: rubberband back to start? */
   if (!gtk_source_search_context_forward_finish (search_context, result, &begin, &end, &error))
-    return;
+    {
+      /*
+       * If we didn't find a match, scroll back to the position when the search
+       * started.
+       */
+      if (priv->rubberband_search)
+        {
+          ide_source_view_rollback_search (mv->self);
+          return;
+        }
+    }
 
   mv->count--;
 
@@ -3130,6 +3195,7 @@ ide_source_view__search_backward_cb (GObject      *object,
                                      gpointer      user_data)
 {
   GtkSourceSearchContext *search_context = (GtkSourceSearchContext *)object;
+  IdeSourceViewPrivate *priv;
   GtkTextBuffer *buffer;
   GtkTextMark *insert;
   GtkTextIter begin;
@@ -3141,12 +3207,23 @@ ide_source_view__search_backward_cb (GObject      *object,
   g_assert (mv);
   g_assert (IDE_IS_SOURCE_VIEW (mv->self));
 
+  priv = ide_source_view_get_instance_private (mv->self);
+
   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (mv->self));
   insert = gtk_text_buffer_get_insert (buffer);
 
-  /* todo: rubberband back to start? */
   if (!gtk_source_search_context_backward_finish (search_context, result, &begin, &end, &error))
-    return;
+    {
+      /*
+       * If we didn't find a match, scroll back to the position when the search
+       * started.
+       */
+      if (priv->rubberband_search)
+        {
+          ide_source_view_rollback_search (mv->self);
+          return;
+        }
+    }
 
   mv->count--;
 
@@ -4499,6 +4576,10 @@ ide_source_view_get_property (GObject    *object,
       g_value_set_boolean (value, ide_source_view_get_overwrite_braces (self));
       break;
 
+    case PROP_RUBBERBAND_SEARCH:
+      g_value_set_boolean (value, ide_source_view_get_rubberband_search (self));
+      break;
+
     case PROP_SCROLL_OFFSET:
       g_value_set_uint (value, ide_source_view_get_scroll_offset (self));
       break;
@@ -4588,6 +4669,10 @@ ide_source_view_set_property (GObject      *object,
       ide_source_view_set_overwrite_braces (self, g_value_get_boolean (value));
       break;
 
+    case PROP_RUBBERBAND_SEARCH:
+      ide_source_view_set_rubberband_search (self, g_value_get_boolean (value));
+      break;
+
     case PROP_SCROLL_OFFSET:
       ide_source_view_set_scroll_offset (self, g_value_get_uint (value));
       break;
@@ -4764,6 +4849,15 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
   g_object_class_install_property (object_class, PROP_OVERWRITE_BRACES,
                                    gParamSpecs [PROP_OVERWRITE_BRACES]);
 
+  gParamSpecs [PROP_RUBBERBAND_SEARCH] =
+    g_param_spec_boolean ("rubberband-search",
+                          _("Rubberband Search"),
+                          _("Auto scroll to next search result without moving insertion caret."),
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_RUBBERBAND_SEARCH,
+                                   gParamSpecs [PROP_RUBBERBAND_SEARCH]);
+
   gParamSpecs [PROP_SCROLL_OFFSET] =
     g_param_spec_uint ("scroll-offset",
                        _("Scroll Offset"),
@@ -6377,3 +6471,70 @@ ide_source_view_set_count (IdeSourceView *self,
       g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_COUNT]);
     }
 }
+
+gboolean
+ide_source_view_get_rubberband_search (IdeSourceView *self)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+
+  g_return_val_if_fail (IDE_IS_SOURCE_VIEW (self), FALSE);
+
+  return priv->rubberband_search;
+}
+
+void
+ide_source_view_set_rubberband_search (IdeSourceView *self,
+                                       gboolean       rubberband_search)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+
+  g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
+
+  rubberband_search = !!rubberband_search;
+
+  if (rubberband_search != priv->rubberband_search)
+    {
+      priv->rubberband_search = rubberband_search;
+
+      if (priv->rubberband_search && (priv->rubberband_mark != NULL))
+        {
+          GtkTextBuffer *buffer;
+          GtkTextMark *insert;
+          GtkTextIter iter;
+          GdkRectangle rect;
+
+          /*
+           * The rubberbound_mark is the top-left position of the sourceview
+           * currently (for the beginning of the search). We use this so that
+           * we can restore the sourceview vadjustment to the proper position
+           * when rubberbanding back to the original position. The
+           * rubberband_insert_mark is the position after the current insert
+           * mark so that we will begin incremental searches after the current
+           * cursor.
+           */
+
+          buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self));
+          insert = gtk_text_buffer_get_insert (buffer);
+
+          gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (self), &rect);
+          gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (self), &iter, rect.x+1, rect.y+1);
+          gtk_text_buffer_move_mark (buffer, priv->rubberband_mark, &iter);
+
+          gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
+          gtk_text_iter_forward_char (&iter);
+          gtk_text_buffer_move_mark (buffer, priv->rubberband_insert_mark, &iter);
+        }
+
+      g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_RUBBERBAND_SEARCH]);
+    }
+}
+
+void
+ide_source_view_rollback_search (IdeSourceView *self)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+
+  g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
+
+  gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (self), priv->rubberband_mark, 0.0, TRUE, 0.0, 1.0);
+}
diff --git a/libide/ide-source-view.h b/libide/ide-source-view.h
index 7235ed4..258bd7f 100644
--- a/libide/ide-source-view.h
+++ b/libide/ide-source-view.h
@@ -287,6 +287,7 @@ const PangoFontDescription *ide_source_view_get_font_desc             (IdeSource
 gboolean                    ide_source_view_get_highlight_current_line(IdeSourceView              *self);
 gboolean                    ide_source_view_get_insert_matching_brace (IdeSourceView              *self);
 gboolean                    ide_source_view_get_overwrite_braces      (IdeSourceView              *self);
+gboolean                    ide_source_view_get_rubberband_search     (IdeSourceView              *self);
 guint                       ide_source_view_get_scroll_offset         (IdeSourceView              *self);
 GtkSourceSearchContext     *ide_source_view_get_search_context        (IdeSourceView              *self);
 gboolean                    ide_source_view_get_show_grid_lines       (IdeSourceView              *self);
@@ -303,6 +304,7 @@ void                        ide_source_view_jump                      (IdeSource
 void                        ide_source_view_pop_snippet               (IdeSourceView              *self);
 void                        ide_source_view_push_snippet              (IdeSourceView              *self,
                                                                        IdeSourceSnippet           *snippet);
+void                        ide_source_view_rollback_search           (IdeSourceView              *self);
 void                        ide_source_view_set_count                 (IdeSourceView              *self,
                                                                        guint                       count);
 void                        ide_source_view_set_enable_word_completion(IdeSourceView              *self,
@@ -317,6 +319,8 @@ void                        ide_source_view_set_insert_matching_brace (IdeSource
                                                                        gboolean                    
insert_matching_brace);
 void                        ide_source_view_set_overwrite_braces      (IdeSourceView              *self,
                                                                        gboolean                    
overwrite_braces);
+void                        ide_source_view_set_rubberband_search     (IdeSourceView              *self,
+                                                                       gboolean                    
rubberband_search);
 void                        ide_source_view_set_scroll_offset         (IdeSourceView              *self,
                                                                        guint                       
scroll_offset);
 void                        ide_source_view_set_show_grid_lines       (IdeSourceView              *self,
diff --git a/src/editor/gb-editor-frame-actions.c b/src/editor/gb-editor-frame-actions.c
index f6262ac..eb5844d 100644
--- a/src/editor/gb-editor-frame-actions.c
+++ b/src/editor/gb-editor-frame-actions.c
@@ -43,6 +43,8 @@ gb_editor_frame_actions_next_search_result (GSimpleAction *action,
 
   g_assert (GB_IS_EDITOR_FRAME (self));
 
+  ide_source_view_set_rubberband_search (self->source_view, FALSE);
+
   IDE_SOURCE_VIEW_GET_CLASS (self->source_view)->move_search
     (self->source_view, GTK_DIR_DOWN, FALSE, TRUE, TRUE, FALSE, FALSE);
 }
@@ -56,6 +58,8 @@ gb_editor_frame_actions_previous_search_result (GSimpleAction *action,
 
   g_assert (GB_IS_EDITOR_FRAME (self));
 
+  ide_source_view_set_rubberband_search (self->source_view, FALSE);
+
   IDE_SOURCE_VIEW_GET_CLASS (self->source_view)->move_search
     (self->source_view, GTK_DIR_UP, FALSE, TRUE, TRUE, FALSE, FALSE);
 }
diff --git a/src/editor/gb-editor-frame.c b/src/editor/gb-editor-frame.c
index c3fb26b..081615b 100644
--- a/src/editor/gb-editor-frame.c
+++ b/src/editor/gb-editor-frame.c
@@ -313,7 +313,9 @@ gb_editor_frame__search_key_press_event (GbEditorFrame *self,
   switch (event->keyval)
     {
     case GDK_KEY_Escape:
+      ide_source_view_rollback_search (self->source_view);
       ide_source_view_clear_search (self->source_view);
+      ide_source_view_set_rubberband_search (self->source_view, FALSE);
       gtk_widget_grab_focus (GTK_WIDGET (self->source_view));
       return TRUE;
 
@@ -323,6 +325,7 @@ gb_editor_frame__search_key_press_event (GbEditorFrame *self,
         gb_widget_activate_action (GTK_WIDGET (self), "frame", "next-search-result", NULL);
       else
         gb_widget_activate_action (GTK_WIDGET (self), "frame", "previous-search-result", NULL);
+      ide_source_view_set_rubberband_search (self->source_view, FALSE);
       gtk_widget_grab_focus (GTK_WIDGET (self->source_view));
       return TRUE;
 
@@ -339,6 +342,9 @@ gb_editor_frame__search_key_press_event (GbEditorFrame *self,
         GtkSourceSearchSettings *search_settings;
         GtkSourceSearchContext *search_context;
 
+        if (!ide_source_view_get_rubberband_search (self->source_view))
+          ide_source_view_set_rubberband_search (self->source_view, TRUE);
+
         /*
          * Other modes, such as Vim emulation, want word boundaries, but we do
          * not when searching from this entry. Sort of hacky, but gets the job
@@ -555,6 +561,14 @@ gb_editor_frame_init (GbEditorFrame *self)
   g_object_bind_property (self->source_view, "overwrite", self->overwrite_label, "visible", 
G_BINDING_SYNC_CREATE);
 
   /*
+   * we want to rubberbanding search until enter has been pressed or next/previous actions
+   * have been activated.
+   */
+  g_object_bind_property (self->search_revealer, "visible",
+                          self->source_view, "rubberband-search",
+                          G_BINDING_SYNC_CREATE);
+
+  /*
    * Drag and drop support
    */
   target_list = gtk_drag_dest_get_target_list (GTK_WIDGET (self->source_view));


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