From ce44b04005a03517d506db34730e2196a71dcfcb Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Thu, 18 Jul 2019 02:10:24 +0200 Subject: [PATCH] app: improve gegl:newsprint's GUI a lot Add some frames, a notebook for the channels and toggles to lock all channels' properties together. --- app/propgui/gimppropgui-newsprint.c | 388 +++++++++++++++++++++++++++- 1 file changed, 385 insertions(+), 3 deletions(-) diff --git a/app/propgui/gimppropgui-newsprint.c b/app/propgui/gimppropgui-newsprint.c index dfc95f937e..ecdc0dcdef 100644 --- a/app/propgui/gimppropgui-newsprint.c +++ b/app/propgui/gimppropgui-newsprint.c @@ -23,6 +23,7 @@ #include #include +#include "libgimpmath/gimpmath.h" #include "libgimpwidgets/gimpwidgets.h" #include "propgui-types.h" @@ -36,6 +37,91 @@ #include "gimp-intl.h" +typedef enum +{ + COLOR_MODEL_WHITE_ON_BLACK, + COLOR_MODEL_BLACK_ON_WHITE, + COLOR_MODEL_RGB, + COLOR_MODEL_CMYK, + + N_COLOR_MODELS +} ColorModel; + +typedef enum +{ + PATTERN_LINE, + PATTERN_CIRCLE, + PATTERN_DIAMOND, + PATTERN_PSCIRCLE, + PATTERN_CROSS, + + N_PATTERNS +} Pattern; + + +typedef struct _Newsprint Newsprint; + +struct _Newsprint +{ + GObject *config; + GtkWidget *notebook; + GtkWidget *pattern_check; + GtkWidget *period_check; + GtkWidget *angle_check; +}; + + +/* local function prototypes */ + +static void newsprint_color_model_notify (GObject *config, + const GParamSpec *pspec, + GtkWidget *label); +static void newsprint_model_prop_notify (GObject *config, + const GParamSpec *pspec, + Newsprint *np); +static void newsprint_lock_patterns_toggled (GtkWidget *widget, + Newsprint *np); +static void newsprint_lock_periods_toggled (GtkWidget *widget, + Newsprint *np); +static void newsprint_lock_angles_toggled (GtkWidget *widget, + Newsprint *np); + + +static const gchar *label_strings[N_COLOR_MODELS][4] = +{ + { NULL, NULL, NULL, N_("White") }, + { NULL, NULL, NULL, N_("Black") }, + { N_("Red"), N_("Green"), N_("Blue"), NULL }, + { N_("Cyan"), N_("Magenta"), N_("Yellow"), N_("Black") } +}; + +static const gchar *pattern_props[] = +{ + "pattern2", + "pattern3", + "pattern4", + "pattern" +}; + +static const gchar *period_props[] = +{ + "period2", + "period3", + "period4", + "period" +}; + +static const gchar *angle_props[] = +{ + "angle2", + "angle3", + "angle4", + "angle" +}; + + +/* public functions */ + GtkWidget * _gimp_prop_gui_new_newsprint (GObject *config, GParamSpec **param_specs, @@ -46,17 +132,313 @@ _gimp_prop_gui_new_newsprint (GObject *config, GimpCreateControllerFunc create_controller_func, gpointer creator) { + Newsprint *np; + GtkWidget *main_vbox; + GtkWidget *frame; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *combo; + GtkWidget *labels[4]; + GtkWidget *pages[4]; + GtkWidget *check; + gint i; + g_return_val_if_fail (G_IS_OBJECT (config), NULL); g_return_val_if_fail (param_specs != NULL, NULL); g_return_val_if_fail (n_param_specs > 0, NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); - return _gimp_prop_gui_new_generic (config, - param_specs, - n_param_specs, + np = g_new0 (Newsprint, 1); + + np->config = config; + + main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4); + + g_object_set_data_full (G_OBJECT (main_vbox), "newsprint", np, + (GDestroyNotify) g_free); + + frame = gimp_frame_new (_("Channels")); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_widget_show (vbox); + + combo = _gimp_prop_gui_new_generic (config, + param_specs + 0, 1, + area, + context, + create_picker_func, + create_controller_func, + creator); + gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0); + gtk_widget_show (combo); + + np->notebook = gtk_notebook_new (); + gtk_box_pack_start (GTK_BOX (vbox), np->notebook, FALSE, FALSE, 0); + gtk_widget_show (np->notebook); + + for (i = 0; i < 4; i++) + { + GtkWidget *widget; + const gchar *unused; + gint remaining; + + labels[i] = gtk_label_new (NULL); + pages[i] = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); + + g_object_set_data (G_OBJECT (labels[i]), "channel", GINT_TO_POINTER (i)); + + g_signal_connect_object (config, "notify::color-model", + G_CALLBACK (newsprint_color_model_notify), + G_OBJECT (labels[i]), 0); + + newsprint_color_model_notify (config, NULL, labels[i]); + + gtk_container_set_border_width (GTK_CONTAINER (pages[i]), 6); + gtk_notebook_append_page (GTK_NOTEBOOK (np->notebook), + pages[i], labels[i]); + + widget = gimp_prop_widget_new_from_pspec (config, + param_specs[1 + 3 * i], + area, context, + create_picker_func, + create_controller_func, + creator, &unused); + gtk_box_pack_start (GTK_BOX (pages[i]), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + g_object_bind_property (G_OBJECT (widget), "visible", + G_OBJECT (pages[i]), "visible", + G_BINDING_SYNC_CREATE); + + if (i == 3) + remaining = 3; + else + remaining = 2; + + widget = _gimp_prop_gui_new_generic (config, + param_specs + 2 + 3 * i, remaining, + area, context, + create_picker_func, + create_controller_func, + creator); + gtk_box_pack_start (GTK_BOX (pages[i]), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + } + + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + gtk_widget_show (hbox); + + np->pattern_check = check = + gtk_check_button_new_with_label (_("Lock patterns")); + gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0); + gtk_widget_show (check); + + g_signal_connect (check, "toggled", + G_CALLBACK (newsprint_lock_patterns_toggled), + np); + + np->period_check = check = + gtk_check_button_new_with_label (_("Lock periods")); + gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0); + gtk_widget_show (check); + + g_signal_connect (check, "toggled", + G_CALLBACK (newsprint_lock_periods_toggled), + np); + + np->angle_check = check = + gtk_check_button_new_with_label (_("Lock angles")); + gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0); + gtk_widget_show (check); + + g_signal_connect (check, "toggled", + G_CALLBACK (newsprint_lock_angles_toggled), + np); + + frame = gimp_frame_new (_("Quality")); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + vbox = _gimp_prop_gui_new_generic (config, + param_specs + 14, 1, area, context, create_picker_func, create_controller_func, creator); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_widget_show (vbox); + + frame = gimp_frame_new (_("Effects")); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + vbox = _gimp_prop_gui_new_generic (config, + param_specs + 15, 3, + area, + context, + create_picker_func, + create_controller_func, + creator); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_widget_show (vbox); + + g_signal_connect (config, "notify", + G_CALLBACK (newsprint_model_prop_notify), + np); + + return main_vbox; +} + + +/* private functions */ + +static void +newsprint_color_model_notify (GObject *config, + const GParamSpec *pspec, + GtkWidget *label) +{ + ColorModel model; + gint channel; + + g_object_get (config, + "color-model", &model, + NULL); + + channel = + GPOINTER_TO_INT (g_object_get_data (G_OBJECT (label), "channel")); + + if (label_strings[model][channel]) + gtk_label_set_text (GTK_LABEL (label), + gettext (label_strings[model][channel])); +} + +static gboolean +newsprint_sync_model_props (Newsprint *np, + const GParamSpec *pspec, + const gchar **props, + gint n_props) +{ + gint i; + + for (i = 0; i < n_props; i++) + { + if (! strcmp (pspec->name, props[i])) + { + GValue value = G_VALUE_INIT; + gint j; + + g_value_init (&value, pspec->value_type); + + g_object_get_property (np->config, pspec->name, &value); + + for (j = 0; j < n_props; j++) + { + if (i != j) + { + g_signal_handlers_block_by_func (np->config, + newsprint_model_prop_notify, + np); + + g_object_set_property (np->config, props[j], &value); + + g_signal_handlers_unblock_by_func (np->config, + newsprint_model_prop_notify, + np); + } + } + + g_value_unset (&value); + + return TRUE; + } + } + + return FALSE; +} + +static void +newsprint_model_prop_notify (GObject *config, + const GParamSpec *pspec, + Newsprint *np) +{ + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (np->pattern_check)) && + newsprint_sync_model_props (np, pspec, + pattern_props, G_N_ELEMENTS (pattern_props))) + return; + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (np->period_check)) && + newsprint_sync_model_props (np, pspec, + period_props, G_N_ELEMENTS (period_props))) + return; + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (np->angle_check)) && + newsprint_sync_model_props (np, pspec, + angle_props, G_N_ELEMENTS (angle_props))) + return; +} + +static void +newsprint_lock_patterns_toggled (GtkWidget *widget, + Newsprint *np) + +{ + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) + { + GParamSpec *pspec; + gint channel; + + channel = gtk_notebook_get_current_page (GTK_NOTEBOOK (np->notebook)); + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (np->config), + pattern_props[channel]); + + newsprint_sync_model_props (np, pspec, + pattern_props, G_N_ELEMENTS (pattern_props)); + } +} + +static void +newsprint_lock_periods_toggled (GtkWidget *widget, + Newsprint *np) + +{ + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) + { + GParamSpec *pspec; + gint channel; + + channel = gtk_notebook_get_current_page (GTK_NOTEBOOK (np->notebook)); + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (np->config), + period_props[channel]); + + newsprint_sync_model_props (np, pspec, + period_props, G_N_ELEMENTS (period_props)); + } +} + +static void +newsprint_lock_angles_toggled (GtkWidget *widget, + Newsprint *np) + +{ + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) + { + GParamSpec *pspec; + gint channel; + + channel = gtk_notebook_get_current_page (GTK_NOTEBOOK (np->notebook)); + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (np->config), + angle_props[channel]); + + newsprint_sync_model_props (np, pspec, + angle_props, G_N_ELEMENTS (angle_props)); + } }