]> Pileus Git - ~andy/gtk/blob - gtk/gtkcolorsel.c
6e76fd780887f7c590f40392d641e4b79716b0c5
[~andy/gtk] / gtk / gtkcolorsel.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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 #include <math.h>
20 #include "gtkcolorsel.h"
21 #include "gtkhbbox.h"
22
23 /*
24  * If you change the way the color values are stored,
25  * please make sure to update the drag & drop support so it sends
26  * across all the color info (currently RGBA). - Elliot
27  */
28
29 #ifndef M_PI
30 #define M_PI    3.14159265358979323846
31 #endif /* M_PI */
32
33 #define DEGTORAD(a) (2.0*M_PI*a/360.0)
34 #define SQR(a) (a*a)
35
36 #define TIMER_DELAY 300
37
38 #define CIRCLE_RADIUS 65
39
40 #define WHEEL_WIDTH   2*CIRCLE_RADIUS+2
41 #define WHEEL_HEIGHT  2*CIRCLE_RADIUS+2
42
43 #define VALUE_WIDTH   32
44 #define VALUE_HEIGHT  WHEEL_HEIGHT
45
46 #define SAMPLE_WIDTH  WHEEL_WIDTH+VALUE_WIDTH+5
47 #define SAMPLE_HEIGHT 28
48
49 static void gtk_color_selection_class_init (GtkColorSelectionClass *klass);
50 static void gtk_color_selection_init (GtkColorSelection *colorsel);
51 static void gtk_color_selection_dialog_class_init(GtkColorSelectionDialogClass *klass);
52 static void gtk_color_selection_dialog_init(GtkColorSelectionDialog *colorseldiag);
53
54 enum
55 {
56   COLOR_CHANGED,
57   LAST_SIGNAL
58 };
59
60 enum
61 {
62   RGB_INPUTS     = 1 << 0,
63   HSV_INPUTS     = 1 << 1,
64   OPACITY_INPUTS = 1 << 2
65 };
66
67 enum
68 {
69   SCALE,
70   ENTRY,
71   BOTH
72 };
73
74 enum
75 {
76   HUE,
77   SATURATION,
78   VALUE,
79   RED,
80   GREEN,
81   BLUE,
82   OPACITY,
83   NUM_CHANNELS
84 };
85
86 typedef struct
87 {
88   gchar *label;
89   gfloat lower, upper, step_inc, page_inc;
90   GtkSignalFunc updater;
91 } scale_val_type;
92
93
94 #define HSV_TO_RGB()  gtk_color_selection_hsv_to_rgb( \
95                         colorsel->values[HUE], \
96                         colorsel->values[SATURATION], \
97                         colorsel->values[VALUE], \
98                         &colorsel->values[RED], \
99                         &colorsel->values[GREEN], \
100                         &colorsel->values[BLUE])
101
102 #define RGB_TO_HSV()  gtk_color_selection_rgb_to_hsv( \
103                         colorsel->values[RED], \
104                         colorsel->values[GREEN], \
105                         colorsel->values[BLUE], \
106                         &colorsel->values[HUE], \
107                         &colorsel->values[SATURATION], \
108                         &colorsel->values[VALUE])
109
110
111 static void gtk_color_selection_hsv_updater       (GtkWidget         *widget,
112                                                    gpointer           data);
113 static void gtk_color_selection_rgb_updater       (GtkWidget         *widget,
114                                                    gpointer           data);
115 static void gtk_color_selection_opacity_updater   (GtkWidget         *widget,
116                                                    gpointer           data);
117 static void gtk_color_selection_realize           (GtkWidget         *widget);
118 static void gtk_color_selection_unrealize         (GtkWidget         *widget);
119 static void gtk_color_selection_finalize          (GtkObject         *object);
120 static void gtk_color_selection_color_changed     (GtkColorSelection *colorsel);
121 static void gtk_color_selection_update_input      (GtkWidget         *scale,
122                                                    GtkWidget         *entry,
123                                                    gdouble            value);
124 static void gtk_color_selection_update_inputs     (GtkColorSelection *colorsel,
125                                                    gint               inputs,
126                                                    gint               which);
127 static void gtk_color_selection_update_value      (GtkColorSelection *colorsel,
128                                                    gint               y);
129 static void gtk_color_selection_update_wheel      (GtkColorSelection *colorsel,
130                                                    gint               x,
131                                                    gint               y);
132 static void gtk_color_selection_value_resize      (GtkWidget          *widget,
133                                                    gpointer            data);
134 static gint gtk_color_selection_value_events      (GtkWidget          *area,
135                                                    GdkEvent           *event);
136 static gint gtk_color_selection_value_timeout     (GtkColorSelection  *colorsel);
137 static void gtk_color_selection_wheel_resize      (GtkWidget          *widget,
138                                                    gpointer            data);
139 static gint gtk_color_selection_wheel_events      (GtkWidget          *area,
140                                                    GdkEvent           *event);
141 static gint gtk_color_selection_wheel_timeout     (GtkColorSelection  *colorsel);
142 static void gtk_color_selection_sample_resize     (GtkWidget          *widget,
143                                                    gpointer            data);
144 static void gtk_color_selection_drop_handle       (GtkWidget          *widget,
145                                                    GdkEvent           *event,
146                                                    GtkWidget          *theclorsel);
147 static void gtk_color_selection_drag_handle       (GtkWidget          *widget,
148                                                    GdkEvent           *event,
149                                                    GtkWidget          *thecolorsel);
150 static void gtk_color_selection_draw_wheel_marker (GtkColorSelection  *colorsel);
151 static void gtk_color_selection_draw_wheel_frame  (GtkColorSelection  *colorsel);
152 static void gtk_color_selection_draw_value_marker (GtkColorSelection  *colorsel);
153 static void gtk_color_selection_draw_value_bar    (GtkColorSelection  *colorsel,
154                                                    gint                resize);
155 static void gtk_color_selection_draw_wheel        (GtkColorSelection  *colorsel,
156                                                    gint                resize);
157 static void gtk_color_selection_draw_sample       (GtkColorSelection  *colorsel,
158                                                    gint                resize);
159
160 static gint gtk_color_selection_eval_wheel        (gint     x, gint     y,
161                                                    gdouble cx, gdouble cy,
162                                                    gdouble *h, gdouble *s);
163
164 static void gtk_color_selection_hsv_to_rgb        (gdouble  h, gdouble  s, gdouble  v,
165                                                    gdouble *r, gdouble *g, gdouble *b);
166 static void gtk_color_selection_rgb_to_hsv        (gdouble  r, gdouble  g, gdouble  b,
167                                                    gdouble *h, gdouble *s, gdouble *v);
168
169
170 static GtkVBoxClass *color_selection_parent_class = NULL;
171 static GtkWindowClass *color_selection_dialog_parent_class = NULL;
172
173
174 static guint color_selection_signals[LAST_SIGNAL] = {0};
175
176 static const gchar      *value_index_key = "gtk-value-index";
177
178
179 #define SF GtkSignalFunc
180
181
182 scale_val_type scale_vals[NUM_CHANNELS] =
183 {
184   {"Hue:",        0.0, 360.0, 1.00, 10.00, (SF) gtk_color_selection_hsv_updater},
185   {"Saturation:", 0.0,   1.0, 0.01,  0.01, (SF) gtk_color_selection_hsv_updater},
186   {"Value:",      0.0,   1.0, 0.01,  0.01, (SF) gtk_color_selection_hsv_updater},
187   {"Red:",        0.0,   1.0, 0.01,  0.01, (SF) gtk_color_selection_rgb_updater},
188   {"Green:",      0.0,   1.0, 0.01,  0.01, (SF) gtk_color_selection_rgb_updater},
189   {"Blue:",       0.0,   1.0, 0.01,  0.01, (SF) gtk_color_selection_rgb_updater},
190   {"Opacity:",    0.0,   1.0, 0.01,  0.01, (SF) gtk_color_selection_opacity_updater}
191 };
192
193 guint
194 gtk_color_selection_get_type (void)
195 {
196   static guint color_selection_type = 0;
197
198   if (!color_selection_type)
199     {
200       GtkTypeInfo colorsel_info =
201       {
202         "GtkColorSelection",
203         sizeof (GtkColorSelection),
204         sizeof (GtkColorSelectionClass),
205         (GtkClassInitFunc) gtk_color_selection_class_init,
206         (GtkObjectInitFunc) gtk_color_selection_init,
207         (GtkArgSetFunc) NULL,
208         (GtkArgGetFunc) NULL,
209       };
210
211       color_selection_type = gtk_type_unique (gtk_vbox_get_type (), &colorsel_info);
212     }
213
214   return color_selection_type;
215 }
216
217 static void
218 gtk_color_selection_class_init (GtkColorSelectionClass *klass)
219 {
220   GtkObjectClass *object_class;
221   GtkWidgetClass *widget_class;
222   GtkContainerClass *container_class;
223
224   object_class = (GtkObjectClass*) klass;
225   widget_class = (GtkWidgetClass*) klass;
226   container_class = (GtkContainerClass*) klass;
227
228   color_selection_parent_class = gtk_type_class (gtk_vbox_get_type ());
229
230   color_selection_signals[COLOR_CHANGED] =
231      gtk_signal_new ("color_changed",
232                      GTK_RUN_FIRST,
233                      object_class->type,
234                      GTK_SIGNAL_OFFSET (GtkColorSelectionClass, color_changed),
235                      gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
236
237   gtk_object_class_add_signals (object_class, color_selection_signals, LAST_SIGNAL);
238
239   object_class->finalize = gtk_color_selection_finalize;
240
241   widget_class->realize = gtk_color_selection_realize;
242   widget_class->unrealize = gtk_color_selection_unrealize;
243 }
244
245 static void
246 gtk_color_selection_init (GtkColorSelection *colorsel)
247 {
248   GtkWidget *frame, *hbox, *vbox, *hbox2, *label, *table;
249   GtkObject *adj;
250   gint old_mask, n;
251   gchar txt[32];
252
253   for (n = RED; n <= OPACITY; n++)
254     colorsel->values[n] = 1.0;
255
256   RGB_TO_HSV ();
257
258   for (n = HUE; n <= OPACITY; n++)
259     colorsel->old_values[n] = colorsel->values[n];
260
261   colorsel->wheel_gc = NULL;
262   colorsel->value_gc = NULL;
263   colorsel->sample_gc = NULL;
264   colorsel->wheel_buf = NULL;
265   colorsel->value_buf = NULL;
266   colorsel->sample_buf = NULL;
267
268   colorsel->use_opacity = FALSE;
269   colorsel->timer_active = FALSE;
270   colorsel->policy = GTK_UPDATE_CONTINUOUS;
271
272   hbox = gtk_hbox_new (FALSE, 5);
273   gtk_container_border_width (GTK_CONTAINER (hbox), 5);
274   gtk_container_add (GTK_CONTAINER (colorsel), hbox);
275
276   vbox = gtk_vbox_new (FALSE, 5);
277   gtk_container_add (GTK_CONTAINER (hbox), vbox);
278   gtk_widget_show (vbox);
279
280   hbox2 = gtk_hbox_new (FALSE, 5);
281   gtk_container_add (GTK_CONTAINER (vbox), hbox2);
282   gtk_widget_show (hbox2);
283
284   colorsel->wheel_area = gtk_preview_new (GTK_PREVIEW_COLOR);
285   old_mask = gtk_widget_get_events(colorsel->wheel_area);
286   gtk_widget_set_events (colorsel->wheel_area,
287                          old_mask |
288                          GDK_BUTTON_PRESS_MASK |
289                          GDK_BUTTON_RELEASE_MASK |
290                          GDK_BUTTON_MOTION_MASK |
291                          GDK_POINTER_MOTION_HINT_MASK);
292   gtk_preview_size (GTK_PREVIEW (colorsel->wheel_area), WHEEL_WIDTH, WHEEL_HEIGHT);
293   gtk_preview_set_expand (GTK_PREVIEW (colorsel->wheel_area), TRUE);
294   gtk_container_add (GTK_CONTAINER (hbox2), colorsel->wheel_area);
295   gtk_widget_show (colorsel->wheel_area);
296
297   old_mask = gtk_widget_get_events (colorsel->wheel_area);
298
299   gtk_signal_connect (GTK_OBJECT (colorsel->wheel_area), "event",
300     (SF) gtk_color_selection_wheel_events, (gpointer) colorsel->wheel_area);
301   gtk_signal_connect_after (GTK_OBJECT (colorsel->wheel_area), "expose_event",
302     (SF) gtk_color_selection_wheel_events, (gpointer) colorsel->wheel_area);
303   gtk_signal_connect_after (GTK_OBJECT (colorsel->wheel_area), "size_allocate",
304     (SF) gtk_color_selection_wheel_resize, (gpointer) colorsel->wheel_area);
305   gtk_object_set_data (GTK_OBJECT (colorsel->wheel_area), "_GtkColorSelection", (gpointer) colorsel);
306
307   frame = gtk_frame_new (NULL);
308   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
309   gtk_container_border_width (GTK_CONTAINER (frame), 0);
310   gtk_box_pack_start (GTK_BOX (hbox2), frame, FALSE, TRUE, 0);
311   gtk_widget_show (frame);
312
313   colorsel->value_area = gtk_preview_new (GTK_PREVIEW_COLOR);
314   gtk_preview_size (GTK_PREVIEW (colorsel->value_area), VALUE_WIDTH, VALUE_HEIGHT);
315   gtk_preview_set_expand (GTK_PREVIEW (colorsel->value_area), TRUE);
316   gtk_container_add (GTK_CONTAINER (frame), colorsel->value_area);
317   gtk_widget_show (colorsel->value_area);
318
319   old_mask = gtk_widget_get_events (colorsel->value_area);
320   gtk_widget_set_events (colorsel->value_area,
321                          old_mask |
322                          GDK_BUTTON_PRESS_MASK |
323                          GDK_BUTTON_RELEASE_MASK |
324                          GDK_BUTTON_MOTION_MASK |
325                          GDK_POINTER_MOTION_HINT_MASK);
326
327   gtk_signal_connect_after (GTK_OBJECT (colorsel->value_area), "expose_event",
328     (SF) gtk_color_selection_value_events, (gpointer) colorsel->value_area);
329   gtk_signal_connect_after (GTK_OBJECT (colorsel->value_area), "size_allocate",
330     (SF) gtk_color_selection_value_resize, (gpointer) colorsel->value_area);
331   gtk_signal_connect (GTK_OBJECT (colorsel->value_area), "event",
332     (SF) gtk_color_selection_value_events, (gpointer) colorsel->value_area);
333   gtk_object_set_data (GTK_OBJECT (colorsel->value_area), "_GtkColorSelection", (gpointer) colorsel);
334
335   /* New/old color samples */
336   /* ===================== */
337
338   frame = gtk_frame_new (NULL);
339   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
340   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
341   gtk_widget_show (frame);
342
343 /*  colorsel->sample_area_eb = gtk_button_new ();
344   gtk_container_add (GTK_CONTAINER (frame), colorsel->sample_area_eb);
345   gtk_widget_show (colorsel->sample_area_eb); */
346
347   colorsel->sample_area = gtk_preview_new (GTK_PREVIEW_COLOR);
348   gtk_preview_size (GTK_PREVIEW (colorsel->sample_area), SAMPLE_WIDTH, SAMPLE_HEIGHT);
349   gtk_preview_set_expand (GTK_PREVIEW (colorsel->sample_area), TRUE);
350   gtk_container_add (GTK_CONTAINER (frame),
351                      colorsel->sample_area);
352   gtk_widget_set_events(colorsel->sample_area,
353                 gtk_widget_get_events(colorsel->sample_area)
354                 | GDK_BUTTON_MOTION_MASK
355                 | GDK_BUTTON_PRESS_MASK
356                 | GDK_BUTTON_RELEASE_MASK
357                 | GDK_ENTER_NOTIFY_MASK
358                 | GDK_LEAVE_NOTIFY_MASK);
359   gtk_widget_show (colorsel->sample_area);
360
361   gtk_signal_connect_after (GTK_OBJECT (colorsel->sample_area),
362                             "size_allocate",
363                             GTK_SIGNAL_FUNC (gtk_color_selection_sample_resize),
364                             colorsel->sample_area);
365   gtk_object_set_data (GTK_OBJECT (colorsel->sample_area), "_GtkColorSelection", (gpointer) colorsel);
366
367   table = gtk_table_new (NUM_CHANNELS, 3, FALSE);
368   gtk_table_set_col_spacings (GTK_TABLE (table), 3);
369   gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, TRUE, 0);
370
371   for (n = HUE; n <= OPACITY; n++)
372     {
373       label = gtk_label_new (scale_vals[n].label);
374       gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
375       gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, n, n + 1);
376
377       adj = gtk_adjustment_new (colorsel->values[n], scale_vals[n].lower,
378                                 scale_vals[n].upper, scale_vals[n].step_inc,
379                                 scale_vals[n].page_inc, 0.0);
380       colorsel->scales[n] = gtk_hscale_new (GTK_ADJUSTMENT (adj));
381       gtk_widget_set_usize (colorsel->scales[n], 128, 0);
382       gtk_scale_set_value_pos (GTK_SCALE (colorsel->scales[n]), GTK_POS_TOP);
383
384       gtk_range_set_update_policy (GTK_RANGE (colorsel->scales[n]), colorsel->policy);
385       gtk_scale_set_draw_value (GTK_SCALE (colorsel->scales[n]), FALSE);
386       gtk_scale_set_digits (GTK_SCALE (colorsel->scales[n]), 2);
387       gtk_table_attach_defaults (GTK_TABLE (table), colorsel->scales[n], 1, 2, n, n + 1);
388
389       colorsel->entries[n] = gtk_entry_new ();
390       gtk_widget_set_usize (colorsel->entries[n], 40, 0);
391       sprintf (txt, "%.2f", colorsel->values[n]);
392       gtk_entry_set_text (GTK_ENTRY (colorsel->entries[n]), txt);
393       gtk_table_attach_defaults (GTK_TABLE (table), colorsel->entries[n], 2, 3, n, n + 1);
394
395       if (n != OPACITY)
396         {
397           gtk_widget_show (label);
398           gtk_widget_show (colorsel->scales[n]);
399           gtk_widget_show (colorsel->entries[n]);
400         }
401
402       gtk_signal_connect_object (GTK_OBJECT (adj), "value_changed",
403                                  scale_vals[n].updater, (gpointer) colorsel->scales[n]);
404       gtk_object_set_data (GTK_OBJECT (colorsel->scales[n]), "_GtkColorSelection", (gpointer) colorsel);
405       gtk_object_set_data (GTK_OBJECT (colorsel->scales[n]), value_index_key, (gpointer) n);
406       gtk_signal_connect_object (GTK_OBJECT (colorsel->entries[n]), "changed",
407                                  scale_vals[n].updater, (gpointer) colorsel->entries[n]);
408       gtk_object_set_data (GTK_OBJECT (colorsel->entries[n]), "_GtkColorSelection", (gpointer) colorsel);
409       gtk_object_set_data (GTK_OBJECT (colorsel->entries[n]), value_index_key, (gpointer) n);
410     }
411
412   colorsel->opacity_label = label;
413
414   gtk_widget_show (table);
415   gtk_widget_show (hbox);
416 }
417
418 GtkWidget *
419 gtk_color_selection_new (void)
420 {
421   GtkColorSelection *colorsel;
422
423   colorsel = gtk_type_new (gtk_color_selection_get_type ());
424
425   return GTK_WIDGET (colorsel);
426 }
427
428 void
429 gtk_color_selection_set_update_policy (GtkColorSelection *colorsel,
430                                        GtkUpdateType      policy)
431 {
432   gint n;
433
434   g_return_if_fail (colorsel != NULL);
435
436   if (policy != colorsel->policy)
437     {
438       colorsel->policy = policy;
439
440       for (n = 0; n < NUM_CHANNELS; n++)
441         gtk_range_set_update_policy (GTK_RANGE (colorsel->scales[n]), policy);
442     }
443 }
444
445
446 void
447 gtk_color_selection_set_color (GtkColorSelection *colorsel,
448                                gdouble           *color)
449 {
450   gint n, i = 0;
451
452   g_return_if_fail (colorsel != NULL);
453   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
454
455   if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (colorsel)))
456     gtk_color_selection_draw_wheel_marker (colorsel);
457
458   for (n = RED; n <= BLUE; n++)
459     {
460       colorsel->old_values[n] = colorsel->values[n];
461       colorsel->values[n] = color[i++];
462     }
463
464   if (colorsel->use_opacity == TRUE)
465     {
466       colorsel->old_values[OPACITY] = colorsel->values[OPACITY];
467       colorsel->values[OPACITY] = color[i];
468     }
469
470   RGB_TO_HSV ();
471
472   gtk_color_selection_update_inputs (colorsel, RGB_INPUTS | HSV_INPUTS | OPACITY_INPUTS, BOTH);
473
474   if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (colorsel)))
475     {
476       gtk_color_selection_draw_value_bar (colorsel, FALSE);
477       gtk_color_selection_draw_sample (colorsel, FALSE);
478       gtk_color_selection_draw_wheel_marker (colorsel);
479     }
480 }
481
482 void
483 gtk_color_selection_get_color (GtkColorSelection *colorsel,
484                                gdouble           *color)
485 {
486   gint n, i = 0;
487
488   g_return_if_fail (colorsel != NULL);
489   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
490
491   for (n = RED; n <= BLUE; n++)
492     color[i++] = colorsel->values[n];
493   if (colorsel->use_opacity == TRUE)
494     color[i] = colorsel->values[OPACITY];
495 }
496
497 static void
498 gtk_color_selection_realize (GtkWidget         *widget)
499 {
500   GtkColorSelection *colorsel;
501   gchar *type_accept_list[] = {"application/x-color"};
502
503   g_return_if_fail (widget != NULL);
504   g_return_if_fail (GTK_IS_COLOR_SELECTION (widget));
505
506   colorsel = GTK_COLOR_SELECTION (widget);
507
508   if (GTK_WIDGET_CLASS (color_selection_parent_class)->realize)
509     (*GTK_WIDGET_CLASS (color_selection_parent_class)->realize) (widget);
510
511   gtk_widget_dnd_drag_set (colorsel->sample_area,
512                            1, type_accept_list, 1);
513   gtk_widget_dnd_drop_set (colorsel->sample_area,
514                            1, type_accept_list, 1, 0);
515   gtk_signal_connect_after (GTK_OBJECT (colorsel->sample_area),
516                             "drop_data_available_event",
517                             GTK_SIGNAL_FUNC (gtk_color_selection_drop_handle),
518                             colorsel);
519   gtk_signal_connect_after (GTK_OBJECT (colorsel->sample_area),
520                             "drag_request_event",
521                             GTK_SIGNAL_FUNC (gtk_color_selection_drag_handle),
522                             colorsel);
523 }
524
525 static void
526 gtk_color_selection_unrealize (GtkWidget      *widget)
527 {
528   GtkColorSelection *colorsel;
529
530   g_return_if_fail (widget != NULL);
531   g_return_if_fail (GTK_IS_COLOR_SELECTION (widget));
532
533   colorsel = GTK_COLOR_SELECTION (widget);
534
535   if (colorsel->value_gc != NULL)
536     {
537       gdk_gc_unref (colorsel->value_gc);
538       colorsel->value_gc = NULL;
539     }
540   if (colorsel->wheel_gc != NULL)
541     {
542       gdk_gc_unref (colorsel->wheel_gc);
543       colorsel->wheel_gc = NULL;
544     }
545   if (colorsel->sample_gc != NULL)
546     {
547       gdk_gc_unref (colorsel->sample_gc);
548       colorsel->sample_gc = NULL;
549     }
550
551   (* GTK_WIDGET_CLASS (color_selection_parent_class)->unrealize) (widget);
552 }
553
554 static void
555 gtk_color_selection_finalize (GtkObject *object)
556 {
557   GtkColorSelection *colorsel;
558
559   g_return_if_fail (object != NULL);
560   g_return_if_fail (GTK_IS_COLOR_SELECTION (object));
561
562   colorsel = GTK_COLOR_SELECTION (object);
563
564   if (colorsel->wheel_buf != NULL)
565     g_free (colorsel->wheel_buf);
566   if (colorsel->value_buf != NULL)
567     g_free (colorsel->value_buf);
568   if (colorsel->sample_buf != NULL)
569     g_free (colorsel->sample_buf);
570
571   (*GTK_OBJECT_CLASS (color_selection_parent_class)->finalize) (object);
572 }
573
574 static void
575 gtk_color_selection_color_changed (GtkColorSelection *colorsel)
576 {
577   gtk_signal_emit (GTK_OBJECT (colorsel), color_selection_signals[COLOR_CHANGED]);
578 }
579
580 static void
581 gtk_color_selection_update_input (GtkWidget *scale,
582                                   GtkWidget *entry,
583                                   gdouble    value)
584 {
585   GtkAdjustment *adj;
586   gchar txt[32];
587
588   if (scale != NULL)
589     {
590       adj = gtk_range_get_adjustment (GTK_RANGE (scale));
591       adj->value = (gfloat) value;
592       gtk_signal_handler_block_by_data (GTK_OBJECT (adj), (gpointer) scale);
593       gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
594       gtk_range_slider_update (GTK_RANGE (scale));
595       gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), (gpointer) scale);
596     }
597
598   if (entry != NULL)
599     {
600       gtk_signal_handler_block_by_data (GTK_OBJECT (entry), (gpointer) entry);
601       sprintf (txt, "%.2f", value);
602       gtk_entry_set_text (GTK_ENTRY (entry), txt);
603       gtk_signal_handler_unblock_by_data (GTK_OBJECT (entry), (gpointer) entry);
604     }
605 }
606
607 static void
608 gtk_color_selection_update_inputs (GtkColorSelection *colorsel,
609                                    gint               inputs,
610                                    gint               which)
611 {
612   gint n;
613
614   switch (which)
615     {
616     case SCALE:
617       if ((inputs & RGB_INPUTS) != 0)
618         for (n = RED; n <= BLUE; n++)
619           gtk_color_selection_update_input (colorsel->scales[n], NULL,
620                                             colorsel->values[n]);
621       if ((inputs & HSV_INPUTS) != 0)
622         for (n = HUE; n <= VALUE; n++)
623           gtk_color_selection_update_input (colorsel->scales[n], NULL,
624                                             colorsel->values[n]);
625       if ((inputs & OPACITY_INPUTS) != 0)
626         gtk_color_selection_update_input(colorsel->scales[OPACITY], NULL,
627                                          colorsel->values[OPACITY]);
628       break;
629     case ENTRY:
630       if ((inputs & RGB_INPUTS) != 0)
631         for (n = RED; n <= BLUE; n++)
632           gtk_color_selection_update_input (NULL, colorsel->entries[n], colorsel->values[n]);
633       if ((inputs & HSV_INPUTS) != 0)
634         for (n = HUE; n <= VALUE; n++)
635           gtk_color_selection_update_input (NULL, colorsel->entries[n], colorsel->values[n]);
636       if ((inputs & OPACITY_INPUTS) != 0)
637         gtk_color_selection_update_input(NULL, colorsel->entries[OPACITY], colorsel->values[OPACITY]);
638       break;
639     default:
640       if ((inputs & RGB_INPUTS) != 0)
641         for (n = RED; n <= BLUE; n++)
642           gtk_color_selection_update_input (colorsel->scales[n], colorsel->entries[n],
643                                             colorsel->values[n]);
644       if ((inputs & HSV_INPUTS) != 0)
645         for (n = HUE; n <= VALUE; n++)
646           gtk_color_selection_update_input (colorsel->scales[n], colorsel->entries[n],
647                                             colorsel->values[n]);
648       if ((inputs & OPACITY_INPUTS) != 0)
649         gtk_color_selection_update_input(colorsel->scales[OPACITY], colorsel->entries[OPACITY],
650                                          colorsel->values[OPACITY]);
651       break;
652     }
653 }
654
655 static void
656 gtk_color_selection_hsv_updater (GtkWidget *widget,
657                                  gpointer   data)
658 {
659   GtkColorSelection *colorsel;
660   GtkAdjustment *adj;
661   gdouble newvalue;
662   gint i, which = SCALE;
663
664   if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (widget)))
665     {
666       colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection");
667       i = (gint) gtk_object_get_data (GTK_OBJECT (widget), value_index_key);
668
669       if (GTK_IS_SCALE (widget))
670         {
671           adj = gtk_range_get_adjustment (GTK_RANGE (GTK_SCALE (widget)));
672           newvalue = (gdouble) adj->value;
673           which = ENTRY;
674         }
675       else
676         newvalue = (gdouble) atof (gtk_entry_get_text (GTK_ENTRY (widget)));
677
678       if (i == VALUE)
679         {
680           gtk_color_selection_draw_value_marker (colorsel);
681           colorsel->values[i] = newvalue;
682
683           HSV_TO_RGB ();
684
685           gtk_color_selection_draw_value_marker (colorsel);
686         }
687       else
688         {
689           gtk_color_selection_draw_wheel_marker (colorsel);
690           colorsel->values[i] = newvalue;
691
692           HSV_TO_RGB ();
693
694           gtk_color_selection_draw_wheel_marker (colorsel);
695           gtk_color_selection_draw_value_bar (colorsel, FALSE);
696         }
697
698       gtk_color_selection_draw_sample (colorsel, FALSE);
699       gtk_color_selection_color_changed (colorsel);
700       gtk_color_selection_update_inputs (colorsel, HSV_INPUTS, which);
701       gtk_color_selection_update_inputs (colorsel, RGB_INPUTS, BOTH);
702     }
703 }
704
705 static void
706 gtk_color_selection_rgb_updater (GtkWidget *widget,
707                                  gpointer   data)
708 {
709   GtkColorSelection *colorsel;
710   GtkAdjustment *adj;
711   gdouble newvalue;
712   gint i, which = SCALE;
713
714   if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (widget)))
715     {
716       colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection");
717       i = (gint) gtk_object_get_data (GTK_OBJECT (widget), value_index_key);
718
719       if (GTK_IS_SCALE (widget))
720         {
721           adj = gtk_range_get_adjustment (GTK_RANGE (GTK_SCALE (widget)));
722           newvalue = (gdouble) adj->value;
723           which = ENTRY;
724         }
725       else
726         newvalue = (gdouble) atof (gtk_entry_get_text (GTK_ENTRY (widget)));
727
728       gtk_color_selection_draw_wheel_marker (colorsel);
729
730       colorsel->values[i] = newvalue;
731       RGB_TO_HSV ();
732
733       gtk_color_selection_draw_wheel_marker (colorsel);
734       gtk_color_selection_draw_value_bar (colorsel, FALSE);
735       gtk_color_selection_draw_sample (colorsel, FALSE);
736       gtk_color_selection_color_changed (colorsel);
737       gtk_color_selection_update_inputs (colorsel, RGB_INPUTS, which);
738       gtk_color_selection_update_inputs (colorsel, HSV_INPUTS, BOTH);
739     }
740 }
741
742 static void
743 gtk_color_selection_opacity_updater (GtkWidget *widget,
744                                      gpointer   data)
745 {
746   GtkColorSelection *colorsel;
747   GtkAdjustment *adj;
748
749   colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection");
750
751   if (GTK_IS_SCALE (widget))
752     {
753       adj = gtk_range_get_adjustment (GTK_RANGE (widget));
754       colorsel->values[OPACITY] = (gdouble) adj->value;
755       gtk_color_selection_update_input (NULL, colorsel->entries[OPACITY], colorsel->values[OPACITY]);
756     }
757   else
758     {
759       colorsel->values[OPACITY] = (gdouble) atof (gtk_entry_get_text (GTK_ENTRY (widget)));
760       gtk_color_selection_update_input (colorsel->scales[OPACITY], NULL, colorsel->values[OPACITY]);
761     }
762
763   gtk_color_selection_draw_sample (colorsel, FALSE);
764   gtk_color_selection_color_changed (colorsel);
765 }
766
767 void
768 gtk_color_selection_set_opacity (GtkColorSelection *colorsel,
769                                  gint               use_opacity)
770 {
771   g_return_if_fail (colorsel != NULL);
772
773   colorsel->use_opacity = use_opacity;
774
775   if (use_opacity == FALSE && GTK_WIDGET_VISIBLE (colorsel->scales[OPACITY]))
776     {
777       gtk_widget_hide (colorsel->opacity_label);
778       gtk_widget_hide (colorsel->scales[OPACITY]);
779       gtk_widget_hide (colorsel->entries[OPACITY]);
780     }
781   else if (use_opacity == TRUE && !GTK_WIDGET_VISIBLE (colorsel->scales[OPACITY]))
782     {
783       gtk_widget_show (colorsel->opacity_label);
784       gtk_widget_show (colorsel->scales[OPACITY]);
785       gtk_widget_show (colorsel->entries[OPACITY]);
786     }
787
788   if (GTK_WIDGET_DRAWABLE (colorsel->sample_area))
789     gtk_color_selection_draw_sample (colorsel, FALSE);
790 }
791
792 static void
793 gtk_color_selection_value_resize (GtkWidget *widget,
794                                   gpointer   data)
795 {
796   GtkColorSelection *colorsel;
797
798   colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection");
799   gtk_color_selection_draw_value_bar (colorsel, TRUE);
800 }
801
802 static void
803 gtk_color_selection_wheel_resize (GtkWidget *widget,
804                                   gpointer   data)
805 {
806   GtkColorSelection *colorsel;
807
808   colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection");
809   gtk_color_selection_draw_wheel (colorsel, TRUE);
810 }
811
812 static void
813 gtk_color_selection_sample_resize (GtkWidget *widget,
814                                    gpointer   data)
815 {
816   GtkColorSelection *colorsel;
817
818   colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection");
819   gtk_color_selection_draw_sample (colorsel, TRUE);
820 }
821
822 static void
823 gtk_color_selection_drop_handle (GtkWidget *widget, GdkEvent *event,
824                                  GtkWidget *thecolorsel)
825 {
826   /* This is currently a gdouble array of the format (I think):
827      use_opacity
828      R
829      G
830      B
831      opacity
832   */
833   gdouble *v = event->dropdataavailable.data;
834   gtk_color_selection_set_opacity(GTK_COLOR_SELECTION(thecolorsel),
835                                   (v[0]==1.0)?TRUE:FALSE);
836   gtk_color_selection_set_color(GTK_COLOR_SELECTION(thecolorsel),
837                                 v + 1);
838   g_free(event->dropdataavailable.data);
839   g_free(event->dropdataavailable.data_type);
840 }
841
842 static void
843 gtk_color_selection_drag_handle (GtkWidget *widget, GdkEvent *event,
844                                  GtkWidget *thecolorsel)
845 {
846   gdouble sendvals[(BLUE - RED + 1) + 3];
847
848   sendvals[0] = (GTK_COLOR_SELECTION(thecolorsel)->use_opacity)?1.0:0.0;
849   gtk_color_selection_get_color(GTK_COLOR_SELECTION(thecolorsel),
850                                 sendvals + 1);
851
852   gtk_widget_dnd_data_set(widget,
853                           event,
854                           (gpointer)sendvals,
855                           sizeof(sendvals));
856 }
857
858 static void
859 gtk_color_selection_draw_wheel_marker (GtkColorSelection *colorsel)
860 {
861   gint xpos, ypos;
862
863   gdk_gc_set_function (colorsel->wheel_gc, GDK_INVERT);
864
865   xpos = (gint) ((-(gdouble) (colorsel->wheel_area->allocation.width) / 2.0) *
866                  colorsel->values[SATURATION] * cos (DEGTORAD ((colorsel->values[HUE] - 90)))) +
867                  (colorsel->wheel_area->allocation.width >> 1) - 4;
868   ypos = (gint) (((gdouble) (colorsel->wheel_area->allocation.height) / 2.0) *
869                  colorsel->values[SATURATION] * sin (DEGTORAD ((colorsel->values[HUE] - 90)))) +
870                  (colorsel->wheel_area->allocation.height >> 1) - 4;
871
872   gdk_draw_arc (colorsel->wheel_area->window, colorsel->wheel_gc, FALSE, xpos, ypos, 8, 8, 0, 360 * 64);
873 }
874
875 static void
876 gtk_color_selection_draw_value_marker (GtkColorSelection *colorsel)
877 {
878   gint y;
879
880   gdk_gc_set_function (colorsel->value_gc, GDK_INVERT);
881
882   y = (gint) ((gdouble) (colorsel->value_area->allocation.height) * (1.0 - colorsel->values[VALUE]));
883   gdk_draw_line (colorsel->value_area->window, colorsel->value_gc,
884                  0, y, colorsel->value_area->allocation.width, y);
885 }
886
887 static void
888 gtk_color_selection_update_value (GtkColorSelection *colorsel,
889                                   gint               y)
890 {
891   gtk_color_selection_draw_value_marker (colorsel);
892
893   if (y < 0)
894     y = 0;
895   else if (y > colorsel->value_area->allocation.height - 1)
896     y = colorsel->value_area->allocation.height - 1;
897
898   colorsel->values[VALUE] = 1.0 - (gdouble) y / (gdouble) (colorsel->value_area->allocation.height);
899
900   HSV_TO_RGB ();
901
902   gtk_color_selection_draw_value_marker (colorsel);
903   gtk_color_selection_draw_sample (colorsel, FALSE);
904   gtk_color_selection_update_input (colorsel->scales[VALUE], colorsel->entries[VALUE],
905                                     colorsel->values[VALUE]);
906   gtk_color_selection_update_inputs (colorsel, RGB_INPUTS, BOTH);
907 }
908
909 static void
910 gtk_color_selection_update_wheel (GtkColorSelection *colorsel,
911                                   gint               x,
912                                   gint               y)
913 {
914   gdouble wid, heig;
915   gint res;
916
917   gtk_color_selection_draw_wheel_marker (colorsel);
918
919   wid = (gdouble) (colorsel->wheel_area->allocation.width) / 2.0;
920   heig = (gdouble) (colorsel->wheel_area->allocation.height) / 2.0;
921
922   res = gtk_color_selection_eval_wheel (x, y, wid, heig, &colorsel->values[HUE],
923                                         &colorsel->values[SATURATION]);
924
925   HSV_TO_RGB ();
926
927   gtk_color_selection_draw_wheel_marker (colorsel);
928   gtk_color_selection_draw_value_bar (colorsel, FALSE);
929   gtk_color_selection_draw_sample (colorsel, FALSE);
930   gtk_color_selection_update_inputs (colorsel, RGB_INPUTS | HSV_INPUTS, BOTH);
931 }
932
933 static gint
934 gtk_color_selection_value_timeout (GtkColorSelection *colorsel)
935 {
936   gint x, y;
937
938   gdk_window_get_pointer (colorsel->value_area->window, &x, &y, NULL);
939   gtk_color_selection_update_value (colorsel, y);
940   gtk_color_selection_color_changed (colorsel);
941
942   return (TRUE);
943 }
944
945 static gint
946 gtk_color_selection_value_events (GtkWidget *area,
947                                   GdkEvent  *event)
948 {
949   GtkColorSelection *colorsel;
950   gint y;
951
952   colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (area), "_GtkColorSelection");
953
954   switch (event->type)
955     {
956     case GDK_MAP:
957       gtk_color_selection_draw_value_marker (colorsel);
958       break;
959     case GDK_EXPOSE:
960       if (colorsel->value_gc == NULL)
961         colorsel->value_gc = gdk_gc_new (colorsel->value_area->window);
962       gtk_color_selection_draw_value_marker (colorsel);
963       break;
964     case GDK_BUTTON_PRESS:
965       gtk_grab_add (area);
966       gtk_color_selection_update_value (colorsel, event->button.y);
967       gtk_color_selection_color_changed (colorsel);
968       break;
969     case GDK_BUTTON_RELEASE:
970       gtk_grab_remove (area);
971       if (colorsel->timer_active == TRUE)
972         gtk_timeout_remove (colorsel->timer_tag);
973       colorsel->timer_active = FALSE;
974
975       y = event->button.y;
976       if (event->button.window != area->window)
977         gdk_window_get_pointer (area->window, NULL, &y, NULL);
978
979       gtk_color_selection_update_value (colorsel, y);
980       gtk_color_selection_color_changed (colorsel);
981       break;
982     case GDK_MOTION_NOTIFY:
983       y = event->motion.y;
984
985       if (event->motion.is_hint || (event->motion.window != area->window))
986         gdk_window_get_pointer (area->window, NULL, &y, NULL);
987
988       switch (colorsel->policy)
989         {
990         case GTK_UPDATE_CONTINUOUS:
991           gtk_color_selection_update_value (colorsel, y);
992           gtk_color_selection_color_changed (colorsel);
993           break;
994         case GTK_UPDATE_DELAYED:
995           if (colorsel->timer_active == TRUE)
996             gtk_timeout_remove (colorsel->timer_tag);
997
998           colorsel->timer_tag = gtk_timeout_add (TIMER_DELAY,
999                                                  (GtkFunction) gtk_color_selection_value_timeout,
1000                                                  (gpointer) colorsel);
1001           colorsel->timer_active = TRUE;
1002           break;
1003         default:
1004           break;
1005         }
1006       break;
1007     default:
1008       break;
1009     }
1010
1011   return (FALSE);
1012 }
1013
1014 static gint
1015 gtk_color_selection_wheel_timeout (GtkColorSelection *colorsel)
1016 {
1017   gint x, y;
1018
1019   gdk_window_get_pointer (colorsel->wheel_area->window, &x, &y, NULL);
1020   gtk_color_selection_update_wheel (colorsel, x, y);
1021   gtk_color_selection_color_changed (colorsel);
1022
1023   return (TRUE);
1024 }
1025
1026 static gint
1027 gtk_color_selection_wheel_events (GtkWidget *area,
1028                                   GdkEvent  *event)
1029 {
1030   GtkColorSelection *colorsel;
1031   gint x, y;
1032
1033   colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (area), "_GtkColorSelection");
1034
1035   switch (event->type)
1036     {
1037     case GDK_MAP:
1038       gtk_color_selection_draw_wheel (colorsel, TRUE);
1039       gtk_color_selection_draw_wheel_marker (colorsel);
1040       gtk_color_selection_draw_sample (colorsel, TRUE);
1041       break;
1042     case GDK_EXPOSE:
1043       if (colorsel->wheel_gc == NULL)
1044         colorsel->wheel_gc = gdk_gc_new (colorsel->wheel_area->window);
1045       if (colorsel->sample_gc == NULL)
1046         colorsel->sample_gc = gdk_gc_new (colorsel->sample_area->window);
1047       if (colorsel->value_gc == NULL)
1048         colorsel->value_gc = gdk_gc_new (colorsel->value_area->window);
1049       gtk_color_selection_draw_wheel_marker (colorsel);
1050       gtk_color_selection_draw_wheel_frame (colorsel);
1051       break;
1052     case GDK_BUTTON_PRESS:
1053       gtk_grab_add (area);
1054       gtk_color_selection_update_wheel (colorsel, event->button.x, event->button.y);
1055       gtk_color_selection_color_changed (colorsel);
1056       break;
1057     case GDK_BUTTON_RELEASE:
1058       gtk_grab_remove (area);
1059       if (colorsel->timer_active == TRUE)
1060         gtk_timeout_remove (colorsel->timer_tag);
1061       colorsel->timer_active = FALSE;
1062
1063       x = event->button.x;
1064       y = event->button.y;
1065
1066       if (event->button.window != area->window)
1067         gdk_window_get_pointer (area->window, &x, &y, NULL);
1068
1069       gtk_color_selection_update_wheel (colorsel, x, y);
1070       gtk_color_selection_color_changed (colorsel);
1071       break;
1072     case GDK_MOTION_NOTIFY:
1073       x = event->motion.x;
1074       y = event->motion.y;
1075
1076       if (event->motion.is_hint || (event->motion.window != area->window))
1077         gdk_window_get_pointer (area->window, &x, &y, NULL);
1078
1079       switch (colorsel->policy)
1080         {
1081         case GTK_UPDATE_CONTINUOUS:
1082           gtk_color_selection_update_wheel (colorsel, x, y);
1083           gtk_color_selection_color_changed (colorsel);
1084           break;
1085         case GTK_UPDATE_DELAYED:
1086           if (colorsel->timer_active == TRUE)
1087             gtk_timeout_remove (colorsel->timer_tag);
1088           colorsel->timer_tag = gtk_timeout_add (TIMER_DELAY,
1089                                                  (GtkFunction) gtk_color_selection_wheel_timeout,
1090                                                  (gpointer) colorsel);
1091           colorsel->timer_active = TRUE;
1092           break;
1093         default:
1094           break;
1095         }
1096       break;
1097     default:
1098       break;
1099     }
1100
1101   return (FALSE);
1102 }
1103
1104 static void
1105 gtk_color_selection_draw_value_bar (GtkColorSelection *colorsel,
1106                                     gint               resize)
1107 {
1108   gint x, y, i, wid, heig, n;
1109   gdouble sv, v, c[3];
1110   guchar rc[3];
1111
1112   wid = colorsel->value_area->allocation.width;
1113   heig = colorsel->value_area->allocation.height;
1114
1115   if (resize)
1116     {
1117       if (colorsel->value_buf != NULL)
1118         g_free (colorsel->value_buf);
1119
1120       colorsel->value_buf = g_new(guchar, 3 * wid);
1121     }
1122
1123   v = 1.0;
1124   sv = 1.0 / (gdouble) (heig - 1);
1125
1126   for (y = 0; y < heig; y++)
1127     {
1128       i = 0;
1129
1130       gtk_color_selection_hsv_to_rgb (colorsel->values[HUE],colorsel->values[SATURATION],v,
1131                                       &c[0], &c[1], &c[2]);
1132
1133       for (n = 0; n < 3; n++)
1134         rc[n] = (guchar) (255.0 * c[n]);
1135
1136       for (x = 0; x < wid; x++)
1137         {
1138           for (n = 0; n < 3; n++)
1139             colorsel->value_buf[i++] = rc[n];
1140         }
1141
1142       gtk_preview_draw_row (GTK_PREVIEW (colorsel->value_area), colorsel->value_buf, 0, y, wid);
1143       v -= sv;
1144     }
1145
1146   gtk_widget_draw (colorsel->value_area, NULL);
1147 }
1148
1149 static void
1150 gtk_color_selection_draw_wheel_frame (GtkColorSelection *colorsel)
1151 {
1152   GtkStyle *style;
1153   gint w, h;
1154
1155   style = gtk_widget_get_style (colorsel->wheel_area);
1156
1157   w = colorsel->wheel_area->allocation.width;
1158   h = colorsel->wheel_area->allocation.height;
1159
1160   gdk_draw_arc (colorsel->wheel_area->window, style->black_gc,
1161                 FALSE, 1, 1, w - 1, h - 1, 30 * 64, 180 * 64);
1162   gdk_draw_arc (colorsel->wheel_area->window, style->mid_gc[GTK_STATE_NORMAL],
1163                 FALSE, 0, 0, w, h, 30 * 64, 180 * 64);
1164
1165   gdk_draw_arc (colorsel->wheel_area->window, style->bg_gc[GTK_STATE_NORMAL],
1166                 FALSE, 1, 1, w - 1, h - 1, 210 * 64, 180 * 64);
1167   gdk_draw_arc (colorsel->wheel_area->window, style->light_gc[GTK_STATE_NORMAL],
1168                 FALSE, 0, 0, w, h, 210 * 64, 180 * 64);
1169 }
1170
1171 static void
1172 gtk_color_selection_draw_wheel (GtkColorSelection *colorsel,
1173                                 gint               resize)
1174 {
1175   gint x, y, i, wid, heig, n;
1176   gdouble cx, cy, h, s, c[3];
1177   guchar bg[3];
1178   GtkStyle *style = gtk_widget_get_style (colorsel->wheel_area);
1179
1180   wid = colorsel->wheel_area->allocation.width;
1181   heig = colorsel->wheel_area->allocation.height;
1182
1183   if (resize)
1184     {
1185       if (colorsel->wheel_buf != NULL)
1186         g_free (colorsel->wheel_buf);
1187
1188       colorsel->wheel_buf = g_new(guchar, 3 * wid);
1189     }
1190
1191   cx = (gdouble) (wid) / 2.0;
1192   cy = (gdouble) (heig) / 2.0;
1193
1194   bg[0] = style->bg[GTK_STATE_NORMAL].red >> 8;
1195   bg[1] = style->bg[GTK_STATE_NORMAL].green >> 8;
1196   bg[2] = style->bg[GTK_STATE_NORMAL].blue >> 8;
1197
1198   for (y = 0; y < heig; y++)
1199     {
1200       i = 0;
1201       for (x = 0; x < wid; x++)
1202         {
1203           if (gtk_color_selection_eval_wheel (x, y, cx, cy, &h, &s) == TRUE)
1204             {
1205               for (n = 0; n < 3; n++)
1206                 colorsel->wheel_buf[i++] = bg[n];
1207             }
1208           else
1209             {
1210               gtk_color_selection_hsv_to_rgb (h, s, 1.0, &c[0], &c[1], &c[2]);
1211               for (n = 0; n < 3; n++)
1212                 colorsel->wheel_buf[i++] = (guchar) (255.0 * c[n]);
1213             }
1214         }
1215
1216       gtk_preview_draw_row (GTK_PREVIEW (colorsel->wheel_area), colorsel->wheel_buf, 0, y, wid);
1217     }
1218
1219   gtk_widget_draw (colorsel->wheel_area, NULL);
1220 }
1221
1222 static void
1223 gtk_color_selection_draw_sample (GtkColorSelection *colorsel,
1224                                  gint               resize)
1225 {
1226   gint x, y, i, wid, heig, f, half, n;
1227   guchar c[3 * 2], cc[3 * 4], *cp = c;
1228   gdouble o, oldo;
1229
1230   wid = colorsel->sample_area->allocation.width;
1231   heig = colorsel->sample_area->allocation.height;
1232   half = wid >> 1;
1233
1234   if (resize)
1235     {
1236       if (colorsel->sample_buf != NULL)
1237         g_free (colorsel->sample_buf);
1238
1239       colorsel->sample_buf = g_new(guchar, 3 * wid);
1240     }
1241
1242   i = RED;
1243   for (n = 0; n < 3; n++)
1244     {
1245       c[n] = (guchar) (255.0 * colorsel->old_values[i]);
1246       c[n + 3] = (guchar) (255.0 * colorsel->values[i++]);
1247     }
1248
1249   if (colorsel->use_opacity == TRUE)
1250     {
1251       o = colorsel->values[OPACITY];
1252       oldo = colorsel->old_values[OPACITY];
1253
1254       for (n = 0; n < 3; n++)
1255         {
1256           cc[n] = (guchar) ((1.0 - oldo) * 192 + (oldo * (gdouble) c[n]));
1257           cc[n + 3] = (guchar) ((1.0 - oldo) * 128 + (oldo * (gdouble) c[n]));
1258           cc[n + 6] = (guchar) ((1.0 - o) * 192 + (o * (gdouble) c[n + 3]));
1259           cc[n + 9] = (guchar) ((1.0 - o) * 128 + (o * (gdouble) c[n + 3]));
1260         }
1261       cp = cc;
1262     }
1263
1264   for (y = 0; y < heig; y++)
1265     {
1266       i = 0;
1267       for (x = 0; x < wid; x++)
1268         {
1269           if (colorsel->use_opacity)
1270             {
1271               f = 3 * (((x % 32) < 16) ^ ((y % 32) < 16));
1272               f += (x > half) * 6;
1273             }
1274           else
1275             f = (x > half) * 3;
1276
1277           for (n = 0; n < 3; n++)
1278             colorsel->sample_buf[i++] = cp[n + f];
1279         }
1280
1281       gtk_preview_draw_row (GTK_PREVIEW (colorsel->sample_area), colorsel->sample_buf, 0, y, wid);
1282     }
1283
1284   gtk_widget_draw (colorsel->sample_area, NULL);
1285 }
1286
1287 static gint
1288 gtk_color_selection_eval_wheel (gint     x,  gint     y,
1289                                 gdouble  cx, gdouble  cy,
1290                                 gdouble *h,  gdouble *s)
1291 {
1292   gdouble d, r, rx, ry, l;
1293
1294   rx = (gdouble) x - cx;
1295   ry = (gdouble) y - cy;
1296
1297   d = (SQR (cy) * SQR (rx) + SQR (cx) * SQR (ry) - SQR (cx) * SQR (cy));
1298
1299   r = sqrt (SQR (rx) + SQR (ry));
1300
1301   if (r != 0.0)
1302     *h = atan2 (rx / r, ry / r);
1303   else
1304     *h = 0.0;
1305
1306   l = sqrt (SQR ((cx * cos (*h + 0.5 * M_PI))) + SQR ((cy * sin (*h + 0.5 * M_PI))));
1307   *s = r / l;
1308   *h = 360.0 * (*h) / (2.0 * M_PI) + 180;
1309
1310   if (*s == 0.0)
1311     *s = 0.00001;
1312   else if (*s > 1.0)
1313     *s = 1.0;
1314
1315   return ((d > 0.0));
1316 }
1317
1318 static void
1319 gtk_color_selection_hsv_to_rgb (gdouble  h, gdouble  s, gdouble  v,
1320                                 gdouble *r, gdouble *g, gdouble *b)
1321 {
1322   gint i;
1323   gdouble f, w, q, t;
1324
1325   if (s == 0.0)
1326     s = 0.000001;
1327
1328   if (h == -1.0)
1329     {
1330       *r = v;
1331       *g = v;
1332       *b = v;
1333     }
1334   else
1335     {
1336       if (h == 360.0)
1337         h = 0.0;
1338       h = h / 60.0;
1339       i = (gint) h;
1340       f = h - i;
1341       w = v * (1.0 - s);
1342       q = v * (1.0 - (s * f));
1343       t = v * (1.0 - (s * (1.0 - f)));
1344
1345       switch (i)
1346         {
1347         case 0:
1348           *r = v;
1349           *g = t;
1350           *b = w;
1351           break;
1352         case 1:
1353           *r = q;
1354           *g = v;
1355           *b = w;
1356           break;
1357         case 2:
1358           *r = w;
1359           *g = v;
1360           *b = t;
1361           break;
1362         case 3:
1363           *r = w;
1364           *g = q;
1365           *b = v;
1366           break;
1367         case 4:
1368           *r = t;
1369           *g = w;
1370           *b = v;
1371           break;
1372         case 5:
1373           *r = v;
1374           *g = w;
1375           *b = q;
1376           break;
1377         }
1378     }
1379 }
1380
1381 static void
1382 gtk_color_selection_rgb_to_hsv (gdouble  r, gdouble  g, gdouble  b,
1383                                 gdouble *h, gdouble *s, gdouble *v)
1384 {
1385   double max, min, delta;
1386
1387   max = r;
1388   if (g > max)
1389     max = g;
1390   if (b > max)
1391     max = b;
1392
1393   min = r;
1394   if (g < min)
1395     min = g;
1396   if (b < min)
1397     min = b;
1398
1399   *v = max;
1400
1401   if (max != 0.0)
1402     *s = (max - min) / max;
1403   else
1404     *s = 0.0;
1405
1406   if (*s == 0.0)
1407     *h = -1.0;
1408   else
1409     {
1410       delta = max - min;
1411
1412       if (r == max)
1413         *h = (g - b) / delta;
1414       else if (g == max)
1415         *h = 2.0 + (b - r) / delta;
1416       else if (b == max)
1417         *h = 4.0 + (r - g) / delta;
1418
1419       *h = *h * 60.0;
1420
1421       if (*h < 0.0)
1422         *h = *h + 360;
1423     }
1424 }
1425
1426 /***************************/
1427 /* GtkColorSelectionDialog */
1428 /***************************/
1429
1430 guint
1431 gtk_color_selection_dialog_get_type (void)
1432 {
1433   static guint color_selection_dialog_type = 0;
1434
1435   if (!color_selection_dialog_type)
1436     {
1437       GtkTypeInfo colorsel_diag_info =
1438       {
1439         "GtkColorSelectionDialog",
1440         sizeof (GtkColorSelectionDialog),
1441         sizeof (GtkColorSelectionDialogClass),
1442         (GtkClassInitFunc) gtk_color_selection_dialog_class_init,
1443         (GtkObjectInitFunc) gtk_color_selection_dialog_init,
1444         (GtkArgSetFunc) NULL,
1445         (GtkArgGetFunc) NULL,
1446       };
1447
1448       color_selection_dialog_type = gtk_type_unique (gtk_window_get_type (), &colorsel_diag_info);
1449     }
1450
1451   return color_selection_dialog_type;
1452 }
1453
1454 static void
1455 gtk_color_selection_dialog_class_init (GtkColorSelectionDialogClass *klass)
1456 {
1457   GtkObjectClass *object_class;
1458
1459   object_class = (GtkObjectClass*) klass;
1460
1461   color_selection_dialog_parent_class = gtk_type_class (gtk_window_get_type ());
1462 }
1463
1464 static void
1465 gtk_color_selection_dialog_init (GtkColorSelectionDialog *colorseldiag)
1466 {
1467   GtkWidget *action_area, *frame;
1468
1469   colorseldiag->main_vbox = gtk_vbox_new (FALSE, 10);
1470   gtk_container_border_width (GTK_CONTAINER (colorseldiag), 10);
1471   gtk_container_add (GTK_CONTAINER (colorseldiag), colorseldiag->main_vbox);
1472   gtk_widget_show (colorseldiag->main_vbox);
1473
1474   frame = gtk_frame_new (NULL);
1475   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
1476   gtk_container_add (GTK_CONTAINER (colorseldiag->main_vbox), frame);
1477   gtk_widget_show (frame);
1478
1479   colorseldiag->colorsel = gtk_color_selection_new ();
1480   gtk_container_add (GTK_CONTAINER (frame), colorseldiag->colorsel);
1481   gtk_widget_show (colorseldiag->colorsel);
1482
1483   action_area = gtk_hbutton_box_new ();
1484   gtk_button_box_set_layout(GTK_BUTTON_BOX(action_area), GTK_BUTTONBOX_END);
1485   gtk_button_box_set_spacing(GTK_BUTTON_BOX(action_area), 5);
1486   gtk_box_pack_end (GTK_BOX (colorseldiag->main_vbox), action_area, FALSE, FALSE, 0);
1487   gtk_widget_show (action_area);
1488
1489   colorseldiag->ok_button = gtk_button_new_with_label ("OK");
1490   GTK_WIDGET_SET_FLAGS (colorseldiag->ok_button, GTK_CAN_DEFAULT);
1491   gtk_box_pack_start (GTK_BOX (action_area), colorseldiag->ok_button, TRUE, TRUE, 0);
1492   gtk_widget_grab_default (colorseldiag->ok_button);
1493   gtk_widget_show (colorseldiag->ok_button);
1494
1495   colorseldiag->cancel_button = gtk_button_new_with_label ("Cancel");
1496   GTK_WIDGET_SET_FLAGS (colorseldiag->cancel_button, GTK_CAN_DEFAULT);
1497   gtk_box_pack_start (GTK_BOX (action_area), colorseldiag->cancel_button, TRUE, TRUE, 0);
1498   gtk_widget_show (colorseldiag->cancel_button);
1499
1500   colorseldiag->help_button = gtk_button_new_with_label ("Help");
1501   GTK_WIDGET_SET_FLAGS (colorseldiag->help_button, GTK_CAN_DEFAULT);
1502   gtk_box_pack_start (GTK_BOX (action_area), colorseldiag->help_button, TRUE, TRUE, 0);
1503   gtk_widget_show (colorseldiag->help_button);
1504 }
1505
1506 GtkWidget *
1507 gtk_color_selection_dialog_new (const gchar *title)
1508 {
1509   GtkColorSelectionDialog *colorseldiag;
1510
1511   colorseldiag = gtk_type_new (gtk_color_selection_dialog_get_type ());
1512   gtk_window_set_title (GTK_WINDOW (colorseldiag), title);
1513
1514   return GTK_WIDGET (colorseldiag);
1515 }