source: trunk/third/gtk/gtk/gtkcolorsel.c @ 14482

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