[libdazzle] suggesetions: add DzlSuggestionButton



commit 67d64703bb442c7a3a89f55a314d3b866e189bb0
Author: Christian Hergert <chergert redhat com>
Date:   Mon Apr 22 12:34:11 2019 -0700

    suggesetions: add DzlSuggestionButton
    
    This is a button-looking widget that transitions between a button and
    a gtkentry and tries to do so in a somewhat attractive fashion.

 data/themes/shared/shared-suggestions.css |   8 +
 src/dazzle.h                              |   1 +
 src/suggestions/dzl-suggestion-button.c   | 293 ++++++++++++++++++++++++++++++
 src/suggestions/dzl-suggestion-button.h   |  50 +++++
 src/suggestions/meson.build               |   2 +
 5 files changed, 354 insertions(+)
---
diff --git a/data/themes/shared/shared-suggestions.css b/data/themes/shared/shared-suggestions.css
index b4c6889..edc47e8 100644
--- a/data/themes/shared/shared-suggestions.css
+++ b/data/themes/shared/shared-suggestions.css
@@ -54,3 +54,11 @@ dzlsuggestionpopover > revealer > box > elastic > scrolledwindow > viewport > li
 dzlsuggestionpopover > revealer > box > elastic > scrolledwindow > viewport > list > row > box > 
image:first-child {
   min-width: 16px;
 }
+
+/* DzlSuggestionButton */
+button.suggestionbutton entry.suggestion image.left {
+  margin-left: 1px;
+}
+button.suggestionbutton entry.suggestion image.right {
+  margin-right: 1px;
+}
diff --git a/src/dazzle.h b/src/dazzle.h
index d70ff8b..60ec635 100644
--- a/src/dazzle.h
+++ b/src/dazzle.h
@@ -118,6 +118,7 @@ G_BEGIN_DECLS
 #include "shortcuts/dzl-shortcuts-window.h"
 #include "statemachine/dzl-state-machine-buildable.h"
 #include "statemachine/dzl-state-machine.h"
+#include "suggestions/dzl-suggestion-button.h"
 #include "suggestions/dzl-suggestion-entry-buffer.h"
 #include "suggestions/dzl-suggestion-entry.h"
 #include "suggestions/dzl-suggestion-popover.h"
diff --git a/src/suggestions/dzl-suggestion-button.c b/src/suggestions/dzl-suggestion-button.c
new file mode 100644
index 0000000..3ccc2d0
--- /dev/null
+++ b/src/suggestions/dzl-suggestion-button.c
@@ -0,0 +1,293 @@
+/* dzl-suggestion-button.c
+ *
+ * Copyright 2019 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
+ */
+
+#define G_LOG_DOMAIN "dzl-suggestion-button"
+
+#include "config.h"
+
+#include "suggestions/dzl-suggestion-button.h"
+#include "suggestions/dzl-suggestion-entry.h"
+#include "util/dzl-gtk.h"
+
+typedef struct
+{
+  DzlSuggestionEntry *entry;
+  GtkButton          *button;
+} DzlSuggestionButtonPrivate;
+
+enum {
+  PROP_0,
+  PROP_BUTTON,
+  PROP_ENTRY,
+  N_PROPS
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (DzlSuggestionButton, dzl_suggestion_button, GTK_TYPE_STACK)
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+entry_icon_press_cb (DzlSuggestionButton  *self,
+                     GtkEntryIconPosition  position,
+                     GdkEvent             *event,
+                     DzlSuggestionEntry   *entry)
+{
+  DzlSuggestionButtonPrivate *priv = dzl_suggestion_button_get_instance_private (self);
+
+  g_assert (DZL_IS_SUGGESTION_BUTTON (self));
+  g_assert (DZL_IS_SUGGESTION_ENTRY (entry));
+
+  if (position == GTK_ENTRY_ICON_PRIMARY)
+    gtk_stack_set_visible_child (GTK_STACK (self), GTK_WIDGET (priv->button));
+}
+
+static gboolean
+entry_focus_in_event_cb (DzlSuggestionButton *self,
+                         GdkEventFocus       *focus,
+                         DzlSuggestionEntry  *entry)
+{
+  DzlSuggestionButtonPrivate *priv = dzl_suggestion_button_get_instance_private (self);
+
+  g_assert (DZL_IS_SUGGESTION_BUTTON (self));
+  g_assert (DZL_IS_SUGGESTION_ENTRY (entry));
+
+  gtk_entry_set_width_chars (GTK_ENTRY (priv->entry), 5);
+  gtk_entry_set_max_width_chars (GTK_ENTRY (priv->entry), 26);
+
+  return GDK_EVENT_PROPAGATE;
+}
+
+static gboolean
+entry_focus_out_event_cb (DzlSuggestionButton *self,
+                          GdkEventFocus       *focus,
+                          DzlSuggestionEntry  *entry)
+{
+  DzlSuggestionButtonPrivate *priv = dzl_suggestion_button_get_instance_private (self);
+
+  g_assert (DZL_IS_SUGGESTION_BUTTON (self));
+  g_assert (DZL_IS_SUGGESTION_ENTRY (entry));
+
+  gtk_entry_set_width_chars (GTK_ENTRY (priv->entry), 0);
+  gtk_entry_set_max_width_chars (GTK_ENTRY (priv->entry), 0);
+  gtk_stack_set_visible_child (GTK_STACK (self), GTK_WIDGET (priv->button));
+
+  return GDK_EVENT_PROPAGATE;
+}
+
+static void
+button_clicked_cb (DzlSuggestionButton *self,
+                   GtkButton           *button)
+{
+  DzlSuggestionButtonPrivate *priv = dzl_suggestion_button_get_instance_private (self);
+
+  g_assert (DZL_IS_SUGGESTION_BUTTON (self));
+  g_assert (GTK_IS_BUTTON (button));
+
+  gtk_entry_set_width_chars (GTK_ENTRY (priv->entry), 5);
+  gtk_entry_set_max_width_chars (GTK_ENTRY (priv->entry), 26);
+
+  gtk_stack_set_visible_child (GTK_STACK (self), GTK_WIDGET (priv->entry));
+  gtk_widget_grab_focus (GTK_WIDGET (priv->entry));
+}
+
+static void
+dzl_suggestion_button_get_preferred_width (GtkWidget *widget,
+                                           gint      *min_width,
+                                           gint      *nat_width)
+{
+  DzlSuggestionButton *self = (DzlSuggestionButton *)widget;
+  DzlSuggestionButtonPrivate *priv = dzl_suggestion_button_get_instance_private (self);
+  gint entry_min_width = -1;
+  gint entry_nat_width = -1;
+
+  g_assert (DZL_IS_SUGGESTION_BUTTON (self));
+  g_assert (min_width != NULL);
+  g_assert (nat_width != NULL);
+
+  GTK_WIDGET_CLASS (dzl_suggestion_button_parent_class)->get_preferred_width (widget, min_width, nat_width);
+
+  if (gtk_stack_get_transition_running (GTK_STACK (self)) ||
+      gtk_stack_get_visible_child (GTK_STACK (self)) == GTK_WIDGET (priv->entry))
+    {
+      gtk_widget_get_preferred_width (GTK_WIDGET (priv->entry), &entry_min_width, &entry_nat_width);
+      *min_width = MAX (*min_width, entry_min_width);
+      *nat_width = MAX (*nat_width, entry_min_width);
+    }
+}
+
+static void
+dzl_suggestion_button_grab_focus (GtkWidget *widget)
+{
+  DzlSuggestionButton *self = (DzlSuggestionButton *)widget;
+  DzlSuggestionButtonPrivate *priv = dzl_suggestion_button_get_instance_private (self);
+
+  g_assert (DZL_IS_SUGGESTION_BUTTON (self));
+
+  gtk_widget_grab_focus (GTK_WIDGET (priv->entry));
+}
+
+static void
+dzl_suggestion_button_get_property (GObject    *object,
+                                    guint       prop_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  DzlSuggestionButton *self = DZL_SUGGESTION_BUTTON (object);
+
+  switch (prop_id)
+    {
+    case PROP_BUTTON:
+      g_value_set_object (value, dzl_suggestion_button_get_button (self));
+      break;
+
+    case PROP_ENTRY:
+      g_value_set_object (value, dzl_suggestion_button_get_entry (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+dzl_suggestion_button_class_init (DzlSuggestionButtonClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->get_property = dzl_suggestion_button_get_property;
+
+  widget_class->grab_focus = dzl_suggestion_button_grab_focus;
+  widget_class->get_preferred_width = dzl_suggestion_button_get_preferred_width;
+
+  properties [PROP_BUTTON] =
+    g_param_spec_object ("button",
+                         "Button",
+                         "The button to be displayed",
+                         GTK_TYPE_BUTTON,
+                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_ENTRY] =
+    g_param_spec_object ("entry",
+                         "Entry",
+                         "The entry for user input",
+                         DZL_TYPE_SUGGESTION_ENTRY,
+                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+dzl_suggestion_button_init (DzlSuggestionButton *self)
+{
+  DzlSuggestionButtonPrivate *priv = dzl_suggestion_button_get_instance_private (self);
+
+  gtk_stack_set_hhomogeneous (GTK_STACK (self), FALSE);
+  gtk_stack_set_interpolate_size (GTK_STACK (self), TRUE);
+  gtk_stack_set_transition_type (GTK_STACK (self), GTK_STACK_TRANSITION_TYPE_CROSSFADE);
+  gtk_stack_set_transition_duration (GTK_STACK (self), 200);
+
+  dzl_gtk_widget_add_style_class (GTK_WIDGET (self), "suggestionbutton");
+
+  priv->button = g_object_new (GTK_TYPE_BUTTON,
+                               "child", g_object_new (GTK_TYPE_IMAGE,
+                                                      "icon-name", "edit-find-symbolic",
+                                                      "halign", GTK_ALIGN_START,
+                                                      "visible", TRUE,
+                                                      NULL),
+                               "visible", TRUE,
+                               NULL);
+  g_signal_connect_object (priv->button,
+                           "clicked",
+                           G_CALLBACK (button_clicked_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+  gtk_container_add_with_properties (GTK_CONTAINER (self), GTK_WIDGET (priv->button),
+                                     "name", "button",
+                                     NULL);
+
+  priv->entry = g_object_new (DZL_TYPE_SUGGESTION_ENTRY,
+                              "max-width-chars", 0,
+                              "placeholder-text", NULL,
+                              "primary-icon-name", "edit-find-symbolic",
+                              "visible", TRUE,
+                              "width-chars", 0,
+                              NULL);
+  g_signal_connect_object (priv->entry,
+                           "icon-press",
+                           G_CALLBACK (entry_icon_press_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+  g_signal_connect_object (priv->entry,
+                           "focus-in-event",
+                           G_CALLBACK (entry_focus_in_event_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+  g_signal_connect_object (priv->entry,
+                           "focus-out-event",
+                           G_CALLBACK (entry_focus_out_event_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+  gtk_container_add_with_properties (GTK_CONTAINER (self), GTK_WIDGET (priv->entry),
+                                     "name", "entry",
+                                     NULL);
+}
+
+GtkWidget *
+dzl_suggestion_button_new (void)
+{
+  return g_object_new (DZL_TYPE_SUGGESTION_BUTTON, NULL);
+}
+
+/**
+ * dzl_suggestion_button_get_entry:
+ * @self: a #DzlSuggestionButton
+ *
+ * Returns: (transfer none): a #DzlSuggestionEntry
+ *
+ * Since: 3.34
+ */
+DzlSuggestionEntry *
+dzl_suggestion_button_get_entry (DzlSuggestionButton *self)
+{
+  DzlSuggestionButtonPrivate *priv = dzl_suggestion_button_get_instance_private (self);
+
+  g_return_val_if_fail (DZL_IS_SUGGESTION_BUTTON (self), NULL);
+
+  return priv->entry;
+}
+
+/**
+ * dzl_suggestion_button_get_button:
+ * @self: a #DzlSuggestionButton
+ *
+ * Returns: (transfer none): a #GtkWidget
+ *
+ * Since: 3.34
+ */
+GtkButton *
+dzl_suggestion_button_get_button (DzlSuggestionButton *self)
+{
+  DzlSuggestionButtonPrivate *priv = dzl_suggestion_button_get_instance_private (self);
+
+  g_return_val_if_fail (DZL_IS_SUGGESTION_BUTTON (self), NULL);
+
+  return priv->button;
+}
diff --git a/src/suggestions/dzl-suggestion-button.h b/src/suggestions/dzl-suggestion-button.h
new file mode 100644
index 0000000..8b5fe43
--- /dev/null
+++ b/src/suggestions/dzl-suggestion-button.h
@@ -0,0 +1,50 @@
+/* dzl-suggestion-button.h
+ *
+ * Copyright 2019 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>
+
+#include "dzl-suggestion-entry.h"
+#include "dzl-version-macros.h"
+
+G_BEGIN_DECLS
+
+#define DZL_TYPE_SUGGESTION_BUTTON (dzl_suggestion_button_get_type())
+
+DZL_AVAILABLE_IN_3_34
+G_DECLARE_DERIVABLE_TYPE (DzlSuggestionButton, dzl_suggestion_button, DZL, SUGGESTION_BUTTON, GtkStack)
+
+struct _DzlSuggestionButtonClass
+{
+  GtkStackClass parent_class;
+
+  /*< private >*/
+  gpointer _reserved[8];
+};
+
+DZL_AVAILABLE_IN_3_34
+GtkWidget          *dzl_suggestion_button_new        (void);
+DZL_AVAILABLE_IN_3_34
+DzlSuggestionEntry *dzl_suggestion_button_get_entry  (DzlSuggestionButton *self);
+DZL_AVAILABLE_IN_3_34
+GtkButton          *dzl_suggestion_button_get_button (DzlSuggestionButton *self);
+
+G_END_DECLS
diff --git a/src/suggestions/meson.build b/src/suggestions/meson.build
index db91b61..2db355d 100644
--- a/src/suggestions/meson.build
+++ b/src/suggestions/meson.build
@@ -1,4 +1,5 @@
 suggestions_headers = [
+  'dzl-suggestion-button.h',
   'dzl-suggestion-entry-buffer.h',
   'dzl-suggestion-entry.h',
   'dzl-suggestion-popover.h',
@@ -7,6 +8,7 @@ suggestions_headers = [
 ]
 
 suggestions_sources = [
+  'dzl-suggestion-button.c',
   'dzl-suggestion-entry-buffer.c',
   'dzl-suggestion-entry.c',
   'dzl-suggestion-popover.c',


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