[gnome-text-editor] searchbar: use custom entry for search entry
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-text-editor] searchbar: use custom entry for search entry
- Date: Thu, 7 Oct 2021 00:10:57 +0000 (UTC)
commit 3d373666b86d253a765e6e9c70696962a9f72d5b
Author: Christian Hergert <chergert redhat com>
Date: Wed Oct 6 16:35:10 2021 -0700
searchbar: use custom entry for search entry
This gives us basically what we used to have in GTK 3 with the
GdTaggedEntry but specific for the search bar pattern within Text Editor.
Fixes #147
src/editor-search-bar.c | 39 ++++--
src/editor-search-bar.ui | 5 +-
src/editor-search-entry-private.h | 37 ++++++
src/editor-search-entry.c | 236 +++++++++++++++++++++++++++++++++
src/editor-search-entry.ui | 29 ++++
src/meson.build | 1 +
src/org.gnome.TextEditor.gresource.xml | 1 +
7 files changed, 334 insertions(+), 14 deletions(-)
---
diff --git a/src/editor-search-bar.c b/src/editor-search-bar.c
index 893eff9..0844459 100644
--- a/src/editor-search-bar.c
+++ b/src/editor-search-bar.c
@@ -25,6 +25,7 @@
#include "editor-enums.h"
#include "editor-page-private.h"
#include "editor-search-bar-private.h"
+#include "editor-search-entry-private.h"
#include "editor-utils-private.h"
struct _EditorSearchBar
@@ -36,7 +37,7 @@ struct _EditorSearchBar
GCancellable *cancellable;
GtkGrid *grid;
- GtkEntry *search_entry;
+ EditorSearchEntry *search_entry;
GtkEntry *replace_entry;
GtkButton *replace_button;
GtkButton *replace_all_button;
@@ -84,6 +85,7 @@ update_properties (EditorSearchBar *self)
gboolean can_move = _editor_search_bar_get_can_move (self);
gboolean can_replace = _editor_search_bar_get_can_replace (self);
gboolean can_replace_all = _editor_search_bar_get_can_replace_all (self);
+ int occurrence_position = -1;
if (can_move != self->can_move)
{
@@ -102,6 +104,17 @@ update_properties (EditorSearchBar *self)
self->can_replace_all = can_replace_all;
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_REPLACE_ALL]);
}
+
+ if (self->context != NULL)
+ {
+ GtkTextBuffer *buffer = GTK_TEXT_BUFFER (gtk_source_search_context_get_buffer (self->context));
+ GtkTextIter begin, end;
+
+ if (gtk_text_buffer_get_selection_bounds (buffer, &begin, &end))
+ occurrence_position = gtk_source_search_context_get_occurrence_position (self->context, &begin,
&end);
+ }
+
+ editor_search_entry_set_occurrence_position (self->search_entry, occurrence_position);
}
static void
@@ -116,11 +129,11 @@ editor_search_bar_scroll_to_insert (EditorSearchBar *self)
}
static void
-editor_search_bar_search_activate_cb (EditorSearchBar *self,
- GtkEntry *entry)
+editor_search_bar_search_activate_cb (EditorSearchBar *self,
+ EditorSearchEntry *entry)
{
g_assert (EDITOR_IS_SEARCH_BAR (self));
- g_assert (GTK_IS_ENTRY (entry));
+ g_assert (EDITOR_IS_SEARCH_ENTRY (entry));
_editor_search_bar_move_next (self, TRUE);
}
@@ -303,12 +316,12 @@ on_notify_replace_text_cb (EditorSearchBar *self,
}
static void
-on_notify_search_text_cb (EditorSearchBar *self,
- GParamSpec *pspec,
- GtkEntry *entry)
+on_notify_search_text_cb (EditorSearchBar *self,
+ GParamSpec *pspec,
+ EditorSearchEntry *entry)
{
g_assert (EDITOR_IS_SEARCH_BAR (self));
- g_assert (GTK_IS_ENTRY (entry));
+ g_assert (EDITOR_IS_SEARCH_ENTRY (entry));
self->scroll_to_first_match = TRUE;
}
@@ -515,6 +528,8 @@ editor_search_bar_class_init (EditorSearchBarClass *klass)
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
+
+ g_type_ensure (EDITOR_TYPE_SEARCH_ENTRY);
}
static void
@@ -611,11 +626,15 @@ editor_search_bar_notify_occurrences_count_cb (EditorSearchBar *self,
GParamSpec *pspec,
GtkSourceSearchContext *context)
{
+ guint occurrence_count;
+
g_assert (EDITOR_IS_SEARCH_BAR (self));
g_assert (GTK_SOURCE_IS_SEARCH_CONTEXT (context));
- if (self->scroll_to_first_match &&
- gtk_source_search_context_get_occurrences_count (context) > 0)
+ occurrence_count = gtk_source_search_context_get_occurrences_count (context);
+ editor_search_entry_set_occurrence_count (self->search_entry, occurrence_count);
+
+ if (self->scroll_to_first_match && occurrence_count > 0)
scroll_to_first_match (self, context);
update_properties (self);
diff --git a/src/editor-search-bar.ui b/src/editor-search-bar.ui
index 08ead7a..8f03f23 100644
--- a/src/editor-search-bar.ui
+++ b/src/editor-search-bar.ui
@@ -10,11 +10,8 @@
<property name="column-spacing">8</property>
<property name="row-spacing">8</property>
<child>
- <object class="GtkEntry" id="search_entry">
- <property name="primary-icon-name">edit-find-symbolic</property>
- <property name="max-width-chars">20</property>
+ <object class="EditorSearchEntry" id="search_entry">
<property name="hexpand">true</property>
- <property name="placeholder-text" translatable="yes">Search</property>
<signal name="activate" handler="editor_search_bar_search_activate_cb" swapped="true"
object="EditorSearchBar"/>
<layout>
<property name="row">0</property>
diff --git a/src/editor-search-entry-private.h b/src/editor-search-entry-private.h
new file mode 100644
index 0000000..cd2bf2c
--- /dev/null
+++ b/src/editor-search-entry-private.h
@@ -0,0 +1,37 @@
+/* editor-search-entry-private.h
+ *
+ * Copyright 2021 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EDITOR_TYPE_SEARCH_ENTRY (editor_search_entry_get_type())
+
+G_DECLARE_FINAL_TYPE (EditorSearchEntry, editor_search_entry, EDITOR, SEARCH_ENTRY, GtkWidget)
+
+GtkWidget *editor_search_entry_new (void);
+void editor_search_entry_set_occurrence_count (EditorSearchEntry *self,
+ guint occurrence_count);
+void editor_search_entry_set_occurrence_position (EditorSearchEntry *self,
+ int occurrence_position);
+
+G_END_DECLS
diff --git a/src/editor-search-entry.c b/src/editor-search-entry.c
new file mode 100644
index 0000000..d821de4
--- /dev/null
+++ b/src/editor-search-entry.c
@@ -0,0 +1,236 @@
+/* editor-search-entry.c
+ *
+ * Copyright 2021 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "editor-search-entry-private.h"
+
+struct _EditorSearchEntry
+{
+ GtkWidget parent_instance;
+
+ GtkText *text;
+ GtkLabel *info;
+
+ guint occurrence_count;
+ int occurrence_position;
+};
+
+static void editable_iface_init (GtkEditableInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EditorSearchEntry, editor_search_entry, GTK_TYPE_WIDGET,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, editable_iface_init))
+
+enum {
+ ACTIVATE,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
+GtkWidget *
+editor_search_entry_new (void)
+{
+ return g_object_new (EDITOR_TYPE_SEARCH_ENTRY, NULL);
+}
+
+static gboolean
+editor_search_entry_grab_focus (GtkWidget *widget)
+{
+ return gtk_widget_grab_focus (GTK_WIDGET (EDITOR_SEARCH_ENTRY (widget)->text));
+}
+
+static void
+on_text_activate_cb (EditorSearchEntry *self,
+ GtkText *text)
+{
+ g_assert (EDITOR_IS_SEARCH_ENTRY (self));
+ g_assert (GTK_IS_TEXT (text));
+
+ g_signal_emit (self, signals [ACTIVATE], 0);
+}
+
+static void
+on_text_notify_cb (EditorSearchEntry *self,
+ GParamSpec *pspec,
+ GtkText *text)
+{
+ GObjectClass *klass;
+
+ g_assert (EDITOR_IS_SEARCH_ENTRY (self));
+ g_assert (GTK_IS_TEXT (text));
+
+ klass = G_OBJECT_GET_CLASS (self);
+ pspec = g_object_class_find_property (klass, pspec->name);
+
+ if (pspec != NULL)
+ g_object_notify_by_pspec (G_OBJECT (self), pspec);
+}
+
+static void
+editor_search_entry_dispose (GObject *object)
+{
+ EditorSearchEntry *self = (EditorSearchEntry *)object;
+ GtkWidget *child;
+
+ self->text = NULL;
+ self->info = NULL;
+
+ while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))))
+ gtk_widget_unparent (child);
+
+ G_OBJECT_CLASS (editor_search_entry_parent_class)->dispose (object);
+}
+
+static void
+editor_search_entry_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ if (gtk_editable_delegate_get_property (object, prop_id, value, pspec))
+ return;
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+}
+
+static void
+editor_search_entry_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ if (gtk_editable_delegate_set_property (object, prop_id, value, pspec))
+ return;
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+}
+
+static void
+editor_search_entry_class_init (EditorSearchEntryClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->dispose = editor_search_entry_dispose;
+ object_class->get_property = editor_search_entry_get_property;
+ object_class->set_property = editor_search_entry_set_property;
+
+ widget_class->grab_focus = editor_search_entry_grab_focus;
+
+ gtk_editable_install_properties (object_class, 1);
+
+ signals[ACTIVATE] =
+ g_signal_new ("activate",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+ gtk_widget_class_set_activate_signal (widget_class, signals[ACTIVATE]);
+ gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT);
+ gtk_widget_class_set_css_name (widget_class, "entry");
+ gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_TEXT_BOX);
+ gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/TextEditor/ui/editor-search-entry.ui");
+ gtk_widget_class_bind_template_child (widget_class, EditorSearchEntry, info);
+ gtk_widget_class_bind_template_child (widget_class, EditorSearchEntry, text);
+ gtk_widget_class_bind_template_callback (widget_class, on_text_activate_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_text_notify_cb);
+}
+
+static void
+editor_search_entry_init (EditorSearchEntry *self)
+{
+ cairo_font_options_t *options;
+
+ self->occurrence_position = -1;
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ options = cairo_font_options_create ();
+ cairo_font_options_set_variations (options, "tnum");
+ gtk_widget_set_font_options (GTK_WIDGET (self->info), options);
+ cairo_font_options_destroy (options);
+}
+
+static GtkEditable *
+editor_search_entry_get_delegate (GtkEditable *editable)
+{
+ return GTK_EDITABLE (EDITOR_SEARCH_ENTRY (editable)->text);
+}
+
+static void
+editable_iface_init (GtkEditableInterface *iface)
+{
+ iface->get_delegate = editor_search_entry_get_delegate;
+}
+
+static void
+editor_search_entry_update_position (EditorSearchEntry *self)
+{
+ const char *text;
+
+ g_assert (EDITOR_IS_SEARCH_ENTRY (self));
+
+ text = gtk_editable_get_text (GTK_EDITABLE (self->text));
+
+ if (self->occurrence_count == 0)
+ {
+ gtk_label_set_label (self->info, NULL);
+ }
+ else
+ {
+ /* translators: the first %u is replaced with the current position, the second with the number of
search results */
+ g_autofree char *str = g_strdup_printf (_("%u of %u"), MAX (0, self->occurrence_position),
self->occurrence_count);
+ gtk_label_set_label (self->info, str);
+ }
+}
+
+void
+editor_search_entry_set_occurrence_count (EditorSearchEntry *self,
+ guint occurrence_count)
+{
+ g_assert (EDITOR_IS_SEARCH_ENTRY (self));
+
+ if (self->occurrence_count != occurrence_count)
+ {
+ self->occurrence_count = occurrence_count;
+ editor_search_entry_update_position (self);
+ }
+}
+
+void
+editor_search_entry_set_occurrence_position (EditorSearchEntry *self,
+ int occurrence_position)
+{
+ g_assert (EDITOR_IS_SEARCH_ENTRY (self));
+
+ occurrence_position = MAX (-1, occurrence_position);
+
+ if (self->occurrence_position != occurrence_position)
+ {
+ self->occurrence_position = occurrence_position;
+ editor_search_entry_update_position (self);
+ }
+}
diff --git a/src/editor-search-entry.ui b/src/editor-search-entry.ui
new file mode 100644
index 0000000..1ad300a
--- /dev/null
+++ b/src/editor-search-entry.ui
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="EditorSearchEntry" parent="GtkWidget">
+ <property name="width-request">225</property>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">edit-find-symbolic</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkText" id="text">
+ <property name="hexpand">true</property>
+ <property name="vexpand">true</property>
+ <property name="width-chars">12</property>
+ <property name="max-width-chars">12</property>
+ <signal name="notify" handler="on_text_notify_cb" swapped="true"/>
+ <signal name="activate" handler="on_text_activate_cb" swapped="true"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="info">
+ <property name="xalign">1</property>
+ <attributes>
+ <attribute name="foreground-alpha" value="33000"/>
+ </attributes>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/meson.build b/src/meson.build
index 9959ecf..8cd3f8f 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -26,6 +26,7 @@ editor_sources = [
'editor-print-operation.c',
'editor-save-changes-dialog.c',
'editor-search-bar.c',
+ 'editor-search-entry.c',
'editor-session.c',
'editor-sidebar-item.c',
'editor-sidebar-model.c',
diff --git a/src/org.gnome.TextEditor.gresource.xml b/src/org.gnome.TextEditor.gresource.xml
index 4c5240f..8974c37 100644
--- a/src/org.gnome.TextEditor.gresource.xml
+++ b/src/org.gnome.TextEditor.gresource.xml
@@ -8,6 +8,7 @@
<file preprocess="xml-stripblanks">editor-page.ui</file>
<file preprocess="xml-stripblanks">editor-position-label.ui</file>
<file preprocess="xml-stripblanks">editor-search-bar.ui</file>
+ <file preprocess="xml-stripblanks">editor-search-entry.ui</file>
<file preprocess="xml-stripblanks">editor-sidebar-row.ui</file>
<file preprocess="xml-stripblanks">editor-sidebar.ui</file>
<file preprocess="xml-stripblanks">editor-theme-selector.ui</file>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]