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