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