diff --git a/libgimpwidgets/Makefile.gi b/libgimpwidgets/Makefile.gi index e5f65f44dd..685f015482 100644 --- a/libgimpwidgets/Makefile.gi +++ b/libgimpwidgets/Makefile.gi @@ -35,6 +35,7 @@ libgimpwidgets_introspectable_headers = \ ../libgimpwidgets/gimpintcombobox.h \ ../libgimpwidgets/gimpintstore.h \ ../libgimpwidgets/gimplabeled.h \ + ../libgimpwidgets/gimplabelentry.h \ ../libgimpwidgets/gimplabelintwidget.h \ ../libgimpwidgets/gimplabelspin.h \ ../libgimpwidgets/gimpmemsizeentry.h \ @@ -100,6 +101,7 @@ libgimpwidgets_introspectable = \ ../libgimpwidgets/gimpintcombobox.c \ ../libgimpwidgets/gimpintstore.c \ ../libgimpwidgets/gimplabeled.c \ + ../libgimpwidgets/gimplabelentry.c \ ../libgimpwidgets/gimplabelintwidget.c \ ../libgimpwidgets/gimplabelspin.c \ ../libgimpwidgets/gimpmemsizeentry.c \ diff --git a/libgimpwidgets/gimplabelentry.c b/libgimpwidgets/gimplabelentry.c new file mode 100644 index 0000000000..6b60f3d936 --- /dev/null +++ b/libgimpwidgets/gimplabelentry.c @@ -0,0 +1,296 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimplabelentry.c + * Copyright (C) 2022 Jehan + * + * 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 3 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 + * Library 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 + * . + */ + +#include "config.h" + +#include +#include + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" +#include "libgimpbase/gimpbase.h" + +#include "gimpwidgets.h" + + +/** + * SECTION: gimplabelentry + * @title: GimpLabelEntry + * @short_description: Widget containing an entry and a label. + * + * This widget is a subclass of #GimpLabeled with a #GtkEntry. + **/ + +enum +{ + VALUE_CHANGED, + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_VALUE, +}; + +typedef struct _GimpLabelEntryPrivate +{ + GtkWidget *entry; +} GimpLabelEntryPrivate; + +static void gimp_label_entry_constructed (GObject *object); +static void gimp_label_entry_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_label_entry_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static GtkWidget * gimp_label_entry_populate (GimpLabeled *entry, + gint *x, + gint *y, + gint *width, + gint *height); + +G_DEFINE_TYPE_WITH_PRIVATE (GimpLabelEntry, gimp_label_entry, GIMP_TYPE_LABELED) + +#define parent_class gimp_label_entry_parent_class + +static guint gimp_label_entry_signals[LAST_SIGNAL] = { 0 }; + +static void +gimp_label_entry_class_init (GimpLabelEntryClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpLabeledClass *labeled_class = GIMP_LABELED_CLASS (klass); + + gimp_label_entry_signals[VALUE_CHANGED] = + g_signal_new ("value-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GimpLabelEntryClass, value_changed), + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + object_class->constructed = gimp_label_entry_constructed; + object_class->set_property = gimp_label_entry_set_property; + object_class->get_property = gimp_label_entry_get_property; + + labeled_class->populate = gimp_label_entry_populate; + + /** + * GimpLabelEntry:value: + * + * The currently set value. + * + * Since: 3.0 + **/ + g_object_class_install_property (object_class, PROP_VALUE, + g_param_spec_string ("value", + "Entry text", + "The text in the entry", + NULL, + GIMP_PARAM_READWRITE)); +} + +static void +gimp_label_entry_init (GimpLabelEntry *entry) +{ + GimpLabelEntryPrivate *priv = gimp_label_entry_get_instance_private (entry); + + priv->entry = gtk_entry_new (); +} + +static void +gimp_label_entry_constructed (GObject *object) +{ + GimpLabelEntry *entry = GIMP_LABEL_ENTRY (object); + GimpLabelEntryPrivate *priv = gimp_label_entry_get_instance_private (entry); + GtkEntryBuffer *buffer = gtk_entry_get_buffer (GTK_ENTRY (priv->entry)); + + G_OBJECT_CLASS (parent_class)->constructed (object); + + /* This is important to make this object into a property widget. It + * will allow config object to bind the "value" property of this + * widget, and therefore be updated automatically. + */ + g_object_bind_property (G_OBJECT (buffer), "text", + G_OBJECT (entry), "value", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); +} + +static void +gimp_label_entry_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpLabelEntry *entry = GIMP_LABEL_ENTRY (object); + GimpLabelEntryPrivate *priv = gimp_label_entry_get_instance_private (entry); + + switch (property_id) + { + case PROP_VALUE: + { + GtkEntryBuffer *buffer = gtk_entry_get_buffer (GTK_ENTRY (priv->entry)); + + /* Avoid looping forever since we have bound this widget's + * "value" property with the entry button "value" property. + */ + if (g_strcmp0 (gtk_entry_buffer_get_text (buffer), + g_value_get_string (value)) != 0) + gtk_entry_buffer_set_text (buffer, g_value_get_string (value), -1); + + g_signal_emit (object, gimp_label_entry_signals[VALUE_CHANGED], 0); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_label_entry_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpLabelEntry *entry = GIMP_LABEL_ENTRY (object); + GimpLabelEntryPrivate *priv = gimp_label_entry_get_instance_private (entry); + + switch (property_id) + { + case PROP_VALUE: + { + GtkEntryBuffer *buffer = gtk_entry_get_buffer (GTK_ENTRY (priv->entry)); + + g_value_set_string (value, gtk_entry_buffer_get_text (buffer)); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static GtkWidget * +gimp_label_entry_populate (GimpLabeled *labeled, + gint *x, + gint *y, + gint *width, + gint *height) +{ + GimpLabelEntry *entry = GIMP_LABEL_ENTRY (labeled); + GimpLabelEntryPrivate *priv = gimp_label_entry_get_instance_private (entry); + + gtk_grid_attach (GTK_GRID (entry), priv->entry, 1, 0, 1, 1); + /* Make sure the label and entry won't be glued next to each other's. */ + gtk_grid_set_column_spacing (GTK_GRID (entry), + 4 * gtk_widget_get_scale_factor (GTK_WIDGET (entry))); + gtk_widget_show (priv->entry); + + return priv->entry; +} + + +/* Public Functions */ + + +/** + * gimp_label_entry_new: + * @label: The text for the #GtkLabel. + * + * + * Returns: (transfer full): The new #GimpLabelEntry widget. + **/ +GtkWidget * +gimp_label_entry_new (const gchar *label) +{ + GtkWidget *labeled; + + labeled = g_object_new (GIMP_TYPE_LABEL_ENTRY, + "label", label, + NULL); + + return labeled; +} + +/** + * gimp_label_entry_set_value: + * @entry: The #GtkLabelEntry. + * @value: A new value. + * + * This function sets the value in the #GtkEntry inside @entry. + **/ +void +gimp_label_entry_set_value (GimpLabelEntry *entry, + const gchar *value) +{ + g_return_if_fail (GIMP_IS_LABEL_ENTRY (entry)); + + g_object_set (entry, + "value", value, + NULL); +} + +/** + * gimp_label_entry_get_value: + * @entry: The #GtkLabelEntry. + * + * This function returns the value shown by @entry. + * + * Returns: (transfer none): The value currently set. + **/ +const gchar * +gimp_label_entry_get_value (GimpLabelEntry *entry) +{ + GimpLabelEntryPrivate *priv = gimp_label_entry_get_instance_private (entry); + GtkEntryBuffer *buffer; + + g_return_val_if_fail (GIMP_IS_LABEL_ENTRY (entry), NULL); + + buffer = gtk_entry_get_buffer (GTK_ENTRY (priv->entry)); + + return gtk_entry_buffer_get_text (buffer); +} + +/** + * gimp_label_entry_get_entry: + * @entry: The #GimpLabelEntry + * + * This function returns the #GtkEntry packed in @entry. + * + * Returns: (transfer none): The #GtkEntry contained in @entry. + **/ +GtkWidget * +gimp_label_entry_get_entry (GimpLabelEntry *entry) +{ + GimpLabelEntryPrivate *priv = gimp_label_entry_get_instance_private (entry); + + g_return_val_if_fail (GIMP_IS_LABEL_ENTRY (entry), NULL); + + return priv->entry; +} diff --git a/libgimpwidgets/gimplabelentry.h b/libgimpwidgets/gimplabelentry.h new file mode 100644 index 0000000000..fa69df18b3 --- /dev/null +++ b/libgimpwidgets/gimplabelentry.h @@ -0,0 +1,64 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimplabelentry.h + * Copyright (C) 2022 Jehan + * + * 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 3 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 + * . + */ + +#if !defined (__GIMP_WIDGETS_H_INSIDE__) && !defined (GIMP_WIDGETS_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __GIMP_LABEL_ENTRY_H__ +#define __GIMP_LABEL_ENTRY_H__ + +#include + +G_BEGIN_DECLS + +#define GIMP_TYPE_LABEL_ENTRY (gimp_label_entry_get_type ()) +G_DECLARE_DERIVABLE_TYPE (GimpLabelEntry, gimp_label_entry, GIMP, LABEL_ENTRY, GimpLabeled) + +struct _GimpLabelEntryClass +{ + GimpLabeledClass parent_class; + + /* Signals */ + void (* value_changed) (GimpLabelEntry *entry); + + /* Padding for future expansion */ + void (* _gimp_reserved1) (void); + void (* _gimp_reserved2) (void); + void (* _gimp_reserved3) (void); + void (* _gimp_reserved4) (void); + void (* _gimp_reserved5) (void); + void (* _gimp_reserved6) (void); + void (* _gimp_reserved7) (void); + void (* _gimp_reserved8) (void); +}; + +GtkWidget * gimp_label_entry_new (const gchar *label); + +void gimp_label_entry_set_value (GimpLabelEntry *entry, + const gchar *value); +const gchar * gimp_label_entry_get_value (GimpLabelEntry *entry); + +GtkWidget * gimp_label_entry_get_entry (GimpLabelEntry *entry); + +G_END_DECLS + +#endif /* __GIMP_LABEL_ENTRY_H__ */ diff --git a/libgimpwidgets/gimppropwidgets.c b/libgimpwidgets/gimppropwidgets.c index 34db39d2a6..c624cd48e2 100644 --- a/libgimpwidgets/gimppropwidgets.c +++ b/libgimpwidgets/gimppropwidgets.c @@ -2100,6 +2100,63 @@ gimp_prop_entry_notify (GObject *config, g_free (value); } +/*****************/ +/* label entry */ +/*****************/ + +/** + * gimp_prop_label_entry_new: + * @config: Object to which property is attached. + * @property_name: Name of string property. + * @max_len: Maximum allowed length of string (set to negative for + * no maximum). + * + * Creates a #GimpLabelEntry to set and display the value of the + * specified string property. + * + * Returns: (transfer full): A new #GtkEntry widget. + * + * Since: 3.0 + */ +GtkWidget * +gimp_prop_label_entry_new (GObject *config, + const gchar *property_name, + gint max_len) +{ + GParamSpec *param_spec; + GtkWidget *label_entry; + GtkWidget *entry; + const gchar *label; + + g_return_val_if_fail (G_IS_OBJECT (config), NULL); + g_return_val_if_fail (property_name != NULL, NULL); + + param_spec = check_param_spec (config, property_name, + G_TYPE_PARAM_STRING, G_STRFUNC); + if (! param_spec) + return NULL; + + label = g_param_spec_get_nick (param_spec); + label_entry = gimp_label_entry_new (label); + entry = gimp_label_entry_get_entry (GIMP_LABEL_ENTRY (label_entry)); + + if (max_len > 0) + gtk_entry_set_max_length (GTK_ENTRY (entry), max_len); + + gtk_editable_set_editable (GTK_EDITABLE (entry), + param_spec->flags & G_PARAM_WRITABLE); + + set_param_spec (G_OBJECT (label_entry), label_entry, param_spec); + + g_object_bind_property (config, property_name, + label_entry, "value", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + + gtk_widget_show (label_entry); + + return label_entry; +} + /*****************/ /* text buffer */ diff --git a/libgimpwidgets/gimppropwidgets.h b/libgimpwidgets/gimppropwidgets.h index 120df1ab2c..8bfdf99e24 100644 --- a/libgimpwidgets/gimppropwidgets.h +++ b/libgimpwidgets/gimppropwidgets.h @@ -147,6 +147,9 @@ GtkWidget * gimp_prop_label_new (GObject *config, GtkWidget * gimp_prop_entry_new (GObject *config, const gchar *property_name, gint max_len); +GtkWidget * gimp_prop_label_entry_new (GObject *config, + const gchar *property_name, + gint max_len); GtkTextBuffer * gimp_prop_text_buffer_new (GObject *config, const gchar *property_name, gint max_len); diff --git a/libgimpwidgets/gimpwidgets.h b/libgimpwidgets/gimpwidgets.h index 84bc0b2473..b7dc789081 100644 --- a/libgimpwidgets/gimpwidgets.h +++ b/libgimpwidgets/gimpwidgets.h @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include diff --git a/libgimpwidgets/gimpwidgetstypes.h b/libgimpwidgets/gimpwidgetstypes.h index 3177bf39e9..940698e757 100644 --- a/libgimpwidgets/gimpwidgetstypes.h +++ b/libgimpwidgets/gimpwidgetstypes.h @@ -63,6 +63,7 @@ typedef struct _GimpHintBox GimpHintBox; typedef struct _GimpIntComboBox GimpIntComboBox; typedef struct _GimpIntStore GimpIntStore; typedef struct _GimpLabeled GimpLabeled; +typedef struct _GimpLabelEntry GimpLabelEntry; typedef struct _GimpLabelSpin GimpLabelSpin; typedef struct _GimpMemsizeEntry GimpMemsizeEntry; typedef struct _GimpNumberPairEntry GimpNumberPairEntry; diff --git a/libgimpwidgets/meson.build b/libgimpwidgets/meson.build index 7004d8cb3e..9521a69cf9 100644 --- a/libgimpwidgets/meson.build +++ b/libgimpwidgets/meson.build @@ -57,6 +57,7 @@ libgimpwidgets_sources_introspectable = files( 'gimplabeled.c', 'gimplabelintwidget.c', 'gimplabelspin.c', + 'gimplabelentry.c', 'gimpmemsizeentry.c', 'gimpnumberpairentry.c', 'gimpoffsetarea.c', @@ -133,6 +134,7 @@ libgimpwidgets_headers_introspectable = files( 'gimplabeled.h', 'gimplabelintwidget.h', 'gimplabelspin.h', + 'gimplabelentry.h', 'gimpintstore.h', 'gimpmemsizeentry.h', 'gimpnumberpairentry.h',