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.
This commit is contained in:
Matthias Clasen
2019-12-24 03:33:02 -05:00
parent 72932d2776
commit cc3ecac6d8
2 changed files with 126 additions and 28 deletions

View File

@@ -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);
}
/**

View File

@@ -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;