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