1/* GTK - The GIMP Toolkit
2 * Copyright (C) 1997 David Mosberger
3 *               2004 Roger Leigh
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
20
21/*
22 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23 * file for a list of people on the GTK+ Team.  See the ChangeLog
24 * files for a list of changes.  These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
26 */
27
28/*
29 * Incorporated into Gutenprint by Roger Leigh in 2004.  Subsequent
30 * changes are by the Gutenprint team.
31 */
32
33#include <config.h>
34#include <string.h>
35#include <stdlib.h>
36#include <stdio.h>
37
38#include <gtk/gtkdialog.h>
39#include <gtk/gtkdrawingarea.h>
40#include <gtk/gtkentry.h>
41#include <gtk/gtkhbox.h>
42#include <gtk/gtkimage.h>
43#include <gtk/gtklabel.h>
44#include <gtk/gtkmain.h>
45#include <gtk/gtkradiobutton.h>
46#include <gtk/gtkstock.h>
47#include <gtk/gtktable.h>
48#include <gtk/gtkvbox.h>
49#include <gtk/gtkwindow.h>
50
51#include <gutenprint/gutenprint-intl-internal.h>
52
53#include <gutenprintui2/curve.h>
54#include <gutenprintui2/gammacurve.h>
55
56static GtkVBoxClass *parent_class = NULL;
57
58
59/* forward declarations: */
60static void stpui_gamma_curve_class_init (StpuiGammaCurveClass *class);
61static void stpui_gamma_curve_init (StpuiGammaCurve *curve);
62static void stpui_gamma_curve_destroy (GtkObject *object);
63
64static void curve_type_changed_callback (GtkWidget *w, gpointer data);
65static void button_realize_callback     (GtkWidget *w);
66static void button_toggled_callback     (GtkWidget *w, gpointer data);
67static void button_clicked_callback     (GtkWidget *w, gpointer data);
68
69enum
70  {
71    LINEAR = 0,
72    SPLINE,
73    FREE,
74    GAMMA,
75    RESET,
76    NUM_XPMS
77  };
78
79static const char *xpm[][27] =
80  {
81    /* spline: */
82    {
83      /* width height ncolors chars_per_pixel */
84      "16 16 4 1",
85      /* colors */
86      ". c None",
87      "B c #000000",
88      "+ c #BC2D2D",
89      "r c #FF0000",
90      /* pixels */
91      "..............BB",
92      ".........rrrrrrB",
93      ".......rr.......",
94      ".....B+.........",
95      "....BBB.........",
96      "....+B..........",
97      "....r...........",
98      "...r............",
99      "...r............",
100      "..r.............",
101      "..r.............",
102      ".r..............",
103      ".r..............",
104      ".r..............",
105      "B+..............",
106      "BB.............."
107    },
108    /* linear: */
109    {
110      /* width height ncolors chars_per_pixel */
111      "16 16 5 1",
112      /* colors */
113      ". c None", /* transparent */
114      "B c #000000",
115      "' c #7F7F7F",
116      "+ c #824141",
117      "r c #FF0000",
118      /* pixels */
119      "..............BB",
120      "..............+B",
121      "..............r.",
122      ".............r..",
123      ".............r..",
124      "....'B'.....r...",
125      "....BBB.....r...",
126      "....+B+....r....",
127      "....r.r....r....",
128      "...r...r..r.....",
129      "...r...r..r.....",
130      "..r.....rB+.....",
131      "..r.....BBB.....",
132      ".r......'B'.....",
133      "B+..............",
134      "BB.............."
135    },
136    /* free: */
137    {
138      /* width height ncolors chars_per_pixel */
139      "16 16 2 1",
140      /* colors */
141      ". c None",
142      "r c #FF0000",
143      /* pixels */
144      "................",
145      "................",
146      "......r.........",
147      "......r.........",
148      ".......r........",
149      ".......r........",
150      ".......r........",
151      "........r.......",
152      "........r.......",
153      "........r.......",
154      ".....r...r.rrrrr",
155      "....r....r......",
156      "...r.....r......",
157      "..r.......r.....",
158      ".r........r.....",
159      "r..............."
160    },
161    /* gamma: */
162    {
163      /* width height ncolors chars_per_pixel */
164      "16 16 10 1",
165      /* colors */
166      ". c None",
167      "B c #000000",
168      "& c #171717",
169      "# c #2F2F2F",
170      "X c #464646",
171      "= c #5E5E5E",
172      "/ c #757575",
173      "+ c #8C8C8C",
174      "- c #A4A4A4",
175      "` c #BBBBBB",
176      /* pixels */
177      "................",
178      "................",
179      "................",
180      "....B=..+B+.....",
181      "....X&`./&-.....",
182      "...../+.XX......",
183      "......B.B+......",
184      "......X.X.......",
185      "......X&+.......",
186      "......-B........",
187      "....../=........",
188      "......#B........",
189      "......BB........",
190      "......B#........",
191      "................",
192      "................"
193    },
194    /* reset: */
195    {
196      /* width height ncolors chars_per_pixel */
197      "16 16 4 1",
198      /* colors */
199      ". c None",
200      "B c #000000",
201      "+ c #824141",
202      "r c #FF0000",
203      /* pixels */
204      "..............BB",
205      "..............+B",
206      ".............r..",
207      "............r...",
208      "...........r....",
209      "..........r.....",
210      ".........r......",
211      "........r.......",
212      ".......r........",
213      "......r.........",
214      ".....r..........",
215      "....r...........",
216      "...r............",
217      "..r.............",
218      "B+..............",
219      "BB.............."
220    }
221  };
222
223GType
224stpui_gamma_curve_get_type (void)
225{
226  static GType gamma_curve_type = 0;
227
228  if (!gamma_curve_type)
229    {
230      static const GTypeInfo gamma_curve_info =
231      {
232	sizeof (StpuiGammaCurveClass),
233	NULL,		/* base_init */
234	NULL,		/* base_finalize */
235	(GClassInitFunc) stpui_gamma_curve_class_init,
236	NULL,		/* class_finalize */
237	NULL,		/* class_data */
238	sizeof (StpuiGammaCurve),
239	0,		/* n_preallocs */
240	(GInstanceInitFunc) stpui_gamma_curve_init,
241      };
242
243      gamma_curve_type = g_type_register_static (GTK_TYPE_VBOX, "StpuiGammaCurve",
244						 &gamma_curve_info, 0);
245    }
246  return gamma_curve_type;
247}
248
249static void
250stpui_gamma_curve_class_init (StpuiGammaCurveClass *class)
251{
252  GtkObjectClass *object_class;
253
254  parent_class = g_type_class_peek_parent (class);
255
256  object_class = (GtkObjectClass *) class;
257  object_class->destroy = stpui_gamma_curve_destroy;
258}
259
260static void
261stpui_gamma_curve_init (StpuiGammaCurve *curve)
262{
263  GtkWidget *vbox;
264  int i;
265
266  curve->gamma = 1.0;
267
268  curve->table = gtk_table_new (1, 2, FALSE);
269  gtk_table_set_col_spacings (GTK_TABLE (curve->table), 3);
270  gtk_container_add (GTK_CONTAINER (curve), curve->table);
271
272  curve->curve = stpui_curve_new ();
273  g_signal_connect (curve->curve, "curve_type_changed",
274		    G_CALLBACK (curve_type_changed_callback), curve);
275  gtk_table_attach_defaults (GTK_TABLE (curve->table), curve->curve, 0, 1, 0, 1);
276
277  vbox = gtk_vbox_new (/* homogeneous */ FALSE, /* spacing */ 3);
278  gtk_table_attach (GTK_TABLE (curve->table), vbox, 1, 2, 0, 1, 0, 0, 0, 0);
279
280  /* toggle buttons: */
281  for (i = 0; i < 3; ++i)
282    {
283      curve->button[i] = gtk_toggle_button_new ();
284      g_object_set_data (G_OBJECT (curve->button[i]), "_StpuiGammaCurveIndex",
285			 GINT_TO_POINTER (i));
286      gtk_container_add (GTK_CONTAINER (vbox), curve->button[i]);
287      g_signal_connect (curve->button[i], "realize",
288			G_CALLBACK (button_realize_callback), NULL);
289      g_signal_connect (curve->button[i], "toggled",
290			G_CALLBACK (button_toggled_callback), curve);
291      gtk_widget_show (curve->button[i]);
292    }
293
294  /* push buttons: */
295  for (i = 3; i < 5; ++i)
296    {
297      curve->button[i] = gtk_button_new ();
298      g_object_set_data (G_OBJECT (curve->button[i]), "_StpuiGammaCurveIndex",
299			 GINT_TO_POINTER (i));
300      gtk_container_add (GTK_CONTAINER (vbox), curve->button[i]);
301      g_signal_connect (curve->button[i], "realize",
302			G_CALLBACK (button_realize_callback), NULL);
303      g_signal_connect (curve->button[i], "clicked",
304			G_CALLBACK (button_clicked_callback), curve);
305      gtk_widget_show (curve->button[i]);
306    }
307
308  gtk_widget_show (vbox);
309  gtk_widget_show (curve->table);
310  gtk_widget_show (curve->curve);
311}
312
313static void
314button_realize_callback (GtkWidget *w)
315{
316  GtkWidget *pixmap;
317  GdkBitmap *mask;
318  GdkPixmap *pm;
319  int i;
320
321  i = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (w), "_StpuiGammaCurveIndex"));
322  pm = gdk_pixmap_create_from_xpm_d (w->window, &mask,
323				     &w->style->bg[GTK_STATE_NORMAL], (gchar **)xpm[i]);
324
325  pixmap = gtk_image_new_from_pixmap (pm, mask);
326  gtk_container_add (GTK_CONTAINER (w), pixmap);
327  gtk_widget_show (pixmap);
328
329  g_object_unref (pm);
330  g_object_unref (mask);
331}
332
333static void
334button_toggled_callback (GtkWidget *w, gpointer data)
335{
336  StpuiGammaCurve *c = data;
337  StpuiCurveType type;
338  int active, i;
339
340  if (!GTK_TOGGLE_BUTTON (w)->active)
341    return;
342
343  active = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (w), "_StpuiGammaCurveIndex"));
344
345  for (i = 0; i < 3; ++i)
346    if ((i != active) && GTK_TOGGLE_BUTTON (c->button[i])->active)
347      break;
348
349  if (i < 3)
350    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (c->button[i]), FALSE);
351
352  switch (active)
353    {
354    case 0:  type = STPUI_CURVE_TYPE_SPLINE; break;
355    case 1:  type = STPUI_CURVE_TYPE_LINEAR; break;
356    default: type = STPUI_CURVE_TYPE_FREE; break;
357    }
358  stpui_curve_set_curve_type (STPUI_CURVE (c->curve), type);
359}
360
361static void
362gamma_cancel_callback (GtkWidget *w, gpointer data)
363{
364  StpuiGammaCurve *c = data;
365
366  gtk_widget_destroy (c->gamma_dialog);
367}
368
369static void
370gamma_ok_callback (GtkWidget *w, gpointer data)
371{
372  StpuiGammaCurve *c = data;
373  const gchar *start;
374  gchar *end;
375  gfloat v;
376
377  start = gtk_entry_get_text (GTK_ENTRY (c->gamma_text));
378  if (start)
379    {
380      v = g_strtod (start, &end);
381      if (end > start && v > 0.0)
382	c->gamma = v;
383    }
384  stpui_curve_set_gamma (STPUI_CURVE (c->curve), c->gamma);
385  gamma_cancel_callback (w, data);
386}
387
388static void
389button_clicked_callback (GtkWidget *w, gpointer data)
390{
391  StpuiGammaCurve *c = data;
392  int active;
393
394  active = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (w), "_StpuiGammaCurveIndex"));
395  if (active == 3)
396    {
397      /* set gamma */
398      if (c->gamma_dialog)
399	return;
400      else
401	{
402	  GtkWidget *vbox, *hbox, *label, *button;
403	  gchar buf[64];
404
405	  c->gamma_dialog = gtk_dialog_new ();
406	  gtk_window_set_screen (GTK_WINDOW (c->gamma_dialog),
407				 gtk_widget_get_screen (w));
408	  gtk_window_set_title (GTK_WINDOW (c->gamma_dialog), _("Gamma"));
409	  g_object_add_weak_pointer (G_OBJECT (c->gamma_dialog),
410				     (gpointer *)&c->gamma_dialog);
411
412	  vbox = GTK_DIALOG (c->gamma_dialog)->vbox;
413
414	  hbox = gtk_hbox_new (/* homogeneous */ FALSE, 0);
415	  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 2);
416	  gtk_widget_show (hbox);
417
418	  label = gtk_label_new_with_mnemonic (_("_Gamma value"));
419	  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
420	  gtk_widget_show (label);
421
422	  sprintf (buf, "%g", c->gamma);
423	  c->gamma_text = gtk_entry_new ();
424          gtk_label_set_mnemonic_widget (GTK_LABEL (label), c->gamma_text);
425	  gtk_entry_set_text (GTK_ENTRY (c->gamma_text), buf);
426	  gtk_box_pack_start (GTK_BOX (hbox), c->gamma_text, TRUE, TRUE, 2);
427	  gtk_widget_show (c->gamma_text);
428
429	  /* fill in action area: */
430	  hbox = GTK_DIALOG (c->gamma_dialog)->action_area;
431
432          button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
433	  g_signal_connect (button, "clicked",
434			    G_CALLBACK (gamma_cancel_callback), c);
435	  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
436	  gtk_widget_show (button);
437
438          button = gtk_button_new_from_stock (GTK_STOCK_OK);
439	  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
440	  g_signal_connect (button, "clicked",
441			    G_CALLBACK (gamma_ok_callback), c);
442	  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
443	  gtk_widget_grab_default (button);
444	  gtk_widget_show (button);
445
446	  gtk_widget_show (c->gamma_dialog);
447	}
448    }
449  else
450    {
451      /* reset */
452      stpui_curve_reset (STPUI_CURVE (c->curve));
453    }
454}
455
456static void
457curve_type_changed_callback (GtkWidget *w, gpointer data)
458{
459  StpuiGammaCurve *c = data;
460  StpuiCurveType new_type;
461  int active;
462
463  new_type = STPUI_CURVE (w)->curve_type;
464  switch (new_type)
465    {
466    case STPUI_CURVE_TYPE_SPLINE: active = 0; break;
467    case STPUI_CURVE_TYPE_LINEAR: active = 1; break;
468    default:		          active = 2; break;
469    }
470  if (!GTK_TOGGLE_BUTTON (c->button[active])->active)
471    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (c->button[active]), TRUE);
472}
473
474GtkWidget*
475stpui_gamma_curve_new (void)
476{
477  return g_object_new (STPUI_TYPE_GAMMA_CURVE, NULL);
478}
479
480static void
481stpui_gamma_curve_destroy (GtkObject *object)
482{
483  StpuiGammaCurve *c;
484
485  g_return_if_fail (STPUI_IS_GAMMA_CURVE (object));
486
487  c = STPUI_GAMMA_CURVE (object);
488
489  if (c->gamma_dialog)
490    gtk_widget_destroy (c->gamma_dialog);
491
492  if (GTK_OBJECT_CLASS (parent_class)->destroy)
493    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
494}
495
496