[nautilus/wip/ernestask/gtk4-continued: 22/144] query-editor: Use GTK+ 4 tagged entry
- From: Ernestas Kulik <ernestask src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nautilus/wip/ernestask/gtk4-continued: 22/144] query-editor: Use GTK+ 4 tagged entry
- Date: Mon, 11 Feb 2019 13:21:17 +0000 (UTC)
commit 3ea372a70c642df8f89f1b6f5687ef2e576adbca
Author: Ernestas Kulik <ernestask gnome org>
Date: Mon Jul 2 10:00:17 2018 +0300
query-editor: Use GTK+ 4 tagged entry
src/libgd/gd-tagged-entry.c | 1242 ---------------------------------------
src/libgd/gd-tagged-entry.h | 117 ----
src/meson.build | 6 +-
src/nautilus-query-editor.c | 152 ++---
src/nautilus-tagged-entry-tag.c | 499 ++++++++++++++++
src/nautilus-tagged-entry-tag.h | 38 ++
src/nautilus-tagged-entry.c | 311 ++++++++++
src/nautilus-tagged-entry.h | 39 ++
src/resources/css/Adwaita.css | 5 -
9 files changed, 977 insertions(+), 1432 deletions(-)
---
diff --git a/src/meson.build b/src/meson.build
index c863198f4..d2d20a162 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -64,8 +64,6 @@ libnautilus_sources = [
'gtk/nautilusgtkplacesviewrowprivate.h',
'libgd/gd-styled-text-renderer.c',
'libgd/gd-styled-text-renderer.h',
- 'libgd/gd-tagged-entry.c',
- 'libgd/gd-tagged-entry.h',
'nautilus-application.c',
'nautilus-application.h',
'nautilus-bookmark-list.c',
@@ -274,6 +272,10 @@ libnautilus_sources = [
'nautilus-types.h',
'nautilus-tracker-utilities.c',
'nautilus-tracker-utilities.h',
+ 'nautilus-tagged-entry.c',
+ 'nautilus-tagged-entry.h',
+ 'nautilus-tagged-entry-tag.c',
+ 'nautilus-tagged-entry-tag.h',
]
nautilus_deps = [
diff --git a/src/nautilus-query-editor.c b/src/nautilus-query-editor.c
index 382a0eb10..91de11ea8 100644
--- a/src/nautilus-query-editor.c
+++ b/src/nautilus-query-editor.c
@@ -28,13 +28,14 @@
#include <gtk/gtk.h>
#include <string.h>
-#include "libgd/gd-tagged-entry.h"
#include "nautilus-file.h"
#include "nautilus-file-utilities.h"
#include "nautilus-global-preferences.h"
#include "nautilus-search-directory.h"
#include "nautilus-search-popover.h"
#include "nautilus-mime-actions.h"
+#include "nautilus-tagged-entry.h"
+#include "nautilus-tagged-entry-tag.h"
#include "nautilus-ui-utilities.h"
struct _NautilusQueryEditor
@@ -45,8 +46,8 @@ struct _NautilusQueryEditor
GtkWidget *popover;
GtkWidget *dropdown_button;
- GdTaggedEntryTag *mime_types_tag;
- GdTaggedEntryTag *date_range_tag;
+ GtkWidget *mime_types_tag;
+ GtkWidget *date_range_tag;
gboolean change_frozen;
@@ -217,19 +218,6 @@ nautilus_query_editor_set_property (GObject *object,
}
}
-static void
-nautilus_query_editor_finalize (GObject *object)
-{
- NautilusQueryEditor *editor;
-
- editor = NAUTILUS_QUERY_EDITOR (object);
-
- g_clear_object (&editor->date_range_tag);
- g_clear_object (&editor->mime_types_tag);
-
- G_OBJECT_CLASS (nautilus_query_editor_parent_class)->finalize (object);
-}
-
static void
nautilus_query_editor_class_init (NautilusQueryEditorClass *class)
{
@@ -237,7 +225,6 @@ nautilus_query_editor_class_init (NautilusQueryEditorClass *class)
GtkWidgetClass *widget_class;
gobject_class = G_OBJECT_CLASS (class);
- gobject_class->finalize = nautilus_query_editor_finalize;
gobject_class->dispose = nautilus_query_editor_dispose;
gobject_class->get_property = nautilus_query_editor_get_property;
gobject_class->set_property = nautilus_query_editor_set_property;
@@ -400,12 +387,38 @@ nautilus_query_editor_on_stop_search (GtkWidget *entry,
static void
nautilus_query_editor_init (NautilusQueryEditor *editor)
{
+ editor->mime_types_tag = NULL;
+ editor->date_range_tag = NULL;
+
g_signal_connect (nautilus_preferences,
"changed::recursive-search",
G_CALLBACK (recursive_search_preferences_changed),
editor);
}
+static void
+on_date_range_tag_button_clicked (NautilusTaggedEntryTag *tag,
+ gpointer user_data)
+{
+ NautilusQueryEditor *editor;
+
+ editor = user_data;
+
+ nautilus_search_popover_reset_date_range (NAUTILUS_SEARCH_POPOVER (editor->popover));
+}
+
+static void
+entry_tag_clicked (NautilusTaggedEntryTag *tag,
+ gpointer user_data)
+{
+ NautilusQueryEditor *editor;
+
+ editor = user_data;
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (editor->dropdown_button),
+ TRUE);
+}
+
static void
search_popover_date_range_changed_cb (NautilusSearchPopover *popover,
GPtrArray *date_range,
@@ -420,17 +433,25 @@ search_popover_date_range_changed_cb (NautilusSearchPopover *popover,
create_query (editor);
}
- gd_tagged_entry_remove_tag (GD_TAGGED_ENTRY (editor->entry),
- editor->date_range_tag);
+ g_clear_pointer (&editor->date_range_tag, gtk_widget_destroy);
+
if (date_range)
{
g_autofree gchar *text_for_date_range = NULL;
text_for_date_range = get_text_for_date_range (date_range, TRUE);
- gd_tagged_entry_tag_set_label (editor->date_range_tag,
- text_for_date_range);
- gd_tagged_entry_add_tag (GD_TAGGED_ENTRY (editor->entry),
- GD_TAGGED_ENTRY_TAG (editor->date_range_tag));
+
+ editor->date_range_tag = nautilus_tagged_entry_tag_new (text_for_date_range);
+
+ nautilus_tagged_entry_add_tag (NAUTILUS_TAGGED_ENTRY (editor->entry),
+ NAUTILUS_TAGGED_ENTRY_TAG (editor->date_range_tag));
+
+ g_signal_connect (editor->date_range_tag,
+ "button-clicked", G_CALLBACK (on_date_range_tag_button_clicked),
+ editor);
+ g_signal_connect (editor->date_range_tag,
+ "clicked", G_CALLBACK (entry_tag_clicked),
+ editor);
}
nautilus_query_set_date_range (editor->query, date_range);
@@ -438,6 +459,17 @@ search_popover_date_range_changed_cb (NautilusSearchPopover *popover,
nautilus_query_editor_changed (editor);
}
+static void
+on_mime_types_tag_button_clicked (NautilusTaggedEntryTag *tag,
+ gpointer user_data)
+{
+ NautilusQueryEditor *editor;
+
+ editor = user_data;
+
+ nautilus_search_popover_reset_mime_types (NAUTILUS_SEARCH_POPOVER (editor->popover));
+}
+
static void
search_popover_mime_type_changed_cb (NautilusSearchPopover *popover,
gint mimetype_group,
@@ -454,8 +486,8 @@ search_popover_mime_type_changed_cb (NautilusSearchPopover *popover,
create_query (editor);
}
- gd_tagged_entry_remove_tag (GD_TAGGED_ENTRY (editor->entry),
- editor->mime_types_tag);
+ g_clear_pointer (&editor->mime_types_tag, gtk_widget_destroy);
+
/* group 0 is anything */
if (mimetype_group == 0)
{
@@ -463,11 +495,23 @@ search_popover_mime_type_changed_cb (NautilusSearchPopover *popover,
}
else if (mimetype_group > 0)
{
+ const gchar *label;
+
+ label = nautilus_mime_types_group_get_name (mimetype_group);
+
mimetypes = nautilus_mime_types_group_get_mimetypes (mimetype_group);
- gd_tagged_entry_tag_set_label (editor->mime_types_tag,
- nautilus_mime_types_group_get_name (mimetype_group));
- gd_tagged_entry_add_tag (GD_TAGGED_ENTRY (editor->entry),
- GD_TAGGED_ENTRY_TAG (editor->mime_types_tag));
+
+ editor->mime_types_tag = nautilus_tagged_entry_tag_new (label);
+
+ nautilus_tagged_entry_add_tag (NAUTILUS_TAGGED_ENTRY (editor->entry),
+ NAUTILUS_TAGGED_ENTRY_TAG (editor->mime_types_tag));
+
+ g_signal_connect (editor->mime_types_tag,
+ "button-clicked", G_CALLBACK (on_mime_types_tag_button_clicked),
+ editor);
+ g_signal_connect (editor->mime_types_tag,
+ "clicked", G_CALLBACK (entry_tag_clicked),
+ editor);
}
else
{
@@ -476,9 +520,18 @@ search_popover_mime_type_changed_cb (NautilusSearchPopover *popover,
mimetypes = g_ptr_array_new_full (1, g_free);
g_ptr_array_add (mimetypes, g_strdup (mimetype));
display_name = g_content_type_get_description (mimetype);
- gd_tagged_entry_tag_set_label (editor->mime_types_tag, display_name);
- gd_tagged_entry_add_tag (GD_TAGGED_ENTRY (editor->entry),
- GD_TAGGED_ENTRY_TAG (editor->mime_types_tag));
+
+ editor->mime_types_tag = nautilus_tagged_entry_tag_new (display_name);
+
+ nautilus_tagged_entry_add_tag (NAUTILUS_TAGGED_ENTRY (editor->entry),
+ NAUTILUS_TAGGED_ENTRY_TAG (editor->mime_types_tag));
+
+ g_signal_connect (editor->mime_types_tag,
+ "button-clicked", G_CALLBACK (on_mime_types_tag_button_clicked),
+ editor);
+ g_signal_connect (editor->mime_types_tag,
+ "clicked", G_CALLBACK (entry_tag_clicked),
+ editor);
}
nautilus_query_set_mime_types (editor->query, mimetypes);
@@ -524,27 +577,6 @@ search_popover_fts_changed_cb (GObject *popover,
nautilus_query_editor_changed (editor);
}
-static void
-entry_tag_clicked (NautilusQueryEditor *editor)
-{
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (editor->dropdown_button),
- TRUE);
-}
-
-static void
-entry_tag_close_button_clicked (NautilusQueryEditor *editor,
- GdTaggedEntryTag *tag)
-{
- if (tag == editor->mime_types_tag)
- {
- nautilus_search_popover_reset_mime_types (NAUTILUS_SEARCH_POPOVER (editor->popover));
- }
- else
- {
- nautilus_search_popover_reset_date_range (NAUTILUS_SEARCH_POPOVER (editor->popover));
- }
-}
-
static void
setup_widgets (NautilusQueryEditor *editor)
{
@@ -561,23 +593,11 @@ setup_widgets (NautilusQueryEditor *editor)
gtk_container_add (GTK_CONTAINER (vbox), hbox);
/* create the search entry */
- editor->entry = GTK_WIDGET (gd_tagged_entry_new ());
+ editor->entry = nautilus_tagged_entry_new ();
gtk_widget_set_hexpand (editor->entry, TRUE);
gtk_container_add (GTK_CONTAINER (hbox), editor->entry);
- editor->mime_types_tag = gd_tagged_entry_tag_new (NULL);
- editor->date_range_tag = gd_tagged_entry_tag_new (NULL);
-
- g_signal_connect_swapped (editor->entry,
- "tag-clicked",
- G_CALLBACK (entry_tag_clicked),
- editor);
- g_signal_connect_swapped (editor->entry,
- "tag-button-clicked",
- G_CALLBACK (entry_tag_close_button_clicked),
- editor);
-
/* setup the search popover */
editor->popover = nautilus_search_popover_new ();
diff --git a/src/nautilus-tagged-entry-tag.c b/src/nautilus-tagged-entry-tag.c
new file mode 100644
index 000000000..1254bffa2
--- /dev/null
+++ b/src/nautilus-tagged-entry-tag.c
@@ -0,0 +1,499 @@
+/* GTK+ 4 implementation of GdTaggedEntry for Nautilus
+ * © 2018 Ernestas Kulik <ernestask gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "nautilus-tagged-entry-tag.h"
+
+struct _NautilusTaggedEntryTag
+{
+ GtkWidget parent_instance;
+
+ GtkWidget *label;
+ GtkWidget *image;
+
+ bool active;
+};
+
+G_DEFINE_TYPE (NautilusTaggedEntryTag, nautilus_tagged_entry_tag, GTK_TYPE_WIDGET)
+
+#define SPACING 6
+
+enum
+{
+ PROP_0,
+ PROP_LABEL,
+ PROP_SHOW_CLOSE_BUTTON,
+ N_PROPERTIES
+};
+
+enum
+{
+ CLICKED,
+ BUTTON_CLICKED,
+ LAST_SIGNAL
+};
+
+static GParamSpec *properties[N_PROPERTIES];
+static unsigned int signals[LAST_SIGNAL];
+
+static void
+on_multi_press_gesture_pressed (GtkGestureMultiPress *gesture,
+ int n_press,
+ double x,
+ double y,
+ gpointer user_data)
+{
+ gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+}
+
+static void
+on_multi_press_gesture_released (GtkGestureMultiPress *gesture,
+ int n_press,
+ double x,
+ double y,
+ gpointer user_data)
+{
+ g_signal_emit (user_data, signals[CLICKED], 0);
+}
+
+static void
+set_image_pressed (NautilusTaggedEntryTag *self,
+ bool pressed)
+{
+ self->active = pressed;
+
+ if (pressed)
+ {
+ gtk_widget_set_state_flags (self->image, GTK_STATE_FLAG_ACTIVE, false);
+ }
+ else
+ {
+ gtk_widget_unset_state_flags (self->image, GTK_STATE_FLAG_ACTIVE);
+ }
+}
+
+static void
+on_image_multi_press_gesture_pressed (GtkGestureMultiPress *gesture,
+ int n_press,
+ double x,
+ double y,
+ gpointer user_data)
+{
+ set_image_pressed (user_data, true);
+
+ gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+}
+
+static void
+on_image_multi_press_gesture_released (GtkGestureMultiPress *gesture,
+ int n_press,
+ double x,
+ double y,
+ gpointer user_data)
+{
+ set_image_pressed (user_data, false);
+
+ g_signal_emit (user_data, signals[BUTTON_CLICKED], 0);
+}
+
+static void
+on_image_multi_press_gesture_cancel (GtkGesture *gesture,
+ GdkEventSequence *sequence,
+ gpointer user_data)
+{
+ set_image_pressed (user_data, false);
+}
+
+static void
+on_image_multi_press_gesture_update (GtkGesture *gesture,
+ GdkEventSequence *sequence,
+ gpointer user_data)
+{
+ GtkWidget *widget;
+ double x;
+ double y;
+ bool contains;
+
+ widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
+
+ gtk_gesture_get_point (gesture, sequence, &x, &y);
+
+ contains = gtk_widget_contains (widget, x, y);
+ if (contains)
+ {
+ gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_PRELIGHT, false);
+ }
+ else
+ {
+ gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_PRELIGHT);
+ }
+
+ set_image_pressed (user_data, contains);
+}
+
+static void
+nautilus_tagged_entry_tag_init (NautilusTaggedEntryTag *self)
+{
+ GtkGesture *gesture;
+ GtkStyleContext *context;
+
+ self->label = gtk_label_new (NULL);
+ self->image = gtk_image_new_from_icon_name ("window-close-symbolic");
+ self->active = false;
+
+ gtk_widget_set_has_surface (GTK_WIDGET (self), false);
+
+ gtk_widget_hide (self->label);
+ gtk_widget_insert_after (self->label, GTK_WIDGET (self), NULL);
+
+ gtk_widget_insert_after (self->image, GTK_WIDGET (self), self->label);
+
+ gesture = gtk_gesture_multi_press_new ();
+ gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
+
+ g_signal_connect (gesture,
+ "pressed", G_CALLBACK (on_multi_press_gesture_pressed),
+ self);
+ g_signal_connect (gesture,
+ "released", G_CALLBACK (on_multi_press_gesture_released),
+ self);
+
+ gesture = gtk_gesture_multi_press_new ();
+ gtk_widget_add_controller (self->image, GTK_EVENT_CONTROLLER (gesture));
+
+ g_signal_connect (gesture,
+ "pressed", G_CALLBACK (on_image_multi_press_gesture_pressed),
+ self);
+ g_signal_connect (gesture,
+ "released", G_CALLBACK (on_image_multi_press_gesture_released),
+ self);
+ g_signal_connect (gesture,
+ "cancel", G_CALLBACK (on_image_multi_press_gesture_cancel),
+ self);
+ g_signal_connect (gesture,
+ "update", G_CALLBACK (on_image_multi_press_gesture_update),
+ self);
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (self));
+ gtk_style_context_add_class (context, "entry-tag");
+
+ context = gtk_widget_get_style_context (self->image);
+ gtk_style_context_add_class (context, "entry-tag");
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
+}
+
+static void
+set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ NautilusTaggedEntryTag *self;
+
+ self = NAUTILUS_TAGGED_ENTRY_TAG (object);
+
+ switch (property_id)
+ {
+ case PROP_LABEL:
+ {
+ const char *string;
+ bool empty;
+
+ string = g_value_get_string (value);
+ empty = (g_strcmp0 (string, "") == 0);
+
+ gtk_label_set_label (GTK_LABEL (self->label), string);
+ gtk_widget_set_visible (self->label, !empty);
+ }
+ break;
+
+ case PROP_SHOW_CLOSE_BUTTON:
+ {
+ gtk_widget_set_visible (self->image, g_value_get_boolean (value));
+ }
+ break;
+
+ default:
+ {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+ }
+}
+
+static void
+get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ NautilusTaggedEntryTag *self;
+
+ self = NAUTILUS_TAGGED_ENTRY_TAG (object);
+
+ switch (property_id)
+ {
+ case PROP_LABEL:
+ {
+ g_value_set_string (value, gtk_label_get_label (GTK_LABEL (self->label)));
+ };
+ break;
+
+ case PROP_SHOW_CLOSE_BUTTON:
+ {
+ g_value_set_boolean (value, gtk_widget_is_visible (self->image));
+ }
+ break;
+
+ default:
+ {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+ }
+}
+
+static void
+finalize (GObject *object)
+{
+ NautilusTaggedEntryTag *self;
+
+ self = NAUTILUS_TAGGED_ENTRY_TAG (object);
+
+ gtk_widget_unparent (self->label);
+ gtk_widget_unparent (self->image);
+
+ G_OBJECT_CLASS (nautilus_tagged_entry_tag_parent_class)->finalize (object);
+}
+
+static void
+size_allocate (GtkWidget *widget,
+ int width,
+ int height,
+ int baseline)
+{
+ NautilusTaggedEntryTag *self;
+ GtkAllocation label_allocation = { 0 };
+ GtkAllocation image_allocation = { 0 };
+
+ self = NAUTILUS_TAGGED_ENTRY_TAG (widget);
+
+ gtk_widget_measure (self->label,
+ GTK_ORIENTATION_HORIZONTAL,
+ -1,
+ &label_allocation.width, NULL,
+ NULL, NULL);
+ gtk_widget_measure (self->label,
+ GTK_ORIENTATION_VERTICAL,
+ label_allocation.width,
+ &label_allocation.height, NULL,
+ NULL, NULL);
+
+ label_allocation.y = (height - label_allocation.height) / 2;
+
+ gtk_widget_size_allocate (self->label, &label_allocation, -1);
+
+ image_allocation.x = label_allocation.width + SPACING;
+
+ gtk_widget_measure (self->image,
+ GTK_ORIENTATION_HORIZONTAL,
+ -1,
+ &image_allocation.width, NULL,
+ NULL, NULL);
+ gtk_widget_measure (self->image,
+ GTK_ORIENTATION_VERTICAL,
+ image_allocation.width,
+ &image_allocation.height, NULL,
+ NULL, NULL);
+
+ image_allocation.y = (height - image_allocation.height) / 2;
+
+ gtk_widget_size_allocate (self->image, &image_allocation, -1);
+}
+
+static void
+measure (GtkWidget *widget,
+ GtkOrientation orientation,
+ int for_size,
+ int *minimum,
+ int *natural,
+ int *minimum_baseline,
+ int *natural_baseline)
+{
+ NautilusTaggedEntryTag *self;
+ int label_minimum;
+ int label_natural;
+ int image_minimum;
+ int image_natural;
+
+ self = NAUTILUS_TAGGED_ENTRY_TAG (widget);
+
+ gtk_widget_measure (self->label, orientation, for_size,
+ &label_minimum, &label_natural,
+ NULL, NULL);
+ gtk_widget_measure (self->image, orientation, for_size,
+ &image_minimum, &image_natural,
+ NULL, NULL);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ if (minimum != NULL)
+ {
+ *minimum = label_minimum + image_minimum;
+
+ if (gtk_widget_is_visible (self->image))
+ {
+ *minimum += SPACING;
+ }
+ }
+ if (natural != NULL)
+ {
+ *natural = label_natural + image_natural;
+
+ if (gtk_widget_is_visible (self->image))
+ {
+ *natural += SPACING;
+ }
+ }
+ }
+ else
+ {
+ if (minimum != NULL)
+ {
+ *minimum = MAX (label_minimum, image_minimum);
+ }
+ if (natural != NULL)
+ {
+ *natural = MAX (label_natural, image_natural);
+ }
+ }
+}
+
+static void
+snapshot (GtkWidget *widget,
+ GtkSnapshot *snapshot)
+{
+ NautilusTaggedEntryTag *self;
+ GtkWidgetClass *parent_widget_class;
+
+ self = NAUTILUS_TAGGED_ENTRY_TAG (widget);
+ parent_widget_class = GTK_WIDGET_CLASS (nautilus_tagged_entry_tag_parent_class);
+
+ parent_widget_class->snapshot (widget, snapshot);
+
+ gtk_widget_snapshot_child (widget, self->label, snapshot);
+ gtk_widget_snapshot_child (widget, self->image, snapshot);
+}
+
+static void
+nautilus_tagged_entry_tag_class_init (NautilusTaggedEntryTagClass *klass)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkCssProvider *provider;
+ GdkDisplay *display;
+
+ object_class = G_OBJECT_CLASS (klass);
+ widget_class = GTK_WIDGET_CLASS (klass);
+ provider = gtk_css_provider_new ();
+ display = gdk_display_get_default ();
+
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+ object_class->finalize = finalize;
+
+ widget_class->size_allocate = size_allocate;
+ widget_class->measure = measure;
+ widget_class->snapshot = snapshot;
+
+ gtk_css_provider_load_from_data (provider,
+ ".entry-tag {"
+ " border-radius: 4px;"
+ " padding: 0 6px 0 6px;"
+ " margin-left: 0;"
+ " margin-right: 0;"
+ "}"
+ ".entry-tag label {"
+ " color: inherit;"
+ "}"
+ /* Reserving space for the border
+ * to prevent jumping around.
+ */
+ ".entry-tag.button:not(:hover),"
+ ".entry-tag.button:backdrop {"
+ " border: 1px solid transparent;"
+ "}"
+ ".entry-tag.button {"
+ " margin: 0;"
+ " padding: 0;"
+ "}"
+ ,
+ -1);
+
+ gtk_style_context_add_provider_for_display (display,
+ GTK_STYLE_PROVIDER (provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+
+ properties[PROP_LABEL] =
+ g_param_spec_string ("label", "Label", "Label",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ properties[PROP_SHOW_CLOSE_BUTTON] =
+ g_param_spec_boolean ("show-close-button", "Show Close Button", "Toggles close button visibility",
+ true,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ signals[CLICKED] = g_signal_new ("clicked",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ signals[BUTTON_CLICKED] = g_signal_new ("button-clicked",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+void
+nautilus_tagged_entry_tag_set_label (NautilusTaggedEntryTag *self,
+ const char *label)
+{
+ g_return_if_fail (NAUTILUS_IS_TAGGED_ENTRY_TAG (self));
+
+ g_object_set (self, "label", label, NULL);
+}
+
+void
+nautilus_tagged_entry_tag_set_show_close_button (NautilusTaggedEntryTag *self,
+ bool show_close_button)
+{
+ g_return_if_fail (NAUTILUS_IS_TAGGED_ENTRY_TAG (self));
+
+ gtk_widget_set_visible (self->image, show_close_button);
+}
+
+GtkWidget *
+nautilus_tagged_entry_tag_new (const char *label)
+{
+ return g_object_new (NAUTILUS_TYPE_TAGGED_ENTRY_TAG, "label", label, NULL);
+}
diff --git a/src/nautilus-tagged-entry-tag.h b/src/nautilus-tagged-entry-tag.h
new file mode 100644
index 000000000..8641e7d19
--- /dev/null
+++ b/src/nautilus-tagged-entry-tag.h
@@ -0,0 +1,38 @@
+/* GTK+ 4 implementation of GdTaggedEntry for Nautilus
+ * © 2018 Ernestas Kulik <ernestask gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+#include <stdbool.h>
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_TAGGED_ENTRY_TAG (nautilus_tagged_entry_tag_get_type ())
+
+G_DECLARE_FINAL_TYPE (NautilusTaggedEntryTag, nautilus_tagged_entry_tag,
+ NAUTILUS, TAGGED_ENTRY_TAG,
+ GtkWidget)
+
+void nautilus_tagged_entry_tag_set_label (NautilusTaggedEntryTag *tag,
+ const char *label);
+void nautilus_tagged_entry_tag_set_show_close_button (NautilusTaggedEntryTag *tag,
+ bool show_close_button);
+
+GtkWidget *nautilus_tagged_entry_tag_new (const char *label);
+
+G_END_DECLS
diff --git a/src/nautilus-tagged-entry.c b/src/nautilus-tagged-entry.c
new file mode 100644
index 000000000..5c029ff91
--- /dev/null
+++ b/src/nautilus-tagged-entry.c
@@ -0,0 +1,311 @@
+/* GTK+ 4 implementation of GdTaggedEntry for Nautilus
+ * © 2018 Ernestas Kulik <ernestask gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "nautilus-tagged-entry.h"
+
+#include "nautilus-tagged-entry-tag.h"
+
+struct _NautilusTaggedEntry
+{
+ GtkSearchEntry parent_instance;
+
+ GtkWidget *box;
+};
+
+G_DEFINE_TYPE (NautilusTaggedEntry, nautilus_tagged_entry, GTK_TYPE_SEARCH_ENTRY)
+
+#define SPACING 3
+
+enum
+{
+ TAG_CLICKED,
+ TAG_BUTTON_CLICKED,
+ LAST_SIGNAL
+};
+
+static unsigned int signals[LAST_SIGNAL];
+
+static void
+nautilus_tagged_entry_init (NautilusTaggedEntry *self)
+{
+ GtkStyleContext *context;
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (self));
+
+ gtk_style_context_add_class (context, "tagged-entry");
+
+ self->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, SPACING);
+
+ gtk_widget_set_cursor_from_name (self->box, "default");
+ gtk_widget_set_parent (self->box, GTK_WIDGET (self));
+ gtk_widget_set_vexpand (self->box, true);
+}
+
+static void
+finalize (GObject *object)
+{
+ NautilusTaggedEntry *self;
+
+ self = NAUTILUS_TAGGED_ENTRY (object);
+
+ gtk_widget_unparent (self->box);
+
+ G_OBJECT_CLASS (nautilus_tagged_entry_parent_class)->finalize (object);
+}
+
+static void
+size_allocate (GtkWidget *widget,
+ int width,
+ int height,
+ int baseline)
+{
+ NautilusTaggedEntry *self;
+ GtkWidgetClass *parent_widget_class;
+ GtkAllocation box_allocation = { 0 };
+ GtkAllocation entry_allocation = { 0 };
+ g_autoptr (GList) children = NULL;
+
+ self = NAUTILUS_TAGGED_ENTRY (widget);
+ parent_widget_class = GTK_WIDGET_CLASS (nautilus_tagged_entry_parent_class);
+ box_allocation = (GtkAllocation) { 0, 0, width, height };
+ entry_allocation = (GtkAllocation) { 0, 0, width, height };
+ children = gtk_container_get_children (GTK_CONTAINER (self->box));
+
+ gtk_widget_measure (self->box,
+ GTK_ORIENTATION_HORIZONTAL,
+ -1,
+ &box_allocation.width, NULL,
+ NULL, NULL);
+
+ box_allocation.x = width - box_allocation.width;
+
+ if (children != NULL)
+ {
+ GtkStyleContext *context;
+ GtkBorder padding = { 0 };
+
+ context = gtk_widget_get_style_context (widget);
+
+ gtk_style_context_get_padding (context, &padding);
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+ {
+ box_allocation.width += padding.right;
+ }
+ else
+ {
+ box_allocation.width += padding.left;
+ }
+ }
+
+ entry_allocation.width -= box_allocation.width;
+
+ parent_widget_class->size_allocate (widget,
+ entry_allocation.width,
+ entry_allocation.height,
+ -1);
+
+ gtk_widget_size_allocate (self->box, &box_allocation, -1);
+}
+
+static void
+measure (GtkWidget *widget,
+ GtkOrientation orientation,
+ int for_size,
+ int *minimum,
+ int *natural,
+ int *minimum_baseline,
+ int *natural_baseline)
+{
+ NautilusTaggedEntry *self;
+ GtkWidgetClass *parent_widget_class;
+ int entry_minimum;
+ int entry_natural;
+ int box_minimum;
+ int box_natural;
+
+ self = NAUTILUS_TAGGED_ENTRY (widget);
+ parent_widget_class = GTK_WIDGET_CLASS (nautilus_tagged_entry_parent_class);
+
+ parent_widget_class->measure (widget, orientation, for_size,
+ &entry_minimum, &entry_natural,
+ NULL, NULL);
+
+ gtk_widget_measure (self->box, orientation, for_size,
+ &box_minimum, &box_natural,
+ NULL, NULL);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ if (minimum != NULL)
+ {
+ *minimum = entry_minimum + box_minimum;
+ }
+ if (natural != NULL)
+ {
+ *natural = entry_natural + box_minimum;
+ }
+ }
+ else
+ {
+ if (minimum != NULL)
+ {
+ *minimum = entry_minimum;
+ }
+ if (natural != NULL)
+ {
+ *natural = entry_natural;
+ }
+ }
+}
+
+static void
+snapshot (GtkWidget *widget,
+ GtkSnapshot *snapshot)
+{
+ NautilusTaggedEntry *self;
+
+ self = NAUTILUS_TAGGED_ENTRY (widget);
+
+ GTK_WIDGET_CLASS (nautilus_tagged_entry_parent_class)->snapshot (widget, snapshot);
+
+ gtk_widget_snapshot_child (widget, self->box, snapshot);
+}
+
+static void
+nautilus_tagged_entry_class_init (NautilusTaggedEntryClass *klass)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkCssProvider *provider;
+ GdkDisplay *display;
+
+ object_class = G_OBJECT_CLASS (klass);
+ widget_class = GTK_WIDGET_CLASS (klass);
+ provider = gtk_css_provider_new ();
+ display = gdk_display_get_default ();
+
+ object_class->finalize = finalize;
+
+ widget_class->size_allocate = size_allocate;
+ widget_class->measure = measure;
+ widget_class->snapshot = snapshot;
+
+ gtk_widget_class_set_css_name (widget_class, "entry");
+
+ gtk_css_provider_load_from_data (provider,
+ ".tagged-entry entry {"
+ " background: transparent;"
+ " border: none;"
+ " box-shadow: none;"
+ "}"
+ ,
+ -1);
+
+ gtk_style_context_add_provider_for_display (display,
+ GTK_STYLE_PROVIDER (provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+
+ signals[TAG_CLICKED] = g_signal_new ("tag-clicked",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE,
+ 1,
+ NAUTILUS_TYPE_TAGGED_ENTRY);
+ signals[TAG_BUTTON_CLICKED] = g_signal_new ("tag-button-clicked",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE,
+ 1,
+ NAUTILUS_TYPE_TAGGED_ENTRY);
+}
+
+static void
+on_tag_clicked (NautilusTaggedEntryTag *tag,
+ gpointer user_data)
+{
+ g_signal_emit (user_data, signals[TAG_CLICKED], 0, tag);
+}
+
+static void
+on_tag_button_clicked (NautilusTaggedEntryTag *tag,
+ gpointer user_data)
+{
+ g_signal_emit (user_data, signals[TAG_BUTTON_CLICKED], 0, tag);
+}
+
+void
+nautilus_tagged_entry_add_tag (NautilusTaggedEntry *self,
+ NautilusTaggedEntryTag *tag)
+{
+ unsigned long handler_id;
+
+ g_return_if_fail (NAUTILUS_IS_TAGGED_ENTRY (self));
+ g_return_if_fail (NAUTILUS_IS_TAGGED_ENTRY_TAG (tag));
+
+ gtk_container_add (GTK_CONTAINER (self->box), GTK_WIDGET (tag));
+
+ handler_id = g_signal_connect (tag,
+ "clicked", G_CALLBACK (on_tag_clicked),
+ self);
+ g_object_set_data (G_OBJECT (tag),
+ "clicked-handler-id", GUINT_TO_POINTER (handler_id));
+
+ handler_id = g_signal_connect (tag,
+ "button-clicked", G_CALLBACK (on_tag_button_clicked),
+ self);
+ g_object_set_data (G_OBJECT (tag),
+ "button-clicked-handler-id", GUINT_TO_POINTER (handler_id));
+}
+
+void
+nautilus_tagged_entry_remove_tag (NautilusTaggedEntry *self,
+ NautilusTaggedEntryTag *tag)
+{
+ GtkWidget *parent;
+ gpointer data;
+ unsigned long handler_id;
+
+ g_return_if_fail (NAUTILUS_IS_TAGGED_ENTRY (self));
+ g_return_if_fail (NAUTILUS_IS_TAGGED_ENTRY_TAG (tag));
+
+ parent = gtk_widget_get_parent (GTK_WIDGET (tag));
+
+ g_return_if_fail (parent != GTK_WIDGET (self));
+
+ data = g_object_get_data (G_OBJECT (tag), "clicked-handler-id");
+ handler_id = GPOINTER_TO_UINT (data);
+ g_signal_handler_disconnect (tag, handler_id);
+
+ data = g_object_get_data (G_OBJECT (tag), "button-clicked-handler-id");
+ handler_id = GPOINTER_TO_UINT (data);
+ g_signal_handler_disconnect (tag, handler_id);
+
+ gtk_container_remove (GTK_CONTAINER (self->box), GTK_WIDGET (tag));
+}
+
+GtkWidget *
+nautilus_tagged_entry_new (void)
+{
+ return g_object_new (NAUTILUS_TYPE_TAGGED_ENTRY, NULL);
+}
diff --git a/src/nautilus-tagged-entry.h b/src/nautilus-tagged-entry.h
new file mode 100644
index 000000000..61721ec4f
--- /dev/null
+++ b/src/nautilus-tagged-entry.h
@@ -0,0 +1,39 @@
+/* GTK+ 4 implementation of GdTaggedEntry for Nautilus
+ * © 2018 Ernestas Kulik <ernestask gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _NautilusTaggedEntryTag NautilusTaggedEntryTag;
+
+#define NAUTILUS_TYPE_TAGGED_ENTRY (nautilus_tagged_entry_get_type ())
+
+G_DECLARE_FINAL_TYPE (NautilusTaggedEntry, nautilus_tagged_entry,
+ NAUTILUS, TAGGED_ENTRY,
+ GtkSearchEntry)
+
+void nautilus_tagged_entry_add_tag (NautilusTaggedEntry *entry,
+ NautilusTaggedEntryTag *tag);
+void nautilus_tagged_entry_remove_tag (NautilusTaggedEntry *entry,
+ NautilusTaggedEntryTag *tag);
+
+GtkWidget *nautilus_tagged_entry_new (void);
+
+G_END_DECLS
diff --git a/src/resources/css/Adwaita.css b/src/resources/css/Adwaita.css
index 9232ba803..c6a74de45 100644
--- a/src/resources/css/Adwaita.css
+++ b/src/resources/css/Adwaita.css
@@ -71,11 +71,6 @@
border-radius: 0px 0px 0px 0px;
}
-/* Make the tags fit into the box */
-entry.search > * {
- margin: 5px;
-}
-
/* Sidebar */
.sidebar-row:selected {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]