diff options
Diffstat (limited to 'libgimpwidgets/gimpquerybox.c')
-rw-r--r-- | libgimpwidgets/gimpquerybox.c | 699 |
1 files changed, 699 insertions, 0 deletions
diff --git a/libgimpwidgets/gimpquerybox.c b/libgimpwidgets/gimpquerybox.c new file mode 100644 index 0000000..f26e609 --- /dev/null +++ b/libgimpwidgets/gimpquerybox.c @@ -0,0 +1,699 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpquerybox.c + * Copyright (C) 1999-2000 Michael Natterer <mitch@gimp.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 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 + * <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> +#include <gtk/gtk.h> + +#include "libgimpbase/gimpbase.h" + +#include "gimpwidgetstypes.h" + +#include "gimpdialog.h" +#include "gimppixmap.h" +#include "gimpquerybox.h" +#include "gimpsizeentry.h" +#include "gimpspinbutton.h" +#include "gimpwidgets.h" + +#include "libgimp/libgimp-intl.h" + + +/** + * SECTION: gimpquerybox + * @title: GimpQueryBox + * @short_description: Some simple dialogs to enter a single int, + * double, string or boolean value. + * @see_also: #GimpSizeEntry, #GimpUnitMenu + * + * These functions provide simple dialogs for entering a single + * string, integer, double, boolean or pixel size value. + * + * They return a pointer to a #GtkDialog which has to be shown with + * gtk_widget_show() by the caller. + * + * The dialogs contain an entry widget for the kind of value they ask + * for and "OK" and "Cancel" buttons. On "Cancel", all query boxes + * except the boolean one silently destroy themselves. On "OK" the + * user defined callback function is called and returns the entered + * value. + **/ + + +/* + * String, integer, double and size query boxes + */ + +typedef struct _QueryBox QueryBox; + +struct _QueryBox +{ + GtkWidget *qbox; + GtkWidget *vbox; + GtkWidget *entry; + GObject *object; + gulong response_handler; + GCallback callback; + gpointer callback_data; +}; + + +static QueryBox * create_query_box (const gchar *title, + GtkWidget *parent, + GimpHelpFunc help_func, + const gchar *help_id, + GCallback response_callback, + const gchar *icon_name, + const gchar *message, + const gchar *ok_button, + const gchar *cancel_button, + GObject *object, + const gchar *signal, + GCallback callback, + gpointer callback_data); + +static void query_box_disconnect (QueryBox *query_box); +static void query_box_destroy (QueryBox *query_box); + +static void string_query_box_response (GtkWidget *widget, + gint response_id, + QueryBox *query_box); +static void int_query_box_response (GtkWidget *widget, + gint response_id, + QueryBox *query_box); +static void double_query_box_response (GtkWidget *widget, + gint response_id, + QueryBox *query_box); +static void size_query_box_response (GtkWidget *widget, + gint response_id, + QueryBox *query_box); +static void boolean_query_box_response (GtkWidget *widget, + gint response_id, + QueryBox *query_box); + +static void query_box_cancel_callback (QueryBox *query_box); + + +/* + * create a generic query box without any entry widget + */ +static QueryBox * +create_query_box (const gchar *title, + GtkWidget *parent, + GimpHelpFunc help_func, + const gchar *help_id, + GCallback response_callback, + const gchar *icon_name, + const gchar *message, + const gchar *ok_button, + const gchar *cancel_button, + GObject *object, + const gchar *signal, + GCallback callback, + gpointer callback_data) +{ + QueryBox *query_box; + GtkWidget *hbox = NULL; + GtkWidget *label; + + /* make sure the object / signal passed are valid + */ + g_return_val_if_fail (parent == NULL || GTK_IS_WIDGET (parent), NULL); + g_return_val_if_fail (object == NULL || G_IS_OBJECT (object), NULL); + g_return_val_if_fail (object == NULL || signal != NULL, NULL); + + query_box = g_slice_new0 (QueryBox); + + query_box->qbox = gimp_dialog_new (title, "gimp-query-box", + parent, 0, + help_func, help_id, + + cancel_button, GTK_RESPONSE_CANCEL, + ok_button, GTK_RESPONSE_OK, + + NULL); + + gtk_dialog_set_alternative_button_order (GTK_DIALOG (query_box->qbox), + GTK_RESPONSE_OK, + GTK_RESPONSE_CANCEL, + -1); + + query_box->response_handler = + g_signal_connect (query_box->qbox, "response", + G_CALLBACK (response_callback), + query_box); + + g_signal_connect (query_box->qbox, "destroy", + G_CALLBACK (gtk_widget_destroyed), + &query_box->qbox); + + /* if we are associated with an object, connect to the provided signal + */ + if (object) + { + GClosure *closure; + + closure = g_cclosure_new_swap (G_CALLBACK (query_box_cancel_callback), + query_box, NULL); + g_object_watch_closure (G_OBJECT (query_box->qbox), closure); + + g_signal_connect_closure (object, signal, closure, FALSE); + } + + if (icon_name) + { + GtkWidget *content_area; + GtkWidget *image; + + content_area = gtk_dialog_get_content_area (GTK_DIALOG (query_box->qbox)); + + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 12); + gtk_box_pack_start (GTK_BOX (content_area), hbox, TRUE, TRUE, 0); + gtk_widget_show (hbox); + + image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0); + gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); + gtk_widget_show (image); + } + + query_box->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); + + g_object_set_data (G_OBJECT (query_box->qbox), "gimp-query-box-vbox", + query_box->vbox); + + if (hbox) + { + gtk_box_pack_start (GTK_BOX (hbox), query_box->vbox, FALSE, FALSE, 0); + } + else + { + GtkWidget *content_area; + + content_area = gtk_dialog_get_content_area (GTK_DIALOG (query_box->qbox)); + + gtk_container_set_border_width (GTK_CONTAINER (query_box->vbox), 12); + gtk_box_pack_start (GTK_BOX (content_area), query_box->vbox, + TRUE, TRUE, 0); + } + + gtk_widget_show (query_box->vbox); + + if (message) + { + label = gtk_label_new (message); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_box_pack_start (GTK_BOX (query_box->vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + } + + query_box->entry = NULL; + query_box->object = object; + query_box->callback = callback; + query_box->callback_data = callback_data; + + return query_box; +} + +/** + * gimp_query_string_box: + * @title: The query box dialog's title. + * @parent: The dialog's parent widget. + * @help_func: The help function to show this dialog's help page. + * @help_id: A string identifying this dialog's help page. + * @message: A string which will be shown above the dialog's entry widget. + * @initial: The initial value. + * @object: The object this query box is associated with. + * @signal: The object's signal which will cause the query box to be closed. + * @callback: The function which will be called when the user selects "OK". + * @data: The callback's user data. + * + * Creates a new #GtkDialog that queries the user for a string value. + * + * Returns: A pointer to the new #GtkDialog. + **/ +GtkWidget * +gimp_query_string_box (const gchar *title, + GtkWidget *parent, + GimpHelpFunc help_func, + const gchar *help_id, + const gchar *message, + const gchar *initial, + GObject *object, + const gchar *signal, + GimpQueryStringCallback callback, + gpointer data) +{ + QueryBox *query_box; + GtkWidget *entry; + + query_box = create_query_box (title, parent, help_func, help_id, + G_CALLBACK (string_query_box_response), + "dialog-question", + message, + _("_OK"), _("_Cancel"), + object, signal, + G_CALLBACK (callback), data); + + if (! query_box) + return NULL; + + entry = gtk_entry_new (); + gtk_entry_set_text (GTK_ENTRY (entry), initial ? initial : ""); + gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); + gtk_box_pack_start (GTK_BOX (query_box->vbox), entry, FALSE, FALSE, 0); + gtk_widget_grab_focus (entry); + gtk_widget_show (entry); + + query_box->entry = entry; + + return query_box->qbox; +} + +/** + * gimp_query_int_box: + * @title: The query box dialog's title. + * @parent: The dialog's parent widget. + * @help_func: The help function to show this dialog's help page. + * @help_id: A string identifying this dialog's help page. + * @message: A string which will be shown above the dialog's entry widget. + * @initial: The initial value. + * @lower: The lower boundary of the range of possible values. + * @upper: The upper boundray of the range of possible values. + * @object: The object this query box is associated with. + * @signal: The object's signal which will cause the query box to be closed. + * @callback: The function which will be called when the user selects "OK". + * @data: The callback's user data. + * + * Creates a new #GtkDialog that queries the user for an integer value. + * + * Returns: A pointer to the new #GtkDialog. + **/ +GtkWidget * +gimp_query_int_box (const gchar *title, + GtkWidget *parent, + GimpHelpFunc help_func, + const gchar *help_id, + const gchar *message, + gint initial, + gint lower, + gint upper, + GObject *object, + const gchar *signal, + GimpQueryIntCallback callback, + gpointer data) +{ + QueryBox *query_box; + GtkWidget *spinbutton; + GtkAdjustment *adjustment; + + query_box = create_query_box (title, parent, help_func, help_id, + G_CALLBACK (int_query_box_response), + "dialog-question", + message, + _("_OK"), _("_Cancel"), + object, signal, + G_CALLBACK (callback), data); + + if (! query_box) + return NULL; + + adjustment = (GtkAdjustment *) + gtk_adjustment_new (initial, lower, upper, 1, 10, 0); + spinbutton = gimp_spin_button_new (adjustment, 1.0, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); + gtk_entry_set_activates_default (GTK_ENTRY (spinbutton), TRUE); + gtk_box_pack_start (GTK_BOX (query_box->vbox), spinbutton, FALSE, FALSE, 0); + gtk_widget_grab_focus (spinbutton); + gtk_widget_show (spinbutton); + + query_box->entry = spinbutton; + + return query_box->qbox; +} + +/** + * gimp_query_double_box: + * @title: The query box dialog's title. + * @parent: The dialog's parent widget. + * @help_func: The help function to show this dialog's help page. + * @help_id: A string identifying this dialog's help page. + * @message: A string which will be shown above the dialog's entry widget. + * @initial: The initial value. + * @lower: The lower boundary of the range of possible values. + * @upper: The upper boundray of the range of possible values. + * @digits: The number of decimal digits the #GtkSpinButton will provide. + * @object: The object this query box is associated with. + * @signal: The object's signal which will cause the query box to be closed. + * @callback: The function which will be called when the user selects "OK". + * @data: The callback's user data. + * + * Creates a new #GtkDialog that queries the user for a double value. + * + * Returns: A pointer to the new #GtkDialog. + **/ +GtkWidget * +gimp_query_double_box (const gchar *title, + GtkWidget *parent, + GimpHelpFunc help_func, + const gchar *help_id, + const gchar *message, + gdouble initial, + gdouble lower, + gdouble upper, + gint digits, + GObject *object, + const gchar *signal, + GimpQueryDoubleCallback callback, + gpointer data) +{ + QueryBox *query_box; + GtkWidget *spinbutton; + GtkAdjustment *adjustment; + + query_box = create_query_box (title, parent, help_func, help_id, + G_CALLBACK (double_query_box_response), + "dialog-question", + message, + _("_OK"), _("_Cancel"), + object, signal, + G_CALLBACK (callback), data); + + if (! query_box) + return NULL; + + adjustment = (GtkAdjustment *) + gtk_adjustment_new (initial, lower, upper, 1, 10, 0); + spinbutton = gimp_spin_button_new (adjustment, 1.0, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); + gtk_entry_set_activates_default (GTK_ENTRY (spinbutton), TRUE); + gtk_box_pack_start (GTK_BOX (query_box->vbox), spinbutton, FALSE, FALSE, 0); + gtk_widget_grab_focus (spinbutton); + gtk_widget_show (spinbutton); + + query_box->entry = spinbutton; + + return query_box->qbox; +} + +/** + * gimp_query_size_box: + * @title: The query box dialog's title. + * @parent: The dialog's parent widget. + * @help_func: The help function to show this dialog's help page. + * @help_id: A string identifying this dialog's help page. + * @message: A string which will be shown above the dialog's entry widget. + * @initial: The initial value. + * @lower: The lower boundary of the range of possible values. + * @upper: The upper boundray of the range of possible values. + * @digits: The number of decimal digits the #GimpSizeEntry provide in + * "pixel" mode. + * @unit: The unit initially shown by the #GimpUnitMenu. + * @resolution: The resolution (in dpi) which will be used for pixel/unit + * calculations. + * @dot_for_dot: %TRUE if the #GimpUnitMenu's initial unit should be "pixels". + * @object: The object this query box is associated with. + * @signal: The object's signal which will cause the query box + * to be closed. + * @callback: The function which will be called when the user selects "OK". + * @data: The callback's user data. + * + * Creates a new #GtkDialog that queries the user for a size using a + * #GimpSizeEntry. + * + * Returns: A pointer to the new #GtkDialog. + **/ +GtkWidget * +gimp_query_size_box (const gchar *title, + GtkWidget *parent, + GimpHelpFunc help_func, + const gchar *help_id, + const gchar *message, + gdouble initial, + gdouble lower, + gdouble upper, + gint digits, + GimpUnit unit, + gdouble resolution, + gboolean dot_for_dot, + GObject *object, + const gchar *signal, + GimpQuerySizeCallback callback, + gpointer data) +{ + QueryBox *query_box; + GtkWidget *sizeentry; + GtkWidget *spinbutton; + + query_box = create_query_box (title, parent, help_func, help_id, + G_CALLBACK (size_query_box_response), + "dialog-question", + message, + _("_OK"), _("_Cancel"), + object, signal, + G_CALLBACK (callback), data); + + if (! query_box) + return NULL; + + sizeentry = gimp_size_entry_new (1, unit, "%p", TRUE, FALSE, FALSE, 12, + GIMP_SIZE_ENTRY_UPDATE_SIZE); + if (dot_for_dot) + gimp_size_entry_set_unit (GIMP_SIZE_ENTRY (sizeentry), GIMP_UNIT_PIXEL); + gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (sizeentry), 0, + resolution, FALSE); + gimp_size_entry_set_refval_digits (GIMP_SIZE_ENTRY (sizeentry), 0, digits); + gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), 0, + lower, upper); + gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (sizeentry), 0, initial); + + spinbutton = gimp_size_entry_get_help_widget (GIMP_SIZE_ENTRY (sizeentry), 0); + gtk_entry_set_activates_default (GTK_ENTRY (spinbutton), TRUE); + + gtk_box_pack_start (GTK_BOX (query_box->vbox), sizeentry, FALSE, FALSE, 0); + gimp_size_entry_grab_focus (GIMP_SIZE_ENTRY (sizeentry)); + gtk_widget_show (sizeentry); + + query_box->entry = sizeentry; + + return query_box->qbox; +} + +/** + * gimp_query_boolean_box: + * @title: The query box dialog's title. + * @parent: The dialog's parent widget. + * @help_func: The help function to show this dialog's help page. + * @help_id: A string identifying this dialog's help page. + * @icon_name: An icon name to specify an icon to appear on the left + * on the dialog's message. + * @message: A string which will be shown in the query box. + * @true_button: The string to be shown in the dialog's left button. + * @false_button: The string to be shown in the dialog's right button. + * @object: The object this query box is associated with. + * @signal: The object's signal which will cause the query box + * to be closed. + * @callback: The function which will be called when the user clicks one + * of the buttons. + * @data: The callback's user data. + * + * Creates a new #GtkDialog that asks the user to do a boolean decision. + * + * Returns: A pointer to the new #GtkDialog. + **/ +GtkWidget * +gimp_query_boolean_box (const gchar *title, + GtkWidget *parent, + GimpHelpFunc help_func, + const gchar *help_id, + const gchar *icon_name, + const gchar *message, + const gchar *true_button, + const gchar *false_button, + GObject *object, + const gchar *signal, + GimpQueryBooleanCallback callback, + gpointer data) +{ + QueryBox *query_box; + + query_box = create_query_box (title, parent, help_func, help_id, + G_CALLBACK (boolean_query_box_response), + icon_name, + message, + true_button, false_button, + object, signal, + G_CALLBACK (callback), data); + + if (! query_box) + return NULL; + + return query_box->qbox; +} + + +/* + * private functions + */ + +static void +query_box_disconnect (QueryBox *query_box) +{ + gtk_widget_set_sensitive (query_box->qbox, FALSE); + + /* disconnect the response callback to avoid that it may be run twice */ + if (query_box->response_handler) + { + g_signal_handler_disconnect (query_box->qbox, + query_box->response_handler); + + query_box->response_handler = 0; + } + + /* disconnect, if we are connected to some signal */ + if (query_box->object) + g_signal_handlers_disconnect_by_func (query_box->object, + query_box_cancel_callback, + query_box); +} + +static void +query_box_destroy (QueryBox *query_box) +{ + /* Destroy the box */ + if (query_box->qbox) + gtk_widget_destroy (query_box->qbox); + + g_slice_free (QueryBox, query_box); +} + +static void +string_query_box_response (GtkWidget *widget, + gint response_id, + QueryBox *query_box) +{ + const gchar *string; + + query_box_disconnect (query_box); + + /* Get the entry data */ + string = gtk_entry_get_text (GTK_ENTRY (query_box->entry)); + + /* Call the user defined callback */ + if (response_id == GTK_RESPONSE_OK) + (* (GimpQueryStringCallback) query_box->callback) (query_box->qbox, + string, + query_box->callback_data); + + query_box_destroy (query_box); +} + +static void +int_query_box_response (GtkWidget *widget, + gint response_id, + QueryBox *query_box) +{ + gint value; + + query_box_disconnect (query_box); + + /* Get the spinbutton data */ + value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (query_box->entry)); + + /* Call the user defined callback */ + if (response_id == GTK_RESPONSE_OK) + (* (GimpQueryIntCallback) query_box->callback) (query_box->qbox, + value, + query_box->callback_data); + + query_box_destroy (query_box); +} + +static void +double_query_box_response (GtkWidget *widget, + gint response_id, + QueryBox *query_box) +{ + gdouble value; + + query_box_disconnect (query_box); + + /* Get the spinbutton data */ + value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (query_box->entry)); + + /* Call the user defined callback */ + if (response_id == GTK_RESPONSE_OK) + (* (GimpQueryDoubleCallback) query_box->callback) (query_box->qbox, + value, + query_box->callback_data); + + query_box_destroy (query_box); +} + +static void +size_query_box_response (GtkWidget *widget, + gint response_id, + QueryBox *query_box) +{ + gdouble size; + GimpUnit unit; + + query_box_disconnect (query_box); + + /* Get the sizeentry data */ + size = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (query_box->entry), 0); + unit = gimp_size_entry_get_unit (GIMP_SIZE_ENTRY (query_box->entry)); + + /* Call the user defined callback */ + if (response_id == GTK_RESPONSE_OK) + (* (GimpQuerySizeCallback) query_box->callback) (query_box->qbox, + size, + unit, + query_box->callback_data); + + query_box_destroy (query_box); +} + +static void +boolean_query_box_response (GtkWidget *widget, + gint response_id, + QueryBox *query_box) +{ + query_box_disconnect (query_box); + + /* Call the user defined callback */ + (* (GimpQueryBooleanCallback) query_box->callback) (query_box->qbox, + (response_id == + GTK_RESPONSE_OK), + query_box->callback_data); + + query_box_destroy (query_box); +} + +static void +query_box_cancel_callback (QueryBox *query_box) +{ + query_box_disconnect (query_box); + query_box_destroy (query_box); +} |