/* LIBGIMP - The GIMP Library * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball * * gimpgradientmenu.c * Copyright (C) 1998 Andy Thomas * * 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 2 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, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "config.h" #ifdef __GNUC__ #warning GTK_DISABLE_DEPRECATED #endif #undef GTK_DISABLE_DEPRECATED #include "gimp.h" #include "gimpui.h" #include "libgimp-intl.h" #define GRADIENT_SELECT_DATA_KEY "gimp-grdient-select-data" #define CELL_HEIGHT 18 #define CELL_WIDTH 84 typedef struct _GradientSelect GradientSelect; struct _GradientSelect { gchar *title; GimpRunGradientCallback callback; gpointer data; GtkWidget *preview; GtkWidget *button; gchar *gradient_name; /* Local copy */ gint sample_size; gboolean reverse; const gchar *temp_gradient_callback; }; /* local function prototypes */ static void gimp_gradient_select_widget_callback (const gchar *name, gint width, const gdouble *grad_data, gint closing, gpointer data); static void gimp_gradient_select_widget_clicked (GtkWidget *widget, GradientSelect *gradient_sel); static void gimp_gradient_select_widget_destroy (GtkWidget *widget, GradientSelect *gradient_sel); static void gimp_gradient_select_preview_update (GtkWidget *preview, gint width, const gdouble *grad_data); /** * gimp_gradient_select_widget_new: * @title: Title of the dialog to use or %NULL to use the default title. * @gradient_name: Initial gradient name or %NULL to use current selection. * @callback: A function to call when the selected gradient changes. * @data: A pointer to arbitary data to be used in the call to * @callback. * * Creates a new #GtkWidget that completely controls the selection of * a gradient. This widget is suitable for placement in a table in a * plug-in dialog. * * Returns: A #GtkWidget that you can use in your UI. */ GtkWidget * gimp_gradient_select_widget_new (const gchar *title, const gchar *gradient_name, GimpRunGradientCallback callback, gpointer data) { GradientSelect *gradient_sel; gint width; gdouble *grad_data; g_return_val_if_fail (callback != NULL, NULL); if (! title) title = _("Gradient Selection"); gradient_sel = g_new0 (GradientSelect, 1); gradient_sel->title = g_strdup (title); gradient_sel->callback = callback; gradient_sel->data = data; gradient_sel->sample_size = CELL_WIDTH; gradient_sel->reverse = FALSE; gradient_sel->button = gtk_button_new (); g_signal_connect (gradient_sel->button, "clicked", G_CALLBACK (gimp_gradient_select_widget_clicked), gradient_sel); g_signal_connect (gradient_sel->button, "destroy", G_CALLBACK (gimp_gradient_select_widget_destroy), gradient_sel); gradient_sel->preview = gtk_preview_new (GTK_PREVIEW_COLOR); gtk_preview_size (GTK_PREVIEW (gradient_sel->preview), CELL_WIDTH, CELL_HEIGHT); gtk_container_add (GTK_CONTAINER (gradient_sel->button), gradient_sel->preview); gtk_widget_show (gradient_sel->preview); /* Do initial gradient setup */ gradient_sel->gradient_name = gimp_gradients_get_gradient_data (gradient_name, gradient_sel->sample_size, gradient_sel->reverse, &width, &grad_data); if (gradient_sel->gradient_name) { gimp_gradient_select_preview_update (gradient_sel->preview, width, grad_data); g_free (grad_data); } g_object_set_data (G_OBJECT (gradient_sel->button), GRADIENT_SELECT_DATA_KEY, gradient_sel); return gradient_sel->button; } /** * gimp_gradient_select_widget_close; * @widget: A gradient select widget. * * Closes the popup window associated with @widget. */ void gimp_gradient_select_widget_close (GtkWidget *widget) { GradientSelect *gradient_sel; gradient_sel = g_object_get_data (G_OBJECT (widget), GRADIENT_SELECT_DATA_KEY); g_return_if_fail (gradient_sel != NULL); if (gradient_sel->temp_gradient_callback) { gimp_gradient_select_destroy (gradient_sel->temp_gradient_callback); gradient_sel->temp_gradient_callback = NULL; } } /** * gimp_gradient_select_widget_set: * @widget: A gradient select widget. * @gradient_name: Gradient name to set. * * Sets the current gradient for the gradient select widget. Calls * the callback function if one was supplied in the call to * gimp_gradient_select_widget_new(). */ void gimp_gradient_select_widget_set (GtkWidget *widget, const gchar *gradient_name) { GradientSelect *gradient_sel; gradient_sel = g_object_get_data (G_OBJECT (widget), GRADIENT_SELECT_DATA_KEY); g_return_if_fail (gradient_sel != NULL); if (gradient_sel->temp_gradient_callback) { gimp_gradients_set_popup (gradient_sel->temp_gradient_callback, gradient_name); } else { gchar *name; gint width; gdouble *grad_data; name = gimp_gradients_get_gradient_data (gradient_name, gradient_sel->sample_size, gradient_sel->reverse, &width, &grad_data); if (name) { gimp_gradient_select_widget_callback (name, width, grad_data, FALSE, gradient_sel); g_free (name); g_free (grad_data); } } } /* private functions */ static void gimp_gradient_select_widget_callback (const gchar *name, gint width, const gdouble *grad_data, gint closing, gpointer data) { GradientSelect *gradient_sel = (GradientSelect *) data; g_free (gradient_sel->gradient_name); gradient_sel->gradient_name = g_strdup (name); gimp_gradient_select_preview_update (gradient_sel->preview, width, grad_data); if (gradient_sel->callback) gradient_sel->callback (name, width, grad_data, closing, gradient_sel->data); if (closing) gradient_sel->temp_gradient_callback = NULL; } static void gimp_gradient_select_widget_clicked (GtkWidget *widget, GradientSelect *gradient_sel) { if (gradient_sel->temp_gradient_callback) { /* calling gimp_gradients_set_popup() raises the dialog */ gimp_gradients_set_popup (gradient_sel->temp_gradient_callback, gradient_sel->gradient_name); } else { gradient_sel->temp_gradient_callback = gimp_gradient_select_new (gradient_sel->title, gradient_sel->gradient_name, gradient_sel->sample_size, gimp_gradient_select_widget_callback, gradient_sel); } } static void gimp_gradient_select_widget_destroy (GtkWidget *widget, GradientSelect *gradient_sel) { if (gradient_sel->temp_gradient_callback) { gimp_gradient_select_destroy (gradient_sel->temp_gradient_callback); gradient_sel->temp_gradient_callback = NULL; } g_free (gradient_sel->title); g_free (gradient_sel->gradient_name); g_free (gradient_sel); } static void gimp_gradient_select_preview_update (GtkWidget *preview, gint width, const gdouble *grad_data) { const gdouble *src; gdouble r, g, b, a; gdouble c0, c1; guchar *p0; guchar *p1; guchar *even; guchar *odd; gint x, y; width /= 4; width = MIN (width, CELL_WIDTH); /* Draw the gradient */ src = grad_data; p0 = even = g_malloc (width * 3); p1 = odd = g_malloc (width * 3); for (x = 0; x < width; x++) { r = src[x * 4 + 0]; g = src[x * 4 + 1]; b = src[x * 4 + 2]; a = src[x * 4 + 3]; if ((x / GIMP_CHECK_SIZE_SM) & 1) { c0 = GIMP_CHECK_LIGHT; c1 = GIMP_CHECK_DARK; } else { c0 = GIMP_CHECK_DARK; c1 = GIMP_CHECK_LIGHT; } *p0++ = (c0 + (r - c0) * a) * 255.0; *p0++ = (c0 + (g - c0) * a) * 255.0; *p0++ = (c0 + (b - c0) * a) * 255.0; *p1++ = (c1 + (r - c1) * a) * 255.0; *p1++ = (c1 + (g - c1) * a) * 255.0; *p1++ = (c1 + (b - c1) * a) * 255.0; } for (y = 0; y < CELL_HEIGHT; y++) { if ((y / GIMP_CHECK_SIZE_SM) & 1) gtk_preview_draw_row (GTK_PREVIEW (preview), odd, 0, y, width); else gtk_preview_draw_row (GTK_PREVIEW (preview), even, 0, y, width); } g_free (even); g_free (odd); gtk_widget_queue_draw (preview); }