[gtk/gtk-demo-fixes: 8/9] cell renderer spin: Bring this back



commit cc3ecac6d8a68c8caa3e62ebe68dfe48afb9489f
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Dec 24 03:33:02 2019 -0500

    cell renderer spin: Bring this back
    
    GtkSpinButton lost its cell editable implementation
    when it stopped being a GtkEntry subclass. Add it
    back, and make it work.

 gtk/gtkcellrendererspin.c | 67 ++++++++++++++++++++++--------------
 gtk/gtkspinbutton.c       | 87 +++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 126 insertions(+), 28 deletions(-)
---
diff --git a/gtk/gtkcellrendererspin.c b/gtk/gtkcellrendererspin.c
index 97c48a354c..43ee161458 100644
--- a/gtk/gtkcellrendererspin.c
+++ b/gtk/gtkcellrendererspin.c
@@ -66,6 +66,7 @@ struct _GtkCellRendererSpinClass
 
 struct _GtkCellRendererSpinPrivate
 {
+  GtkWidget *spin;
   GtkAdjustment *adjustment;
   gdouble climb_rate;
   guint   digits;
@@ -175,8 +176,8 @@ gtk_cell_renderer_spin_finalize (GObject *object)
 {
   GtkCellRendererSpinPrivate *priv = gtk_cell_renderer_spin_get_instance_private (GTK_CELL_RENDERER_SPIN 
(object));
 
-  if (priv && priv->adjustment)
-    g_object_unref (priv->adjustment);
+  g_clear_object (&priv->adjustment);
+  g_clear_object (&priv->spin);
 
   G_OBJECT_CLASS (gtk_cell_renderer_spin_parent_class)->finalize (object);
 }
@@ -258,9 +259,7 @@ gtk_cell_renderer_spin_focus_changed (GtkWidget  *widget,
   if (gtk_widget_has_focus (widget))
     return;
 
-  g_object_get (widget,
-                "editing-canceled", &canceled,
-                NULL);
+  g_object_get (widget, "editing-canceled", &canceled, NULL);
 
   g_signal_handlers_disconnect_by_func (widget,
                                        gtk_cell_renderer_spin_focus_changed,
@@ -268,13 +267,12 @@ gtk_cell_renderer_spin_focus_changed (GtkWidget  *widget,
 
   gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (data), canceled);
 
-  if (!canceled)
-    {
-      path = g_object_get_data (G_OBJECT (widget), GTK_CELL_RENDERER_SPIN_PATH);
+  if (canceled)
+    return;
 
-      new_text = gtk_editable_get_text (GTK_EDITABLE (widget));
-      g_signal_emit_by_name (data, "edited", path, new_text);
-    }
+  path = g_object_get_data (G_OBJECT (widget), GTK_CELL_RENDERER_SPIN_PATH);
+  new_text = gtk_editable_get_text (GTK_EDITABLE (widget));
+  g_signal_emit_by_name (data, "edited", path, new_text);
 }
 
 static gboolean
@@ -301,6 +299,28 @@ gtk_cell_renderer_spin_key_pressed (GtkEventControllerKey *controller,
   return FALSE;
 }
 
+static void
+gtk_cell_renderer_spin_editing_done (GtkSpinButton       *spin,
+                                     GtkCellRendererSpin *cell)
+{
+  GtkCellRendererSpinPrivate *priv = gtk_cell_renderer_spin_get_instance_private (GTK_CELL_RENDERER_SPIN 
(cell));
+  gboolean canceled;
+  const char *path;
+  const char *new_text;
+
+  g_clear_object (&priv->spin);
+
+  g_object_get (spin, "editing-canceled", &canceled, NULL);
+  gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (cell), canceled);
+
+  if (canceled)
+    return;
+
+  path = g_object_get_data (G_OBJECT (spin), GTK_CELL_RENDERER_SPIN_PATH);
+  new_text = gtk_editable_get_text (GTK_EDITABLE (spin));
+  g_signal_emit_by_name (cell, "edited", path, new_text);
+}
+
 static GtkCellEditable *
 gtk_cell_renderer_spin_start_editing (GtkCellRenderer      *cell,
                                      GdkEvent             *event,
@@ -313,7 +333,6 @@ gtk_cell_renderer_spin_start_editing (GtkCellRenderer      *cell,
   GtkCellRendererSpinPrivate *priv = gtk_cell_renderer_spin_get_instance_private (GTK_CELL_RENDERER_SPIN 
(cell));
   GtkCellRendererText *cell_text = GTK_CELL_RENDERER_TEXT (cell);
   GtkEventController *key_controller;
-  GtkWidget *spin;
   gboolean editable;
   gchar *text;
 
@@ -324,33 +343,31 @@ gtk_cell_renderer_spin_start_editing (GtkCellRenderer      *cell,
   if (!priv->adjustment)
     return NULL;
 
-  spin = gtk_spin_button_new (priv->adjustment,
-                             priv->climb_rate, priv->digits);
+  priv->spin = gtk_spin_button_new (priv->adjustment, priv->climb_rate, priv->digits);
+  g_object_ref_sink (priv->spin);
 
   g_object_get (cell_text, "text", &text, NULL);
   if (text)
     {
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin),
-                                 g_strtod (text, NULL));
+      gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->spin), g_strtod (text, NULL));
       g_free (text);
     }
 
   key_controller = gtk_event_controller_key_new ();
   g_signal_connect (key_controller, "key-pressed",
-                    G_CALLBACK (gtk_cell_renderer_spin_key_pressed),
-                    spin);
-  gtk_widget_add_controller (spin, key_controller);
+                    G_CALLBACK (gtk_cell_renderer_spin_key_pressed), priv->spin);
+  gtk_widget_add_controller (priv->spin, key_controller);
 
-  g_object_set_data_full (G_OBJECT (spin), GTK_CELL_RENDERER_SPIN_PATH,
+  g_object_set_data_full (G_OBJECT (priv->spin), GTK_CELL_RENDERER_SPIN_PATH,
                          g_strdup (path), g_free);
 
-  g_signal_connect (G_OBJECT (spin), "notify::has-focus",
-                   G_CALLBACK (gtk_cell_renderer_spin_focus_changed),
-                   cell);
+  g_signal_connect (priv->spin, "editing-done",
+                    G_CALLBACK (gtk_cell_renderer_spin_editing_done), cell);
 
-  gtk_widget_show (spin);
+  g_signal_connect (priv->spin, "notify::has-focus",
+                   G_CALLBACK (gtk_cell_renderer_spin_focus_changed), cell);
 
-  return GTK_CELL_EDITABLE (spin);
+  return GTK_CELL_EDITABLE (priv->spin);
 }
 
 /**
diff --git a/gtk/gtkspinbutton.c b/gtk/gtkspinbutton.c
index b7a460cfd3..9e16ac0d78 100644
--- a/gtk/gtkspinbutton.c
+++ b/gtk/gtkspinbutton.c
@@ -35,6 +35,7 @@
 #include "gtkbutton.h"
 #include "gtkcssstylepropertyprivate.h"
 #include "gtkeditable.h"
+#include "gtkcelleditable.h"
 #include "gtkimage.h"
 #include "gtktext.h"
 #include "gtkeventcontrollerkey.h"
@@ -54,6 +55,7 @@
 #include "gtkwidgetpath.h"
 #include "gtkwidgetprivate.h"
 #include "gtkboxlayout.h"
+#include "gtktextprivate.h"
 
 #include "a11y/gtkspinbuttonaccessible.h"
 
@@ -232,6 +234,7 @@ struct _GtkSpinButtonPrivate
   guint          snap_to_ticks : 1;
   guint          timer_calls   : 3;
   guint          wrap          : 1;
+  guint          editing_canceled : 1;
 };
 typedef struct _GtkSpinButtonPrivate GtkSpinButtonPrivate;
 
@@ -246,7 +249,8 @@ enum {
   PROP_UPDATE_POLICY,
   PROP_VALUE,
   NUM_SPINBUTTON_PROPS,
-  PROP_ORIENTATION = NUM_SPINBUTTON_PROPS
+  PROP_ORIENTATION = NUM_SPINBUTTON_PROPS,
+  PROP_EDITING_CANCELED
 };
 
 /* Signals */
@@ -261,6 +265,7 @@ enum
 };
 
 static void gtk_spin_button_editable_init  (GtkEditableInterface *iface);
+static void gtk_spin_button_cell_editable_init  (GtkCellEditableIface *iface);
 static void gtk_spin_button_finalize       (GObject            *object);
 static void gtk_spin_button_set_property   (GObject         *object,
                                             guint            prop_id,
@@ -309,7 +314,9 @@ G_DEFINE_TYPE_WITH_CODE (GtkSpinButton, gtk_spin_button, GTK_TYPE_WIDGET,
                          G_ADD_PRIVATE (GtkSpinButton)
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL)
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
-                                                gtk_spin_button_editable_init))
+                                                gtk_spin_button_editable_init)
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE,
+                                                gtk_spin_button_cell_editable_init))
 
 #define add_spin_binding(binding_set, keyval, mask, scroll)            \
   gtk_binding_entry_add_signal (binding_set, keyval, mask,             \
@@ -417,7 +424,8 @@ gtk_spin_button_class_init (GtkSpinButtonClass *class)
 
   g_object_class_install_properties (gobject_class, NUM_SPINBUTTON_PROPS, spinbutton_props);
   g_object_class_override_property (gobject_class, PROP_ORIENTATION, "orientation");
-  gtk_editable_install_properties (gobject_class, PROP_ORIENTATION + 1);
+  g_object_class_override_property (gobject_class, PROP_EDITING_CANCELED, "editing-canceled");
+  gtk_editable_install_properties (gobject_class, PROP_EDITING_CANCELED + 1);
 
   /**
    * GtkSpinButton::input:
@@ -572,6 +580,69 @@ gtk_spin_button_editable_init (GtkEditableInterface *iface)
   iface->insert_text = gtk_spin_button_insert_text;
 }
 
+static void
+gtk_cell_editable_spin_button_activated (GtkText *text, GtkSpinButton *spin)
+{
+  g_object_ref (spin);
+  gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (spin));
+  gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (spin));
+  g_object_unref (spin);
+}
+
+static gboolean
+gtk_cell_editable_spin_button_key_pressed (GtkEventControllerKey *key,
+                                           guint                  keyval,
+                                           guint                  keycode,
+                                           GdkModifierType        modifiers,
+                                           GtkSpinButton         *spin)
+{
+  GtkSpinButtonPrivate *priv = gtk_spin_button_get_instance_private (spin);
+
+  if (keyval == GDK_KEY_Escape)
+    {
+      priv->editing_canceled = TRUE;
+
+      g_object_ref (spin);
+      gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (spin));
+      gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (spin));
+      g_object_unref (spin);
+
+      return GDK_EVENT_STOP;
+    }
+
+  /* override focus */
+  if (keyval == GDK_KEY_Up || keyval == GDK_KEY_Down)
+    {
+      g_object_ref (spin);
+      gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (spin));
+      gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (spin));
+      g_object_unref (spin);
+
+      return GDK_EVENT_STOP;
+    }
+
+  return GDK_EVENT_PROPAGATE;
+}
+
+static void
+gtk_spin_button_start_editing (GtkCellEditable *cell_editable,
+                               GdkEvent        *event)
+{
+  GtkSpinButton *spin = GTK_SPIN_BUTTON (cell_editable);
+  GtkSpinButtonPrivate *priv = gtk_spin_button_get_instance_private (spin);
+
+  g_signal_connect (priv->entry, "activate",
+                    G_CALLBACK (gtk_cell_editable_spin_button_activated), cell_editable);
+  g_signal_connect (gtk_text_get_key_controller (GTK_TEXT (priv->entry)), "key-pressed",
+                    G_CALLBACK (gtk_cell_editable_spin_button_key_pressed), cell_editable);
+}
+
+static void
+gtk_spin_button_cell_editable_init (GtkCellEditableIface *iface)
+{
+  iface->start_editing = gtk_spin_button_start_editing;
+}
+
 static void
 gtk_spin_button_set_property (GObject      *object,
                               guint         prop_id,
@@ -622,6 +693,13 @@ gtk_spin_button_set_property (GObject      *object,
     case PROP_ORIENTATION:
       gtk_spin_button_set_orientation (spin_button, g_value_get_enum (value));
       break;
+    case PROP_EDITING_CANCELED:
+      if (priv->editing_canceled != g_value_get_boolean (value))
+        {
+          priv->editing_canceled = g_value_get_boolean (value);
+          g_object_notify (object, "editing-canceled");
+        }
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -669,6 +747,9 @@ gtk_spin_button_get_property (GObject      *object,
     case PROP_ORIENTATION:
       g_value_set_enum (value, priv->orientation);
       break;
+    case PROP_EDITING_CANCELED:
+      g_value_set_boolean (value, priv->editing_canceled);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;


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