diff options
author | Owen Taylor <otaylor@redhat.com> | 2000-05-10 21:39:03 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 2000-05-10 21:39:03 +0000 |
commit | 88286d32af4f7289c3e3878e3f5159ebcdf0e753 (patch) | |
tree | 8ecaad5fd53e21323716bc2b7b7e79dbb6dd192c /gtk | |
parent | ac9090ed103ebc0fb61ccf361156b2827b9e14d5 (diff) | |
download | gtk+-88286d32af4f7289c3e3878e3f5159ebcdf0e753.tar.gz |
Color selection dialog rewrite.
Wed May 10 16:38:17 2000 Owen Taylor <otaylor@redhat.com>
* gtk/Makefile.am docs/Changes-1.4.txt gtk/gtkcolorsel.[ch]
gtk/gtkhsv.[ch]: Color selection dialog rewrite.
(Original triangle color selector from Simon Budig
<Simon.Budig@unix-ag.org>, Cleaned up and rewritten for GTK+ by
from Jonathan, Havoc, and Federico. Merge into GTK+ done by David
Santiago <mrcooger@cyberverse.com>)
* gtk/gtkcolorseldialog.[ch]: Split color selection dialog
out into a separate widget.
* gtk/testgtk.c: Add some checkbuttons for toggling palette
and opacity controls.
Wed May 10 16:08:09 2000 Owen Taylor <otaylor@redhat.com>
* configure.in (GTK_LIBS_EXTRA): Remove references to gobject that
snuck in prematurely.
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/Makefile.am | 3 | ||||
-rw-r--r-- | gtk/gtk.h | 1 | ||||
-rw-r--r-- | gtk/gtkcolorsel.c | 2801 | ||||
-rw-r--r-- | gtk/gtkcolorsel.h | 160 | ||||
-rw-r--r-- | gtk/gtkcolorseldialog.c | 138 | ||||
-rw-r--r-- | gtk/gtkcolorseldialog.h | 76 | ||||
-rw-r--r-- | gtk/gtkhsv.c | 1407 | ||||
-rw-r--r-- | gtk/gtkhsv.h | 83 | ||||
-rw-r--r-- | gtk/testgtk.c | 47 |
9 files changed, 3250 insertions, 1466 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 296dda3e7f..6c2a2d6adf 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -62,6 +62,7 @@ gtk_public_h_sources = @STRIP_BEGIN@ \ gtkcheckmenuitem.h \ gtkclist.h \ gtkcolorsel.h \ + gtkcolorseldialog.h \ gtkcombo.h \ gtkcompat.h \ gtkcontainer.h \ @@ -177,6 +178,7 @@ gtk_c_sources = @STRIP_BEGIN@ \ gtkcheckmenuitem.c \ gtkclist.c \ gtkcolorsel.c \ + gtkcolorseldialog.c \ gtkcombo.c \ gtkcontainer.c \ gtkctree.c \ @@ -202,6 +204,7 @@ gtk_c_sources = @STRIP_BEGIN@ \ gtkhscale.c \ gtkhscrollbar.c \ gtkhseparator.c \ + gtkhsv.c \ gtkimage.c \ gtkinputdialog.c \ gtkintl.h \ @@ -46,6 +46,7 @@ #include <gtk/gtkcheckmenuitem.h> #include <gtk/gtkclist.h> #include <gtk/gtkcolorsel.h> +#include <gtk/gtkcolorseldialog.h> #include <gtk/gtkcombo.h> #include <gtk/gtkcompat.h> #include <gtk/gtkcontainer.h> diff --git a/gtk/gtkcolorsel.c b/gtk/gtkcolorsel.c index 5e82acc6d9..6af300bd9e 100644 --- a/gtk/gtkcolorsel.c +++ b/gtk/gtkcolorsel.c @@ -1,4 +1,5 @@ -/* GTK - The GIMP Toolkit + /* GTK - The GIMP Toolkit + * Copyright (C) 2000 Red Hat, Inc. * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or @@ -24,915 +25,643 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <gdk/gdk.h> +#include <glib.h> +#include "gdk/gdkx.h" +#include "gdk/gdkkeysyms.h" #include "gtkcolorsel.h" +#include "gtkhsv.h" #include "gtkwindow.h" +#include "gtkselection.h" +#include "gtkdnd.h" +#include "gtkdrawingarea.h" +#include "gtksignal.h" +#include "gtkhbox.h" #include "gtkhbbox.h" +#include "gtkrc.h" +#include "gtkframe.h" +#include "gtktable.h" +#include "gtklabel.h" +#include "gtkpixmap.h" +#include "gtkspinbutton.h" +#include "gtkrange.h" +#include "gtkhscale.h" +#include "gtkentry.h" +#include "gtkbutton.h" +#include "gtkhseparator.h" #include "gtkintl.h" -#include "gtkdnd.h" -#include "gtkselection.h" - -/* - * If you change the way the color values are stored, - * please make sure to update the drag & drop support so it sends - * across all the color info (currently RGBA). - Elliot - */ - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif /* M_PI */ - -#define DEGTORAD(a) (2.0*M_PI*a/360.0) -#define SQR(a) (a*a) - -#define TIMER_DELAY 300 - -#define CIRCLE_RADIUS 65 - -#define WHEEL_WIDTH 2*CIRCLE_RADIUS+2 -#define WHEEL_HEIGHT 2*CIRCLE_RADIUS+2 - -#define VALUE_WIDTH 32 -#define VALUE_HEIGHT WHEEL_HEIGHT - -#define SAMPLE_WIDTH WHEEL_WIDTH+VALUE_WIDTH+5 -#define SAMPLE_HEIGHT 28 - -static void gtk_color_selection_class_init (GtkColorSelectionClass *klass); -static void gtk_color_selection_set_arg (GtkObject *object, - GtkArg *arg, - guint arg_id); -static void gtk_color_selection_get_arg (GtkObject *object, - GtkArg *arg, - guint arg_id); -static void gtk_color_selection_init (GtkColorSelection *colorsel); -static void gtk_color_selection_dialog_class_init (GtkColorSelectionDialogClass *klass); -static void gtk_color_selection_dialog_init (GtkColorSelectionDialog *colorseldiag); enum { COLOR_CHANGED, LAST_SIGNAL }; -enum { - RGB_INPUTS = 1 << 0, - HSV_INPUTS = 1 << 1, - OPACITY_INPUTS = 1 << 2 -}; -enum { - SCALE, - ENTRY, - BOTH -}; enum { - HUE, - SATURATION, - VALUE, - RED, - GREEN, - BLUE, - OPACITY, - NUM_CHANNELS + COLORSEL_RED = 0, + COLORSEL_GREEN = 1, + COLORSEL_BLUE = 2, + COLORSEL_OPACITY = 3, + COLORSEL_HUE, + COLORSEL_SATURATION, + COLORSEL_VALUE, + COLORSEL_NUM_CHANNELS }; -enum { - ARG_0, - ARG_UPDATE_POLICY, - ARG_USE_OPACITY -}; +typedef struct _ColorSelectionPrivate ColorSelectionPrivate; -typedef struct -{ - gchar *label; - gfloat lower, upper, step_inc, page_inc; - GtkSignalFunc updater; -} scale_val_type; - - -#define HSV_TO_RGB() gtk_color_selection_hsv_to_rgb( \ - colorsel->values[HUE], \ - colorsel->values[SATURATION], \ - colorsel->values[VALUE], \ - &colorsel->values[RED], \ - &colorsel->values[GREEN], \ - &colorsel->values[BLUE]) - -#define RGB_TO_HSV() gtk_color_selection_rgb_to_hsv( \ - colorsel->values[RED], \ - colorsel->values[GREEN], \ - colorsel->values[BLUE], \ - &colorsel->values[HUE], \ - &colorsel->values[SATURATION], \ - &colorsel->values[VALUE]) - - -static void gtk_color_selection_hsv_updater (GtkWidget *widget, - gpointer data); -static void gtk_color_selection_rgb_updater (GtkWidget *widget, - gpointer data); -static void gtk_color_selection_opacity_updater (GtkWidget *widget, - gpointer data); -static void gtk_color_selection_realize (GtkWidget *widget); -static void gtk_color_selection_unrealize (GtkWidget *widget); -static void gtk_color_selection_finalize (GtkObject *object); -static void gtk_color_selection_color_changed (GtkColorSelection *colorsel); -static void gtk_color_selection_update_input (GtkWidget *scale, - GtkWidget *entry, - gdouble value); -static void gtk_color_selection_update_inputs (GtkColorSelection *colorsel, - gint inputs, - gint which); -static void gtk_color_selection_update_value (GtkColorSelection *colorsel, - gint y); -static void gtk_color_selection_update_wheel (GtkColorSelection *colorsel, - gint x, - gint y); -static void gtk_color_selection_value_resize (GtkWidget *widget, - gpointer data); -static gint gtk_color_selection_value_events (GtkWidget *area, - GdkEvent *event); -static gint gtk_color_selection_value_timeout (GtkColorSelection *colorsel); -static void gtk_color_selection_wheel_resize (GtkWidget *widget, - gpointer data); -static gint gtk_color_selection_wheel_events (GtkWidget *area, - GdkEvent *event); -static gint gtk_color_selection_wheel_timeout (GtkColorSelection *colorsel); -static void gtk_color_selection_sample_resize (GtkWidget *widget, - gpointer data); -static void gtk_color_selection_drag_begin (GtkWidget *widget, - GdkDragContext *context, - gpointer data); -static void gtk_color_selection_drag_end (GtkWidget *widget, - GdkDragContext *context, - gpointer data); -static void gtk_color_selection_drop_handle (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection_data, - guint info, - guint time, - gpointer data); -static void gtk_color_selection_drag_handle (GtkWidget *widget, - GdkDragContext *context, - GtkSelectionData *selection_data, - guint info, - guint time, - gpointer data); -static void gtk_color_selection_draw_wheel_marker (GtkColorSelection *colorsel); -static void gtk_color_selection_draw_wheel_frame (GtkColorSelection *colorsel); -static void gtk_color_selection_draw_value_marker (GtkColorSelection *colorsel); -static void gtk_color_selection_draw_value_bar (GtkColorSelection *colorsel, - gint resize); -static void gtk_color_selection_draw_wheel (GtkColorSelection *colorsel, - gint resize); -static void gtk_color_selection_draw_sample (GtkColorSelection *colorsel, - gint resize); - -static gint gtk_color_selection_eval_wheel (gint x, gint y, - gdouble cx, gdouble cy, - gdouble *h, gdouble *s); - -static void gtk_color_selection_hsv_to_rgb (gdouble h, gdouble s, gdouble v, - gdouble *r, gdouble *g, gdouble *b); -static void gtk_color_selection_rgb_to_hsv (gdouble r, gdouble g, gdouble b, - gdouble *h, gdouble *s, gdouble *v); - - -static GtkVBoxClass *color_selection_parent_class = NULL; -static GtkWindowClass *color_selection_dialog_parent_class = NULL; - - -static guint color_selection_signals[LAST_SIGNAL] = {0}; - -static const gchar *value_index_key = "gtk-value-index"; - - -#define SF GtkSignalFunc - - -static const scale_val_type scale_vals[NUM_CHANNELS] = +struct _ColorSelectionPrivate { - {N_("Hue:"), 0.0, 360.0, 1.00, 10.00, (SF) gtk_color_selection_hsv_updater}, - {N_("Saturation:"), 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_hsv_updater}, - {N_("Value:"), 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_hsv_updater}, - {N_("Red:"), 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_rgb_updater}, - {N_("Green:"), 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_rgb_updater}, - {N_("Blue:"), 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_rgb_updater}, - {N_("Opacity:"), 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_opacity_updater} + /* < Private > */ + gboolean use_opacity; + gboolean use_palette; + gboolean changing; + gboolean default_set; + + gdouble color[COLORSEL_NUM_CHANNELS]; + gdouble old_color[COLORSEL_NUM_CHANNELS]; + + GtkWidget *triangle_colorsel; + GtkWidget *hue_spinbutton; + GtkWidget *sat_spinbutton; + GtkWidget *val_spinbutton; + GtkWidget *red_spinbutton; + GtkWidget *green_spinbutton; + GtkWidget *blue_spinbutton; + GtkWidget *opacity_slider; + GtkWidget *opacity_label; + GtkWidget *opacity_entry; + GtkWidget *palette_frame; + GtkWidget *hex_entry; + + /* The Palette code */ + GtkWidget *custom_palette [CUSTOM_PALETTE_WIDTH][CUSTOM_PALETTE_HEIGHT]; + GtkWidget *last_palette; + + /* The color_sample stuff */ + GtkWidget *sample_area; + GtkWidget *old_sample; + GtkWidget *cur_sample; + GtkWidget *colorsel; + + /* The color dropper */ + gboolean moving_dropper; }; -GtkType -gtk_color_selection_get_type (void) -{ - static GtkType color_selection_type = 0; - if (!color_selection_type) - { - static const GtkTypeInfo colorsel_info = - { - "GtkColorSelection", - sizeof (GtkColorSelection), - sizeof (GtkColorSelectionClass), - (GtkClassInitFunc) gtk_color_selection_class_init, - (GtkObjectInitFunc) gtk_color_selection_init, - /* reserved_1 */ NULL, - /* reserved_2 */ NULL, - (GtkClassInitFunc) NULL, - }; +static void gtk_color_selection_init (GtkColorSelection *colorsel); +static void gtk_color_selection_class_init (GtkColorSelectionClass *klass); +static void gtk_color_selection_destroy (GtkObject *object); +static void update_color (GtkColorSelection *colorsel); + +static GtkVBoxClass *parent_class = NULL; +static guint color_selection_signals[LAST_SIGNAL] = { 0 }; + + +/* The cursor for the dropper */ +#define DROPPER_WIDTH 17 +#define DROPPER_HEIGHT 17 +#define DROPPER_X_HOT 2 +#define DROPPER_Y_HOT 16 + + +static char dropper_bits[] = { + 0xff, 0x8f, 0x01, 0xff, 0x77, 0x01, 0xff, 0xfb, 0x00, 0xff, 0xf8, 0x00, + 0x7f, 0xff, 0x00, 0xff, 0x7e, 0x01, 0xff, 0x9d, 0x01, 0xff, 0xd8, 0x01, + 0x7f, 0xd4, 0x01, 0x3f, 0xee, 0x01, 0x1f, 0xff, 0x01, 0x8f, 0xff, 0x01, + 0xc7, 0xff, 0x01, 0xe3, 0xff, 0x01, 0xf3, 0xff, 0x01, 0xfd, 0xff, 0x01, + 0xff, 0xff, 0x01, }; + +static char dropper_mask[] = { + 0x00, 0x70, 0x00, 0x00, 0xf8, 0x00, 0x00, 0xfc, 0x01, 0x00, 0xff, 0x01, + 0x80, 0xff, 0x01, 0x00, 0xff, 0x00, 0x00, 0x7f, 0x00, 0x80, 0x3f, 0x00, + 0xc0, 0x3f, 0x00, 0xe0, 0x13, 0x00, 0xf0, 0x01, 0x00, 0xf8, 0x00, 0x00, + 0x7c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x0d, 0x00, 0x00, + 0x02, 0x00, 0x00, }; + +static GdkCursor *picker_cursor = NULL; + + +/* XPM */ +static char *picker[] = { + /* columns rows colors chars-per-pixel */ + "25 25 8 1", + " c Gray0", + ". c #020202", + "X c Gray12", + "o c Gray13", + "O c Gray52", + "+ c #929292", + "@ c Gray100", + "# c None", + /* pixels */ + "#########################", + "#########################", + "#########################", + "#########################", + "#########################", + "################# #####", + "################ ####", + "################ +###", + "############# +###", + "############## ++###", + "#############+@ +++####", + "############+@@@ +######", + "###########+@@@ + +######", + "##########+@@@ ++#+######", + "#########+@@@ ++#########", + "########+@@@ ++##########", + "#######+@@@ ++###########", + "######+@@@ ++############", + "######+@@ ++#############", + "#####+@ ++##############", + "###### +++###############", + "#########################", + "#########################", + "#########################", + "#########################" +}; - color_selection_type = gtk_type_unique (GTK_TYPE_VBOX, &colorsel_info); - } - return color_selection_type; -} +/* + * + * The Sample Color + * + */ +#define SAMPLE_WIDTH 64 +#define SAMPLE_HEIGHT 28 + +static void color_sample_draw_sample (GtkColorSelection *colorsel, int which); +static void color_sample_draw_samples (GtkColorSelection *colorsel); static void -gtk_color_selection_class_init (GtkColorSelectionClass *klass) +color_sample_drag_begin (GtkWidget *widget, + GdkDragContext *context, + gpointer data) { - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - GtkContainerClass *container_class; + GtkColorSelection *colorsel = data; + ColorSelectionPrivate *priv; + GtkWidget *window; + gdouble colors[4]; + gdouble *colsrc; + GdkColor bg; + gint n, i; - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - container_class = (GtkContainerClass*) klass; + priv = colorsel->private; + window = gtk_window_new (GTK_WINDOW_POPUP); + gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE); + gtk_widget_set_usize (window, 48, 32); + gtk_widget_realize (window); + gtk_object_set_data_full (GTK_OBJECT (widget), + "gtk-color-selection-drag-window", + window, + (GtkDestroyNotify) gtk_widget_destroy); - color_selection_parent_class = gtk_type_class (GTK_TYPE_VBOX); - - gtk_object_add_arg_type ("GtkColorSelection::policy", GTK_TYPE_UPDATE_TYPE, - GTK_ARG_READWRITE, ARG_UPDATE_POLICY); - gtk_object_add_arg_type ("GtkColorSelection::use_opacity", GTK_TYPE_BOOL, - GTK_ARG_READWRITE, ARG_USE_OPACITY); - - color_selection_signals[COLOR_CHANGED] = - gtk_signal_new ("color_changed", - GTK_RUN_FIRST, - object_class->type, - GTK_SIGNAL_OFFSET (GtkColorSelectionClass, color_changed), - gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); + if (widget == priv->old_sample) + colsrc = priv->old_color; + else + colsrc = priv->color; - gtk_object_class_add_signals (object_class, color_selection_signals, LAST_SIGNAL); + for (i=0, n = COLORSEL_RED; n <= COLORSEL_BLUE; n++) + { + colors[i++] = colsrc[n]; + } + + if (priv->use_opacity) + { + colors[i] = colsrc[COLORSEL_OPACITY]; + } + + bg.red = 0xffff * colors[0]; + bg.green = 0xffff * colors[1]; + bg.blue = 0xffff * colors[2]; - object_class->set_arg = gtk_color_selection_set_arg; - object_class->get_arg = gtk_color_selection_get_arg; - object_class->finalize = gtk_color_selection_finalize; + gdk_color_alloc (gtk_widget_get_colormap (window), &bg); + gdk_window_set_background (window->window, &bg); - widget_class->realize = gtk_color_selection_realize; - widget_class->unrealize = gtk_color_selection_unrealize; + gtk_drag_set_icon_widget (context, window, -2, -2); } static void -gtk_color_selection_init (GtkColorSelection *colorsel) +color_sample_drag_end (GtkWidget *widget, + GdkDragContext *context, + gpointer data) { - GtkWidget *frame, *hbox, *vbox, *hbox2, *label, *table; - GtkObject *adj; - gint old_mask, n; - gchar txt[32]; - - for (n = RED; n <= OPACITY; n++) - colorsel->values[n] = 1.0; - - RGB_TO_HSV (); - - for (n = HUE; n <= OPACITY; n++) - colorsel->old_values[n] = colorsel->values[n]; - - colorsel->wheel_gc = NULL; - colorsel->value_gc = NULL; - colorsel->sample_gc = NULL; - colorsel->wheel_buf = NULL; - colorsel->value_buf = NULL; - colorsel->sample_buf = NULL; - - colorsel->use_opacity = FALSE; - colorsel->timer_active = FALSE; - colorsel->policy = GTK_UPDATE_CONTINUOUS; - - hbox = gtk_hbox_new (FALSE, 5); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - gtk_container_add (GTK_CONTAINER (colorsel), hbox); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_container_add (GTK_CONTAINER (hbox), vbox); - gtk_widget_show (vbox); - - hbox2 = gtk_hbox_new (FALSE, 5); - gtk_container_add (GTK_CONTAINER (vbox), hbox2); - gtk_widget_show (hbox2); - - colorsel->wheel_area = gtk_preview_new (GTK_PREVIEW_COLOR); - old_mask = gtk_widget_get_events(colorsel->wheel_area); - gtk_widget_set_events (colorsel->wheel_area, - old_mask | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK); - gtk_preview_size (GTK_PREVIEW (colorsel->wheel_area), WHEEL_WIDTH, WHEEL_HEIGHT); - gtk_preview_set_expand (GTK_PREVIEW (colorsel->wheel_area), TRUE); - gtk_container_add (GTK_CONTAINER (hbox2), colorsel->wheel_area); - gtk_widget_show (colorsel->wheel_area); - - old_mask = gtk_widget_get_events (colorsel->wheel_area); - - gtk_signal_connect (GTK_OBJECT (colorsel->wheel_area), "event", - (SF) gtk_color_selection_wheel_events, (gpointer) colorsel->wheel_area); - gtk_signal_connect_after (GTK_OBJECT (colorsel->wheel_area), "expose_event", - (SF) gtk_color_selection_wheel_events, (gpointer) colorsel->wheel_area); - gtk_signal_connect_after (GTK_OBJECT (colorsel->wheel_area), "size_allocate", - (SF) gtk_color_selection_wheel_resize, (gpointer) colorsel->wheel_area); - gtk_object_set_data (GTK_OBJECT (colorsel->wheel_area), "_GtkColorSelection", (gpointer) colorsel); + gtk_object_set_data (GTK_OBJECT (widget), "gtk-color-selection-drag-window", NULL); +} - frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); - gtk_container_set_border_width (GTK_CONTAINER (frame), 0); - gtk_box_pack_start (GTK_BOX (hbox2), frame, FALSE, TRUE, 0); - gtk_widget_show (frame); - - colorsel->value_area = gtk_preview_new (GTK_PREVIEW_COLOR); - gtk_preview_size (GTK_PREVIEW (colorsel->value_area), VALUE_WIDTH, VALUE_HEIGHT); - gtk_preview_set_expand (GTK_PREVIEW (colorsel->value_area), TRUE); - gtk_container_add (GTK_CONTAINER (frame), colorsel->value_area); - gtk_widget_show (colorsel->value_area); - - old_mask = gtk_widget_get_events (colorsel->value_area); - gtk_widget_set_events (colorsel->value_area, - old_mask | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK); - - gtk_signal_connect_after (GTK_OBJECT (colorsel->value_area), "expose_event", - (SF) gtk_color_selection_value_events, (gpointer) colorsel->value_area); - gtk_signal_connect_after (GTK_OBJECT (colorsel->value_area), "size_allocate", - (SF) gtk_color_selection_value_resize, (gpointer) colorsel->value_area); - gtk_signal_connect (GTK_OBJECT (colorsel->value_area), "event", - (SF) gtk_color_selection_value_events, (gpointer) colorsel->value_area); - gtk_object_set_data (GTK_OBJECT (colorsel->value_area), "_GtkColorSelection", (gpointer) colorsel); - - /* New/old color samples */ - /* ===================== */ +static void +color_sample_drop_handle (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time, + gpointer data) +{ + GtkColorSelection *colorsel = data; + ColorSelectionPrivate *priv; + guint16 *vals; + gdouble color[4]; + priv = colorsel->private; - frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); - gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); - gtk_widget_show (frame); - -/* colorsel->sample_area_eb = gtk_button_new (); - gtk_container_add (GTK_CONTAINER (frame), colorsel->sample_area_eb); - gtk_widget_show (colorsel->sample_area_eb); */ - - colorsel->sample_area = gtk_preview_new (GTK_PREVIEW_COLOR); - gtk_preview_size (GTK_PREVIEW (colorsel->sample_area), SAMPLE_WIDTH, SAMPLE_HEIGHT); - gtk_preview_set_expand (GTK_PREVIEW (colorsel->sample_area), TRUE); - gtk_container_add (GTK_CONTAINER (frame), - colorsel->sample_area); - gtk_widget_set_events(colorsel->sample_area, - gtk_widget_get_events(colorsel->sample_area) - | GDK_BUTTON_MOTION_MASK - | GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK - | GDK_ENTER_NOTIFY_MASK - | GDK_LEAVE_NOTIFY_MASK); - gtk_widget_show (colorsel->sample_area); - - gtk_signal_connect_after (GTK_OBJECT (colorsel->sample_area), - "size_allocate", - GTK_SIGNAL_FUNC (gtk_color_selection_sample_resize), - colorsel->sample_area); - gtk_object_set_data (GTK_OBJECT (colorsel->sample_area), "_GtkColorSelection", (gpointer) colorsel); - - table = gtk_table_new (NUM_CHANNELS, 3, FALSE); - gtk_table_set_col_spacings (GTK_TABLE (table), 3); - gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, TRUE, 0); - - for (n = HUE; n <= OPACITY; n++) - { - label = gtk_label_new (_(scale_vals[n].label)); - gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); - gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, n, n + 1); - - adj = gtk_adjustment_new (colorsel->values[n], scale_vals[n].lower, - scale_vals[n].upper, scale_vals[n].step_inc, - scale_vals[n].page_inc, 0.0); - colorsel->scales[n] = gtk_hscale_new (GTK_ADJUSTMENT (adj)); - gtk_widget_set_usize (colorsel->scales[n], 128, 0); - gtk_scale_set_value_pos (GTK_SCALE (colorsel->scales[n]), GTK_POS_TOP); - - gtk_range_set_update_policy (GTK_RANGE (colorsel->scales[n]), colorsel->policy); - gtk_scale_set_draw_value (GTK_SCALE (colorsel->scales[n]), FALSE); - gtk_scale_set_digits (GTK_SCALE (colorsel->scales[n]), 2); - gtk_table_attach_defaults (GTK_TABLE (table), colorsel->scales[n], 1, 2, n, n + 1); - - colorsel->entries[n] = gtk_entry_new (); - gtk_widget_set_usize (colorsel->entries[n], 40, 0); - sprintf (txt, "%.2f", colorsel->values[n]); - gtk_entry_set_text (GTK_ENTRY (colorsel->entries[n]), txt); - gtk_table_attach_defaults (GTK_TABLE (table), colorsel->entries[n], 2, 3, n, n + 1); - - if (n != OPACITY) - { - gtk_widget_show (label); - gtk_widget_show (colorsel->scales[n]); - gtk_widget_show (colorsel->entries[n]); - } + /* This is currently a guint16 array of the format: + * R + * G + * B + * opacity + */ - gtk_signal_connect_object (GTK_OBJECT (adj), "value_changed", - scale_vals[n].updater, (gpointer) colorsel->scales[n]); - gtk_object_set_data (GTK_OBJECT (colorsel->scales[n]), "_GtkColorSelection", (gpointer) colorsel); - gtk_object_set_data (GTK_OBJECT (colorsel->scales[n]), value_index_key, GINT_TO_POINTER (n)); - gtk_signal_connect_object (GTK_OBJECT (colorsel->entries[n]), "changed", - scale_vals[n].updater, (gpointer) colorsel->entries[n]); - gtk_object_set_data (GTK_OBJECT (colorsel->entries[n]), "_GtkColorSelection", (gpointer) colorsel); - gtk_object_set_data (GTK_OBJECT (colorsel->entries[n]), value_index_key, GINT_TO_POINTER (n)); + if (selection_data->length < 0) + return; + + if ((selection_data->format != 16) || + (selection_data->length != 8)) + { + g_warning ("Received invalid color data\n"); + return; } - colorsel->opacity_label = label; - - gtk_widget_show (table); - gtk_widget_show (hbox); -} + vals = (guint16 *)selection_data->data; -static void -gtk_color_selection_set_arg (GtkObject *object, - GtkArg *arg, - guint arg_id) -{ - GtkColorSelection *color_selection = GTK_COLOR_SELECTION (object); - - switch (arg_id) + if (widget == priv->cur_sample) { - case ARG_UPDATE_POLICY: - gtk_color_selection_set_update_policy (color_selection, GTK_VALUE_ENUM (*arg)); - break; - case ARG_USE_OPACITY: - gtk_color_selection_set_opacity (color_selection, GTK_VALUE_BOOL (*arg)); - break; + color[0] = (gdouble)vals[0] / 0xffff; + color[1] = (gdouble)vals[1] / 0xffff; + color[2] = (gdouble)vals[2] / 0xffff; + color[3] = (gdouble)vals[3] / 0xffff; + + gtk_color_selection_set_color (colorsel, color); } } static void -gtk_color_selection_get_arg (GtkObject *object, - GtkArg *arg, - guint arg_id) +color_sample_drag_handle (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time, + gpointer data) { - GtkColorSelection *color_selection; - - color_selection = GTK_COLOR_SELECTION (object); - - switch (arg_id) - { - case ARG_UPDATE_POLICY: - GTK_VALUE_ENUM (*arg) = color_selection->policy; - break; - case ARG_USE_OPACITY: - GTK_VALUE_BOOL (*arg) = color_selection->use_opacity; - break; - default: - break; - } -} + GtkColorSelection *colorsel = data; + ColorSelectionPrivate *priv; + guint16 vals[4]; + gdouble *colsrc; -GtkWidget* -gtk_color_selection_new (void) -{ - GtkColorSelection *colorsel; + priv = colorsel->private; - colorsel = gtk_type_new (GTK_TYPE_COLOR_SELECTION); + if (widget == priv->old_sample) + colsrc = priv->old_color; + else + colsrc = priv->color; - return GTK_WIDGET (colorsel); + vals[0] = colsrc[COLORSEL_RED] * 0xffff; + vals[1] = colsrc[COLORSEL_GREEN] * 0xffff; + vals[2] = colsrc[COLORSEL_BLUE] * 0xffff; + vals[3] = priv->use_opacity ? colsrc[COLORSEL_OPACITY] * 0xffff : 0xffff; + + gtk_selection_data_set (selection_data, + gdk_atom_intern ("application/x-color", FALSE), + 16, (guchar *)vals, 8); } -void -gtk_color_selection_set_update_policy (GtkColorSelection *colorsel, - GtkUpdateType policy) +/* which = 0 means draw old sample, which = 1 means draw new */ +static void +color_sample_draw_sample (GtkColorSelection *colorsel, int which) { - gint n; + GtkWidget *da; + gint x, y, i, wid, heig, f, n, goff; + guchar c[3 * 2], cc[3 * 4], *cp = c; + gdouble o; + guchar *buf; + ColorSelectionPrivate *priv; g_return_if_fail (colorsel != NULL); + priv = colorsel->private; - if (policy != colorsel->policy) - { - colorsel->policy = policy; + g_return_if_fail (priv->sample_area != NULL); + if (!GTK_WIDGET_DRAWABLE (priv->sample_area)) + return; - for (n = 0; n < NUM_CHANNELS; n++) - gtk_range_set_update_policy (GTK_RANGE (colorsel->scales[n]), policy); + if (which == 0) + { + da = priv->old_sample; + for (n = 0, i = COLORSEL_RED; n < 3; n++, i++) + c[n] = (guchar) (255.0 * priv->old_color[i]); + goff = 0; + } + else + { + da = priv->cur_sample; + for (n = 0, i = COLORSEL_RED; n < 3; n++, i++) + c[n] = (guchar) (255.0 * priv->color[i]); + goff = priv->old_sample->allocation.width % 32; } -} - -void -gtk_color_selection_set_color (GtkColorSelection *colorsel, - gdouble *color) -{ - gint n, i = 0; + wid = da->allocation.width; + heig = da->allocation.height; - g_return_if_fail (colorsel != NULL); - g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); + buf = g_new(guchar, 3 * wid * heig); - if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (colorsel))) - gtk_color_selection_draw_wheel_marker (colorsel); +#if 0 + i = COLORSEL_RED; + for (n = 0; n < 3; n++) + { + c[n] = (guchar) (255.0 * priv->old_color[i]); + c[n + 3] = (guchar) (255.0 * priv->color[i++]); + } +#endif - for (n = RED; n <= BLUE; n++) + if (priv->use_opacity) { - colorsel->old_values[n] = colorsel->values[n]; - colorsel->values[n] = color[i++]; + o = (which) ? priv->color[COLORSEL_OPACITY] : priv->old_color[COLORSEL_OPACITY]; + + for (n = 0; n < 3; n++) + { + cc[n] = (guchar) ((1.0 - o) * 192 + (o * (gdouble) c[n])); + cc[n + 3] = (guchar) ((1.0 - o) * 128 + (o * (gdouble) c[n])); + } + cp = cc; } - if (colorsel->use_opacity) + i = 0; + for (y = 0; y < heig; y++) { - colorsel->old_values[OPACITY] = colorsel->values[OPACITY]; - colorsel->values[OPACITY] = color[i]; + for (x = 0; x < wid; x++) + { + if (priv->use_opacity) + f = 3 * ((((goff + x) % 32) < 16) ^ ((y % 32) < 16)); + else + f = 0; + + for (n = 0; n < 3; n++) + buf[i++] = cp[n + f]; + } } - RGB_TO_HSV (); + gdk_draw_rgb_image(da->window, + da->style->black_gc, + 0, 0, + wid, heig, + GDK_RGB_DITHER_NORMAL, + buf, + 3*wid); - gtk_color_selection_update_inputs (colorsel, RGB_INPUTS | HSV_INPUTS | OPACITY_INPUTS, BOTH); - if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (colorsel))) - { - gtk_color_selection_draw_value_bar (colorsel, FALSE); - gtk_color_selection_draw_sample (colorsel, FALSE); - gtk_color_selection_draw_wheel_marker (colorsel); - } + g_free (buf); + } -void -gtk_color_selection_get_color (GtkColorSelection *colorsel, - gdouble *color) -{ - gint n, i = 0; - g_return_if_fail (colorsel != NULL); - g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); +static void +color_sample_draw_samples (GtkColorSelection *colorsel) +{ + color_sample_draw_sample (colorsel, 0); + color_sample_draw_sample (colorsel, 1); +} - for (n = RED; n <= BLUE; n++) - color[i++] = colorsel->values[n]; - if (colorsel->use_opacity) - color[i] = colorsel->values[OPACITY]; +static void +color_old_sample_expose(GtkWidget* da, GdkEventExpose* event, GtkColorSelection *colorsel) +{ + color_sample_draw_sample (colorsel, 0); } + static void -gtk_color_selection_realize (GtkWidget *widget) +color_cur_sample_expose(GtkWidget* da, GdkEventExpose* event, GtkColorSelection *colorsel) { - GtkColorSelection *colorsel; + color_sample_draw_sample (colorsel, 1); +} +static void +color_sample_setup_dnd (GtkColorSelection *colorsel, GtkWidget *sample) +{ static const GtkTargetEntry targets[] = { { "application/x-color", 0 } }; + ColorSelectionPrivate *priv; + priv = colorsel->private; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_COLOR_SELECTION (widget)); - - colorsel = GTK_COLOR_SELECTION (widget); - - if (GTK_WIDGET_CLASS (color_selection_parent_class)->realize) - (*GTK_WIDGET_CLASS (color_selection_parent_class)->realize) (widget); - - gtk_drag_dest_set (colorsel->sample_area, - GTK_DEST_DEFAULT_HIGHLIGHT | - GTK_DEST_DEFAULT_MOTION | - GTK_DEST_DEFAULT_DROP, - targets, 1, - GDK_ACTION_COPY); - - gtk_drag_source_set (colorsel->sample_area, + gtk_drag_source_set (sample, GDK_BUTTON1_MASK | GDK_BUTTON3_MASK, targets, 1, GDK_ACTION_COPY | GDK_ACTION_MOVE); - gtk_signal_connect (GTK_OBJECT (colorsel->sample_area), + gtk_signal_connect (GTK_OBJECT (sample), "drag_begin", - GTK_SIGNAL_FUNC (gtk_color_selection_drag_begin), - colorsel); - gtk_signal_connect (GTK_OBJECT (colorsel->sample_area), - "drag_end", - GTK_SIGNAL_FUNC (gtk_color_selection_drag_end), + GTK_SIGNAL_FUNC (color_sample_drag_begin), colorsel); - gtk_signal_connect (GTK_OBJECT (colorsel->sample_area), + if (sample == priv->cur_sample) + { + + gtk_drag_dest_set (sample, + GTK_DEST_DEFAULT_HIGHLIGHT | + GTK_DEST_DEFAULT_MOTION | + GTK_DEST_DEFAULT_DROP, + targets, 1, + GDK_ACTION_COPY); + + gtk_signal_connect (GTK_OBJECT (sample), + "drag_end", + GTK_SIGNAL_FUNC (color_sample_drag_end), + colorsel); + } + + gtk_signal_connect (GTK_OBJECT (sample), "drag_data_get", - GTK_SIGNAL_FUNC (gtk_color_selection_drag_handle), + GTK_SIGNAL_FUNC (color_sample_drag_handle), colorsel); - gtk_signal_connect (GTK_OBJECT (colorsel->sample_area), + gtk_signal_connect (GTK_OBJECT (sample), "drag_data_received", - GTK_SIGNAL_FUNC (gtk_color_selection_drop_handle), + GTK_SIGNAL_FUNC (color_sample_drop_handle), colorsel); + } + static void -gtk_color_selection_unrealize (GtkWidget *widget) +color_sample_new (GtkColorSelection *colorsel) { - GtkColorSelection *colorsel; + ColorSelectionPrivate *priv; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_COLOR_SELECTION (widget)); + priv = colorsel->private; - colorsel = GTK_COLOR_SELECTION (widget); - - if (colorsel->value_gc != NULL) - { - gdk_gc_unref (colorsel->value_gc); - colorsel->value_gc = NULL; - } - if (colorsel->wheel_gc != NULL) - { - gdk_gc_unref (colorsel->wheel_gc); - colorsel->wheel_gc = NULL; - } - if (colorsel->sample_gc != NULL) - { - gdk_gc_unref (colorsel->sample_gc); - colorsel->sample_gc = NULL; - } + gtk_widget_push_visual(gdk_rgb_get_visual()); + gtk_widget_push_colormap(gdk_rgb_get_cmap()); - (* GTK_WIDGET_CLASS (color_selection_parent_class)->unrealize) (widget); -} + priv->sample_area = gtk_hbox_new (FALSE, 0); + priv->old_sample = gtk_drawing_area_new (); + priv->cur_sample = gtk_drawing_area_new (); -static void -gtk_color_selection_finalize (GtkObject *object) -{ - GtkColorSelection *colorsel; + gtk_box_pack_start (GTK_BOX (priv->sample_area), priv->old_sample, + TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (priv->sample_area), priv->cur_sample, + TRUE, TRUE, 0); + gtk_widget_pop_visual(); + gtk_widget_pop_colormap(); - g_return_if_fail (object != NULL); - g_return_if_fail (GTK_IS_COLOR_SELECTION (object)); + gtk_signal_connect(GTK_OBJECT (priv->old_sample), "expose_event", + GTK_SIGNAL_FUNC (color_old_sample_expose), + colorsel); + gtk_signal_connect(GTK_OBJECT (priv->cur_sample), "expose_event", + GTK_SIGNAL_FUNC (color_cur_sample_expose), + colorsel); - colorsel = GTK_COLOR_SELECTION (object); + color_sample_setup_dnd (colorsel, priv->old_sample); + color_sample_setup_dnd (colorsel, priv->cur_sample); - if (colorsel->wheel_buf != NULL) - g_free (colorsel->wheel_buf); - if (colorsel->value_buf != NULL) - g_free (colorsel->value_buf); - if (colorsel->sample_buf != NULL) - g_free (colorsel->sample_buf); - - (*GTK_OBJECT_CLASS (color_selection_parent_class)->finalize) (object); + gtk_widget_show_all (priv->sample_area); } static void -gtk_color_selection_color_changed (GtkColorSelection *colorsel) +color_sample_set_use_opacity (GtkColorSelection *colorsel) { - gtk_signal_emit (GTK_OBJECT (colorsel), color_selection_signals[COLOR_CHANGED]); -} + ColorSelectionPrivate *priv; -static void -gtk_color_selection_update_input (GtkWidget *scale, - GtkWidget *entry, - gdouble value) -{ - GtkAdjustment *adj; - gchar txt[32]; + g_return_if_fail (colorsel != NULL); - if (scale != NULL) - { - adj = gtk_range_get_adjustment (GTK_RANGE (scale)); - adj->value = (gfloat) value; - gtk_signal_handler_block_by_data (GTK_OBJECT (adj), (gpointer) scale); - gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed"); - gtk_range_slider_update (GTK_RANGE (scale)); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), (gpointer) scale); - } + priv = colorsel->private; - if (entry != NULL) - { - gtk_signal_handler_block_by_data (GTK_OBJECT (entry), (gpointer) entry); - sprintf (txt, "%.2f", value); - gtk_entry_set_text (GTK_ENTRY (entry), txt); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (entry), (gpointer) entry); - } + color_sample_draw_samples (colorsel); } + +/* + * + * The palette area code + * + */ +#define CUSTOM_PALETTE_ENTRY_WIDTH 18 +#define CUSTOM_PALETTE_ENTRY_HEIGHT 18 + static void -gtk_color_selection_update_inputs (GtkColorSelection *colorsel, - gint inputs, - gint which) +palette_get_color (GtkWidget *drawing_area, gdouble *color) { - gint n; + gdouble *color_val; + + g_return_if_fail (color != NULL); - switch (which) + color_val = gtk_object_get_data (GTK_OBJECT (drawing_area), "color_val"); + if (color_val == NULL) { - case SCALE: - if ((inputs & RGB_INPUTS) != 0) - for (n = RED; n <= BLUE; n++) - gtk_color_selection_update_input (colorsel->scales[n], NULL, - colorsel->values[n]); - if ((inputs & HSV_INPUTS) != 0) - for (n = HUE; n <= VALUE; n++) - gtk_color_selection_update_input (colorsel->scales[n], NULL, - colorsel->values[n]); - if ((inputs & OPACITY_INPUTS) != 0) - gtk_color_selection_update_input(colorsel->scales[OPACITY], NULL, - colorsel->values[OPACITY]); - break; - case ENTRY: - if ((inputs & RGB_INPUTS) != 0) - for (n = RED; n <= BLUE; n++) - gtk_color_selection_update_input (NULL, colorsel->entries[n], colorsel->values[n]); - if ((inputs & HSV_INPUTS) != 0) - for (n = HUE; n <= VALUE; n++) - gtk_color_selection_update_input (NULL, colorsel->entries[n], colorsel->values[n]); - if ((inputs & OPACITY_INPUTS) != 0) - gtk_color_selection_update_input(NULL, colorsel->entries[OPACITY], colorsel->values[OPACITY]); - break; - default: - if ((inputs & RGB_INPUTS) != 0) - for (n = RED; n <= BLUE; n++) - gtk_color_selection_update_input (colorsel->scales[n], colorsel->entries[n], - colorsel->values[n]); - if ((inputs & HSV_INPUTS) != 0) - for (n = HUE; n <= VALUE; n++) - gtk_color_selection_update_input (colorsel->scales[n], colorsel->entries[n], - colorsel->values[n]); - if ((inputs & OPACITY_INPUTS) != 0) - gtk_color_selection_update_input(colorsel->scales[OPACITY], colorsel->entries[OPACITY], - colorsel->values[OPACITY]); - break; + /* Default to white for no good reason */ + color[0] = 1.0; + color[1] = 1.0; + color[2] = 1.0; + color[3] = 1.0; + return; } + + color[0] = color_val[0]; + color[1] = color_val[1]; + color[2] = color_val[2]; + color[3] = 1.0; } +#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11) static void -gtk_color_selection_hsv_updater (GtkWidget *widget, - gpointer data) +palette_paint (GtkWidget *drawing_area, GdkRectangle *area, gpointer data) { - GtkColorSelection *colorsel; - GtkAdjustment *adj; - gdouble newvalue; - gint i, which = SCALE; - - if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (widget))) - { - colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); - i = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), value_index_key)); + if (drawing_area->window == NULL) + return; - if (GTK_IS_SCALE (widget)) - { - adj = gtk_range_get_adjustment (GTK_RANGE (GTK_SCALE (widget))); - newvalue = (gdouble) adj->value; - which = ENTRY; - } - else - newvalue = (gdouble) atof (gtk_entry_get_text (GTK_ENTRY (widget))); + gdk_window_clear_area (drawing_area->window, + area->x, + area->y, + area->width, + area->height); - if (i == VALUE) - { - gtk_color_selection_draw_value_marker (colorsel); - colorsel->values[i] = newvalue; + if (GTK_WIDGET_HAS_FOCUS (drawing_area)) + { + GdkGC *gc; + gdouble color[4]; - HSV_TO_RGB (); + palette_get_color (drawing_area, color); - gtk_color_selection_draw_value_marker (colorsel); - } + if (INTENSITY (color[0], color[1], color[2]) > 0.5) + gc = drawing_area->style->black_gc; else - { - gtk_color_selection_draw_wheel_marker (colorsel); - colorsel->values[i] = newvalue; + gc = drawing_area->style->white_gc; - HSV_TO_RGB (); - - gtk_color_selection_draw_wheel_marker (colorsel); - gtk_color_selection_draw_value_bar (colorsel, FALSE); - } - - gtk_color_selection_draw_sample (colorsel, FALSE); - gtk_color_selection_color_changed (colorsel); - gtk_color_selection_update_inputs (colorsel, HSV_INPUTS, which); - gtk_color_selection_update_inputs (colorsel, RGB_INPUTS, BOTH); + gdk_draw_rectangle (drawing_area->window, + gc, FALSE, 0, 0, + drawing_area->allocation.width - 1, + drawing_area->allocation.height - 1); } } static void -gtk_color_selection_rgb_updater (GtkWidget *widget, - gpointer data) +palette_expose (GtkWidget *drawing_area, GdkEventExpose *event, gpointer data) { - GtkColorSelection *colorsel; - GtkAdjustment *adj; - gdouble newvalue; - gint i, which = SCALE; - - if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (widget))) - { - colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); - i = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), value_index_key)); - - if (GTK_IS_SCALE (widget)) - { - adj = gtk_range_get_adjustment (GTK_RANGE (GTK_SCALE (widget))); - newvalue = (gdouble) adj->value; - which = ENTRY; - } - else - newvalue = (gdouble) atof (gtk_entry_get_text (GTK_ENTRY (widget))); - - gtk_color_selection_draw_wheel_marker (colorsel); - - colorsel->values[i] = newvalue; - RGB_TO_HSV (); + if (drawing_area->window == NULL) + return; - gtk_color_selection_draw_wheel_marker (colorsel); - gtk_color_selection_draw_value_bar (colorsel, FALSE); - gtk_color_selection_draw_sample (colorsel, FALSE); - gtk_color_selection_color_changed (colorsel); - gtk_color_selection_update_inputs (colorsel, RGB_INPUTS, which); - gtk_color_selection_update_inputs (colorsel, HSV_INPUTS, BOTH); - } + palette_paint (drawing_area, &(event->area), data); } static void -gtk_color_selection_opacity_updater (GtkWidget *widget, - gpointer data) +palette_focus_in (GtkWidget *drawing_area, GdkEventFocus *event, gpointer data) { - GtkColorSelection *colorsel; - GtkAdjustment *adj; + ColorSelectionPrivate *priv; - colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); - - if (GTK_IS_SCALE (widget)) - { - adj = gtk_range_get_adjustment (GTK_RANGE (widget)); - colorsel->values[OPACITY] = (gdouble) adj->value; - gtk_color_selection_update_input (NULL, colorsel->entries[OPACITY], colorsel->values[OPACITY]); - } - else - { - colorsel->values[OPACITY] = (gdouble) atof (gtk_entry_get_text (GTK_ENTRY (widget))); - gtk_color_selection_update_input (colorsel->scales[OPACITY], NULL, colorsel->values[OPACITY]); - } + if (drawing_area->window == NULL) + return; - gtk_color_selection_draw_sample (colorsel, FALSE); - gtk_color_selection_color_changed (colorsel); + priv = GTK_COLOR_SELECTION (data)->private; + priv->last_palette = drawing_area; + GTK_WIDGET_SET_FLAGS (drawing_area, GTK_HAS_FOCUS); + + gtk_widget_queue_clear_area (drawing_area, 0, 0, drawing_area->allocation.x, drawing_area->allocation.y); } -void -gtk_color_selection_set_opacity (GtkColorSelection *colorsel, - gint use_opacity) +static void +palette_focus_out (GtkWidget *drawing_area, GdkEventFocus *event, gpointer data) { - g_return_if_fail (colorsel != NULL); - - colorsel->use_opacity = use_opacity; - - if (!use_opacity && GTK_WIDGET_VISIBLE (colorsel->scales[OPACITY])) - { - gtk_widget_hide (colorsel->opacity_label); - gtk_widget_hide (colorsel->scales[OPACITY]); - gtk_widget_hide (colorsel->entries[OPACITY]); - } - else if (use_opacity && !GTK_WIDGET_VISIBLE (colorsel->scales[OPACITY])) - { - gtk_widget_show (colorsel->opacity_label); - gtk_widget_show (colorsel->scales[OPACITY]); - gtk_widget_show (colorsel->entries[OPACITY]); - } - - if (GTK_WIDGET_DRAWABLE (colorsel->sample_area)) - gtk_color_selection_draw_sample (colorsel, FALSE); + GTK_WIDGET_UNSET_FLAGS (drawing_area, GTK_HAS_FOCUS); + gtk_widget_queue_clear_area (drawing_area, 0, 0, drawing_area->allocation.x, drawing_area->allocation.y); } static void -gtk_color_selection_value_resize (GtkWidget *widget, - gpointer data) +palette_press (GtkWidget *drawing_area, GdkEventButton *event, gpointer data) { - GtkColorSelection *colorsel; - - colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); - gtk_color_selection_draw_value_bar (colorsel, TRUE); + gtk_widget_grab_focus (drawing_area); + if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (drawing_area), "color_set")) != 0) + { + gdouble color[4]; + palette_get_color (drawing_area, color); + gtk_color_selection_set_color (GTK_COLOR_SELECTION (data), color); + } } static void -gtk_color_selection_wheel_resize (GtkWidget *widget, - gpointer data) +palette_draw (GtkWidget *drawing_area, GdkRectangle *area, gpointer data) { - GtkColorSelection *colorsel; - - colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); - gtk_color_selection_draw_wheel (colorsel, TRUE); + palette_paint (drawing_area, area, data); } static void -gtk_color_selection_sample_resize (GtkWidget *widget, - gpointer data) +palette_unset_color (GtkWidget *drawing_area) { - GtkColorSelection *colorsel; + if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (drawing_area), "color_set")) == 0) + return; - colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); - gtk_color_selection_draw_sample (colorsel, TRUE); + gtk_widget_reset_rc_styles (drawing_area); + gtk_object_set_data (GTK_OBJECT (drawing_area), "color_set", GINT_TO_POINTER (0)); } static void -gtk_color_selection_drag_begin (GtkWidget *widget, - GdkDragContext *context, - gpointer data) +palette_drag_begin (GtkWidget *widget, + GdkDragContext *context, + gpointer data) { GtkColorSelection *colorsel = data; + ColorSelectionPrivate *priv; GtkWidget *window; gdouble colors[4]; GdkColor bg; + priv = colorsel->private; window = gtk_window_new (GTK_WINDOW_POPUP); gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE); gtk_widget_set_usize (window, 48, 32); @@ -942,7 +671,7 @@ gtk_color_selection_drag_begin (GtkWidget *widget, window, (GtkDestroyNotify) gtk_widget_destroy); - gtk_color_selection_get_color (colorsel, colors); + palette_get_color (widget, colors); bg.red = 0xffff * colors[0]; bg.green = 0xffff * colors[1]; bg.blue = 0xffff * colors[2]; @@ -954,803 +683,1157 @@ gtk_color_selection_drag_begin (GtkWidget *widget, } static void -gtk_color_selection_drag_end (GtkWidget *widget, - GdkDragContext *context, - gpointer data) +palette_drag_handle (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time, + gpointer data) +{ + guint16 vals[4]; + gdouble colsrc[4]; + + palette_get_color (widget, colsrc); + + vals[0] = colsrc[COLORSEL_RED] * 0xffff; + vals[1] = colsrc[COLORSEL_GREEN] * 0xffff; + vals[2] = colsrc[COLORSEL_BLUE] * 0xffff; + vals[3] = 0xffff; + + gtk_selection_data_set (selection_data, + gdk_atom_intern ("application/x-color", FALSE), + 16, (guchar *)vals, 8); +} + +static void +palette_set_color (GtkWidget *drawing_area, GtkColorSelection *colorsel, gdouble *color) +{ + GtkRcStyle *rc_style; + gdouble *new_color = g_new (double, 4); + gdouble *old_color; + + rc_style = gtk_rc_style_new (); + rc_style->bg[GTK_STATE_NORMAL].red = color[0]*65535; + rc_style->bg[GTK_STATE_NORMAL].green = color[1]*65535; + rc_style->bg[GTK_STATE_NORMAL].blue = color[2]*65535; + rc_style->color_flags[GTK_STATE_NORMAL] = GTK_RC_BG; + gtk_rc_style_ref (rc_style); + gtk_widget_modify_style (drawing_area, rc_style); + + if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (drawing_area), "color_set")) == 0) + { + static const GtkTargetEntry targets[] = { + { "application/x-color", 0 } + }; + gtk_drag_source_set (drawing_area, + GDK_BUTTON1_MASK | GDK_BUTTON3_MASK, + targets, 1, + GDK_ACTION_COPY | GDK_ACTION_MOVE); + + gtk_signal_connect (GTK_OBJECT (drawing_area), + "drag_begin", + GTK_SIGNAL_FUNC (palette_drag_begin), + colorsel); + gtk_signal_connect (GTK_OBJECT (drawing_area), + "drag_data_get", + GTK_SIGNAL_FUNC (palette_drag_handle), + colorsel); + + gtk_object_set_data (GTK_OBJECT (drawing_area), "color_set", GINT_TO_POINTER (1)); + } + else + { + old_color = (gdouble *) gtk_object_get_data (GTK_OBJECT (drawing_area), "color_val"); + if (old_color) + { + g_free (old_color); + } + } + new_color[0] = color[0]; + new_color[1] = color[1]; + new_color[2] = color[2]; + new_color[3] = 1.0; + + gtk_object_set_data (GTK_OBJECT (drawing_area), "color_val", new_color); +} + +static void +palette_drag_end (GtkWidget *widget, + GdkDragContext *context, + gpointer data) { gtk_object_set_data (GTK_OBJECT (widget), "gtk-color-selection-drag-window", NULL); } static void -gtk_color_selection_drop_handle (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection_data, - guint info, - guint time, - gpointer data) +palette_drop_handle (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time, + gpointer data) { - GtkColorSelection *colorsel = data; guint16 *vals; - gdouble colors[4]; - - /* This is currently a guint16 array of the format: - R - G - B - opacity - */ + gdouble color[4]; if (selection_data->length < 0) return; - if ((selection_data->format != 16) || + if ((selection_data->format != 16) || (selection_data->length != 8)) { g_warning ("Received invalid color data\n"); return; } - + vals = (guint16 *)selection_data->data; - colors[0] = (gdouble)vals[0] / 0xffff; - colors[1] = (gdouble)vals[1] / 0xffff; - colors[2] = (gdouble)vals[2] / 0xffff; - colors[3] = (gdouble)vals[3] / 0xffff; - - gtk_color_selection_set_color(colorsel, colors); + color[0] = (gdouble)vals[0] / 0xffff; + color[1] = (gdouble)vals[1] / 0xffff; + color[2] = (gdouble)vals[2] / 0xffff; + color[3] = (gdouble)vals[3] / 0xffff; + palette_set_color (widget, GTK_COLOR_SELECTION (data), color); + gtk_color_selection_set_color (GTK_COLOR_SELECTION (data), color); } -static void -gtk_color_selection_drag_handle (GtkWidget *widget, - GdkDragContext *context, - GtkSelectionData *selection_data, - guint info, - guint time, - gpointer data) +static int +palette_activate (GtkWidget *widget, + GdkEventKey *event, + gpointer data) { GtkColorSelection *colorsel = data; - guint16 vals[4]; - gdouble colors[4]; + ColorSelectionPrivate *priv; - gtk_color_selection_get_color(colorsel, colors); + if ((event->keyval == ' ') || (event->keyval == GDK_Return)) + { + priv = colorsel->private; + palette_set_color (widget, GTK_COLOR_SELECTION (data), priv->color); + } - vals[0] = colors[0] * 0xffff; - vals[1] = colors[1] * 0xffff; - vals[2] = colors[2] * 0xffff; - vals[3] = colorsel->use_opacity ? colors[3] * 0xffff : 0xffff; + return TRUE; +} - gtk_selection_data_set (selection_data, - gdk_atom_intern ("application/x-color", FALSE), - 16, (guchar *)vals, 8); +static GtkWidget * +palette_new (GtkColorSelection *colorsel) +{ + GtkWidget *retval; + + static const GtkTargetEntry targets[] = { + { "application/x-color", 0 } + }; + + retval = gtk_drawing_area_new (); + gtk_object_set_data (GTK_OBJECT (retval), "color_set", GINT_TO_POINTER (0)); + gtk_widget_set_events (retval, GDK_BUTTON_PRESS_MASK | GDK_EXPOSURE_MASK); + + GTK_WIDGET_SET_FLAGS (retval, GTK_CAN_FOCUS); + gtk_signal_connect (GTK_OBJECT (retval), "focus_in_event", palette_focus_in, colorsel); + gtk_signal_connect (GTK_OBJECT (retval), "focus_out_event", palette_focus_out, colorsel); + gtk_signal_connect (GTK_OBJECT (retval), "draw", palette_draw, colorsel); + gtk_signal_connect (GTK_OBJECT (retval), "expose_event", palette_expose, colorsel); + gtk_signal_connect (GTK_OBJECT (retval), "button_press_event", palette_press, colorsel); + + gtk_drag_dest_set (retval, + GTK_DEST_DEFAULT_HIGHLIGHT | + GTK_DEST_DEFAULT_MOTION | + GTK_DEST_DEFAULT_DROP, + targets, 1, + GDK_ACTION_COPY); + + gtk_signal_connect (GTK_OBJECT (retval), "drag_end", palette_drag_end, NULL); + gtk_signal_connect (GTK_OBJECT (retval), "drag_data_received", palette_drop_handle, colorsel); + gtk_signal_connect (GTK_OBJECT (retval), "key_press_event", GTK_SIGNAL_FUNC (palette_activate), colorsel); + + return retval; } + +/* + * + * The actual GtkColorSelection widget + * + */ + static void -gtk_color_selection_draw_wheel_marker (GtkColorSelection *colorsel) +initialize_cursor () { - gint xpos, ypos; + GdkColor fg, bg; + + GdkPixmap *pixmap = + gdk_bitmap_create_from_data (NULL, + dropper_bits, + DROPPER_WIDTH, DROPPER_HEIGHT); + GdkPixmap *mask = + gdk_bitmap_create_from_data (NULL, + dropper_mask, + DROPPER_WIDTH, DROPPER_HEIGHT); + + gdk_color_white (gdk_colormap_get_system (), &bg); + gdk_color_black (gdk_colormap_get_system (), &fg); - gdk_gc_set_function (colorsel->wheel_gc, GDK_INVERT); + picker_cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, DROPPER_X_HOT ,DROPPER_Y_HOT); - xpos = (gint) ((-(gdouble) (colorsel->wheel_area->allocation.width) / 2.0) * - colorsel->values[SATURATION] * cos (DEGTORAD ((colorsel->values[HUE] - 90)))) + - (colorsel->wheel_area->allocation.width >> 1) - 4; - ypos = (gint) (((gdouble) (colorsel->wheel_area->allocation.height) / 2.0) * - colorsel->values[SATURATION] * sin (DEGTORAD ((colorsel->values[HUE] - 90)))) + - (colorsel->wheel_area->allocation.height >> 1) - 4; + gdk_pixmap_unref (pixmap); + gdk_pixmap_unref (mask); - gdk_draw_arc (colorsel->wheel_area->window, colorsel->wheel_gc, FALSE, xpos, ypos, 8, 8, 0, 360 * 64); } static void -gtk_color_selection_draw_value_marker (GtkColorSelection *colorsel) +grab_color_at_mouse (GtkWidget *button, int x_root, int y_root, gpointer data) { - gint y; - - gdk_gc_set_function (colorsel->value_gc, GDK_INVERT); + GdkImage *image; + guint32 pixel; + GdkVisual *visual; + GtkColorSelection *colorsel = data; + ColorSelectionPrivate *priv; + GdkColormap *colormap = gdk_colormap_get_system (); + XColor xcolor; + + priv = colorsel->private; + + image = gdk_image_get (GDK_ROOT_PARENT (), x_root, y_root, 1, 1); + pixel = gdk_image_get_pixel (image, 0, 0); + visual = gdk_colormap_get_visual (colormap); + + switch (visual->type) { + case GDK_VISUAL_DIRECT_COLOR: + case GDK_VISUAL_TRUE_COLOR: + priv->color[COLORSEL_RED] = (double)((pixel & visual->red_mask)>>visual->red_shift)/((1<<visual->red_prec) - 1); + priv->color[COLORSEL_GREEN] = (double)((pixel & visual->green_mask)>>visual->green_shift)/((1<<visual->green_prec) - 1); + priv->color[COLORSEL_BLUE] = (double)((pixel & visual->blue_mask)>>visual->blue_shift)/((1<<visual->blue_prec) - 1); + break; + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_GRAYSCALE: + priv->color[COLORSEL_RED] = (double)pixel/((1<<visual->depth) - 1); + priv->color[COLORSEL_GREEN] = (double)pixel/((1<<visual->depth) - 1); + priv->color[COLORSEL_BLUE] = (double)pixel/((1<<visual->depth) - 1); + break; + case GDK_VISUAL_STATIC_COLOR: + xcolor.pixel = pixel; + XQueryColor (GDK_DISPLAY (), GDK_COLORMAP_XCOLORMAP (colormap), &xcolor); + priv->color[COLORSEL_RED] = xcolor.red/65535.0; + priv->color[COLORSEL_GREEN] = xcolor.green/65535.0; + priv->color[COLORSEL_BLUE] = xcolor.blue/65535.0; + break; + case GDK_VISUAL_PSEUDO_COLOR: + priv->color[COLORSEL_RED] = colormap->colors[pixel].red/(double)0xffffff; + priv->color[COLORSEL_GREEN] = colormap->colors[pixel].green/(double)0xffffff; + priv->color[COLORSEL_BLUE] = colormap->colors[pixel].blue/(double)0xffffff; + break; + default: + g_assert_not_reached (); + break; + } + + gtk_rgb_to_hsv (priv->color[COLORSEL_RED], + priv->color[COLORSEL_GREEN], + priv->color[COLORSEL_BLUE], + &priv->color[COLORSEL_HUE], + &priv->color[COLORSEL_SATURATION], + &priv->color[COLORSEL_VALUE]); + update_color (colorsel); +} - y = (gint) ((gdouble) (colorsel->value_area->allocation.height) * (1.0 - colorsel->values[VALUE])); - gdk_draw_line (colorsel->value_area->window, colorsel->value_gc, - 0, y, colorsel->value_area->allocation.width, y); +static void +mouse_motion (GtkWidget *button, GdkEventMotion *event, gpointer data) +{ + grab_color_at_mouse (button, event->x_root, event->y_root, data); } static void -gtk_color_selection_update_value (GtkColorSelection *colorsel, - gint y) +mouse_release (GtkWidget *button, GdkEventButton *event, gpointer data) { - gtk_color_selection_draw_value_marker (colorsel); + GtkColorSelection *colorsel = data; + ColorSelectionPrivate *priv; + priv = colorsel->private; - if (y < 0) - y = 0; - else if (y > colorsel->value_area->allocation.height - 1) - y = colorsel->value_area->allocation.height - 1; + gtk_signal_disconnect_by_func (GTK_OBJECT (button), mouse_motion, data); + gtk_signal_disconnect_by_func (GTK_OBJECT (button), mouse_release, data); - colorsel->values[VALUE] = 1.0 - (gdouble) y / (gdouble) (colorsel->value_area->allocation.height); + grab_color_at_mouse (button, event->x_root, event->y_root, data); + gdk_pointer_ungrab (0); +} - HSV_TO_RGB (); +/* Helper Functions */ +static void +mouse_press (GtkWidget *button, GdkEventButton *event, gpointer data) +{ + GtkColorSelection *colorsel = data; + ColorSelectionPrivate *priv; + priv = colorsel->private; - gtk_color_selection_draw_value_marker (colorsel); - gtk_color_selection_draw_sample (colorsel, FALSE); - gtk_color_selection_update_input (colorsel->scales[VALUE], colorsel->entries[VALUE], - colorsel->values[VALUE]); - gtk_color_selection_update_inputs (colorsel, RGB_INPUTS, BOTH); + gtk_signal_connect (GTK_OBJECT (button), "motion_notify_event", mouse_motion, data); + gtk_signal_connect (GTK_OBJECT (button), "button_release_event", mouse_release, data); + gtk_signal_disconnect_by_func (GTK_OBJECT (button), mouse_press, data); } +/* when the button is clicked */ static void -gtk_color_selection_update_wheel (GtkColorSelection *colorsel, - gint x, - gint y) +get_screen_color (GtkWidget *button) { - gdouble wid, heig; - gint res; + GtkColorSelection *colorsel = gtk_object_get_data (GTK_OBJECT (button), "COLORSEL"); + ColorSelectionPrivate *priv = colorsel->private; - gtk_color_selection_draw_wheel_marker (colorsel); + if (picker_cursor == NULL) + { + initialize_cursor (); + } - wid = (gdouble) (colorsel->wheel_area->allocation.width) / 2.0; - heig = (gdouble) (colorsel->wheel_area->allocation.height) / 2.0; + /* Why do we do this? Because the "clicked" signal will be emitted after the "button_released" + signal. We don't want to do this stuff again, though, or else it will get trapped here. So, + priv->moving_dropper is initialized to FALSE at the initialization of the colorselector, + it is initialized to true when we start waiting for the user to click the the dropper on a + color, and whenver it is true when this function starts to execute, we set it to false. */ + if (priv->moving_dropper == FALSE) + { + priv->moving_dropper = TRUE; + gtk_signal_connect (GTK_OBJECT (button), "button_press_event", mouse_press, colorsel); + + gdk_pointer_grab (button->window, + FALSE, + GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK, + NULL, + picker_cursor, + 0); + } + else + { + priv->moving_dropper = FALSE; + } +} - res = gtk_color_selection_eval_wheel (x, y, wid, heig, &colorsel->values[HUE], - &colorsel->values[SATURATION]); +void +hex_changed (GtkWidget *hex_entry, gpointer data) +{ + GtkColorSelection *colorsel; + ColorSelectionPrivate *priv; + GdkColor color; + gchar *text; + + colorsel = GTK_COLOR_SELECTION (data); + priv = colorsel->private; - HSV_TO_RGB (); + if (priv->changing) + return; - gtk_color_selection_draw_wheel_marker (colorsel); - gtk_color_selection_draw_value_bar (colorsel, FALSE); - gtk_color_selection_draw_sample (colorsel, FALSE); - gtk_color_selection_update_inputs (colorsel, RGB_INPUTS | HSV_INPUTS, BOTH); + text = gtk_editable_get_chars (GTK_EDITABLE (priv->hex_entry), 0, -1); + if (gdk_color_parse (text, &color)) + { + priv->color[COLORSEL_RED] = CLAMP (color.red/65280.0, 0.0, 1.0); + priv->color[COLORSEL_GREEN] = CLAMP (color.green/65280.0, 0.0, 1.0); + priv->color[COLORSEL_BLUE] = CLAMP (color.blue/65280.0, 0.0, 1.0); + gtk_rgb_to_hsv (priv->color[COLORSEL_RED], + priv->color[COLORSEL_GREEN], + priv->color[COLORSEL_BLUE], + &priv->color[COLORSEL_HUE], + &priv->color[COLORSEL_SATURATION], + &priv->color[COLORSEL_VALUE]); + update_color (colorsel); + } + g_free (text); } -static gint -gtk_color_selection_value_timeout (GtkColorSelection *colorsel) +void +hsv_changed (GtkWidget *hsv, gpointer data) { - gint x, y; - - GDK_THREADS_ENTER (); - - gdk_window_get_pointer (colorsel->value_area->window, &x, &y, NULL); - gtk_color_selection_update_value (colorsel, y); - gtk_color_selection_color_changed (colorsel); + GtkColorSelection *colorsel; + ColorSelectionPrivate *priv; - GDK_THREADS_LEAVE (); + colorsel = GTK_COLOR_SELECTION (data); + priv = colorsel->private; + + if (priv->changing) + return; - return (TRUE); + gtk_hsv_get_color (GTK_HSV (hsv), + &priv->color[COLORSEL_HUE], + &priv->color[COLORSEL_SATURATION], + &priv->color[COLORSEL_VALUE]); + gtk_hsv_to_rgb (priv->color[COLORSEL_HUE], + priv->color[COLORSEL_SATURATION], + priv->color[COLORSEL_VALUE], + &priv->color[COLORSEL_RED], + &priv->color[COLORSEL_GREEN], + &priv->color[COLORSEL_BLUE]); + update_color (colorsel); } -static gint -gtk_color_selection_value_events (GtkWidget *area, - GdkEvent *event) +void +adjustment_changed (GtkAdjustment *adjustment, gpointer data) { GtkColorSelection *colorsel; - gint y; + ColorSelectionPrivate *priv; - colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (area), "_GtkColorSelection"); + colorsel = GTK_COLOR_SELECTION (gtk_object_get_data (GTK_OBJECT (adjustment), "COLORSEL")); + priv = colorsel->private; - if (colorsel->value_gc == NULL) - colorsel->value_gc = gdk_gc_new (colorsel->value_area->window); + if (priv->changing) + return; - switch (event->type) + switch (GPOINTER_TO_INT (data)) { - case GDK_MAP: - gtk_color_selection_draw_value_bar (colorsel, FALSE); - gtk_color_selection_draw_value_marker (colorsel); - break; - case GDK_EXPOSE: - gtk_color_selection_draw_value_marker (colorsel); - break; - case GDK_BUTTON_PRESS: - gtk_grab_add (area); - gtk_color_selection_update_value (colorsel, event->button.y); - gtk_color_selection_color_changed (colorsel); + case COLORSEL_SATURATION: + case COLORSEL_VALUE: + priv->color[GPOINTER_TO_INT (data)] = adjustment->value / 255; + gtk_hsv_to_rgb (priv->color[COLORSEL_HUE], + priv->color[COLORSEL_SATURATION], + priv->color[COLORSEL_VALUE], + &priv->color[COLORSEL_RED], + &priv->color[COLORSEL_GREEN], + &priv->color[COLORSEL_BLUE]); break; - case GDK_BUTTON_RELEASE: - gtk_grab_remove (area); - if (colorsel->timer_active) - gtk_timeout_remove (colorsel->timer_tag); - colorsel->timer_active = FALSE; - - y = event->button.y; - if (event->button.window != area->window) - gdk_window_get_pointer (area->window, NULL, &y, NULL); - - gtk_color_selection_update_value (colorsel, y); - gtk_color_selection_color_changed (colorsel); + case COLORSEL_HUE: + priv->color[GPOINTER_TO_INT (data)] = adjustment->value / 360; + gtk_hsv_to_rgb (priv->color[COLORSEL_HUE], + priv->color[COLORSEL_SATURATION], + priv->color[COLORSEL_VALUE], + &priv->color[COLORSEL_RED], + &priv->color[COLORSEL_GREEN], + &priv->color[COLORSEL_BLUE]); break; - case GDK_MOTION_NOTIFY: - /* Even though we select BUTTON_MOTION_MASK, we seem to need - * to occasionally get events without buttons pressed. - */ - if (!(event->motion.state & - (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK))) - return FALSE; - - y = event->motion.y; - - if (event->motion.is_hint || (event->motion.window != area->window)) - gdk_window_get_pointer (area->window, NULL, &y, NULL); - - switch (colorsel->policy) - { - case GTK_UPDATE_CONTINUOUS: - gtk_color_selection_update_value (colorsel, y); - gtk_color_selection_color_changed (colorsel); - break; - case GTK_UPDATE_DELAYED: - if (colorsel->timer_active) - gtk_timeout_remove (colorsel->timer_tag); - - colorsel->timer_tag = gtk_timeout_add (TIMER_DELAY, - (GtkFunction) gtk_color_selection_value_timeout, - (gpointer) colorsel); - colorsel->timer_active = TRUE; - break; - default: - break; - } + case COLORSEL_RED: + case COLORSEL_GREEN: + case COLORSEL_BLUE: + priv->color[GPOINTER_TO_INT (data)] = adjustment->value / 255; + + gtk_rgb_to_hsv (priv->color[COLORSEL_RED], + priv->color[COLORSEL_GREEN], + priv->color[COLORSEL_BLUE], + &priv->color[COLORSEL_HUE], + &priv->color[COLORSEL_SATURATION], + &priv->color[COLORSEL_VALUE]); break; default: + priv->color[GPOINTER_TO_INT (data)] = adjustment->value / 255; break; } - - return (FALSE); + update_color (colorsel); } -static gint -gtk_color_selection_wheel_timeout (GtkColorSelection *colorsel) +void +opacity_entry_changed (GtkWidget *opacity_entry, gpointer data) { - gint x, y; + GtkColorSelection *colorsel; + ColorSelectionPrivate *priv; + GtkAdjustment *adj; + gchar *text; - GDK_THREADS_ENTER (); + colorsel = GTK_COLOR_SELECTION (data); + priv = colorsel->private; + + if (priv->changing) + return; - gdk_window_get_pointer (colorsel->wheel_area->window, &x, &y, NULL); - gtk_color_selection_update_wheel (colorsel, x, y); - gtk_color_selection_color_changed (colorsel); + text = gtk_editable_get_chars (GTK_EDITABLE (priv->opacity_entry), 0, -1); + adj = gtk_range_get_adjustment (GTK_RANGE (priv->opacity_slider)); + gtk_adjustment_set_value (adj, g_strtod (text, NULL)); - GDK_THREADS_LEAVE (); + update_color (colorsel); - return (TRUE); + g_free (text); } -static gint -gtk_color_selection_wheel_events (GtkWidget *area, - GdkEvent *event) +static void +widget_focus_in (GtkWidget *drawing_area, GdkEventFocus *event, gpointer data) + /* This signal is connected to by all of the widgets except the "Set Color" button */ + /* This will let you add a color to the currently selected palette */ { - GtkColorSelection *colorsel; - gint x, y; + GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data); + ColorSelectionPrivate *priv; - colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (area), "_GtkColorSelection"); - - if (colorsel->wheel_gc == NULL) - colorsel->wheel_gc = gdk_gc_new (colorsel->wheel_area->window); - if (colorsel->sample_gc == NULL) - colorsel->sample_gc = gdk_gc_new (colorsel->sample_area->window); - if (colorsel->value_gc == NULL) - colorsel->value_gc = gdk_gc_new (colorsel->value_area->window); - - switch (event->type) - { - case GDK_MAP: - gtk_color_selection_draw_wheel (colorsel, TRUE); - gtk_color_selection_draw_wheel_marker (colorsel); - gtk_color_selection_draw_sample (colorsel, TRUE); - break; - case GDK_EXPOSE: - gtk_color_selection_draw_wheel_marker (colorsel); - gtk_color_selection_draw_wheel_frame (colorsel); - break; - case GDK_BUTTON_PRESS: - gtk_grab_add (area); - gtk_color_selection_update_wheel (colorsel, event->button.x, event->button.y); - gtk_color_selection_color_changed (colorsel); - break; - case GDK_BUTTON_RELEASE: - gtk_grab_remove (area); - if (colorsel->timer_active) - gtk_timeout_remove (colorsel->timer_tag); - colorsel->timer_active = FALSE; - - x = event->button.x; - y = event->button.y; + priv = colorsel->private; - if (event->button.window != area->window) - gdk_window_get_pointer (area->window, &x, &y, NULL); - - gtk_color_selection_update_wheel (colorsel, x, y); - gtk_color_selection_color_changed (colorsel); - break; - case GDK_MOTION_NOTIFY: - /* Even though we select BUTTON_MOTION_MASK, we seem to need - * to occasionally get events without buttons pressed. - */ - if (!(event->motion.state & - (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK))) - return FALSE; - - x = event->motion.x; - y = event->motion.y; - - if (event->motion.is_hint || (event->motion.window != area->window)) - gdk_window_get_pointer (area->window, &x, &y, NULL); - - switch (colorsel->policy) - { - case GTK_UPDATE_CONTINUOUS: - gtk_color_selection_update_wheel (colorsel, x, y); - gtk_color_selection_color_changed (colorsel); - break; - case GTK_UPDATE_DELAYED: - if (colorsel->timer_active) - gtk_timeout_remove (colorsel->timer_tag); - colorsel->timer_tag = gtk_timeout_add (TIMER_DELAY, - (GtkFunction) gtk_color_selection_wheel_timeout, - (gpointer) colorsel); - colorsel->timer_active = TRUE; - break; - default: - break; - } - break; - default: - break; - } - - return (FALSE); + priv->last_palette = NULL; } + static void -gtk_color_selection_draw_value_bar (GtkColorSelection *colorsel, - gint resize) +make_label_spinbutton (GtkColorSelection *colorsel, + GtkWidget **spinbutton, + gchar *text, + GtkWidget *table, + gint i, gint j, + gint channel_type) { - gint x, y, wid, heig, n; - gdouble sv, v; + GtkWidget *label; + GtkAdjustment *adjust; - wid = colorsel->value_area->allocation.width; - heig = colorsel->value_area->allocation.height; - - if (resize || !colorsel->value_buf) + if (channel_type == COLORSEL_HUE) { - g_free (colorsel->value_buf); - colorsel->value_buf = g_new0 (guchar, 3 * wid); + adjust = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 360.0, 1.0, 1.0, 1.0)); } - - v = 1.0; - sv = 1.0 / (gdouble) MAX (heig - 1, 0); - - for (y = 0; y < heig; y++) + else { - gdouble c[3]; - guchar rc[3]; - gint i = 0; - - gtk_color_selection_hsv_to_rgb (colorsel->values[HUE], - colorsel->values[SATURATION], - v, - &c[0], &c[1], &c[2]); - - for (n = 0; n < 3; n++) - rc[n] = (guchar) (255.0 * c[n]); - - for (x = 0; x < wid; x++) - { - for (n = 0; n < 3; n++) - colorsel->value_buf[i++] = rc[n]; - } - - gtk_preview_draw_row (GTK_PREVIEW (colorsel->value_area), colorsel->value_buf, 0, y, wid); - v -= sv; + adjust = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 255.0, 1.0, 1.0, 1.0)); } + gtk_object_set_data (GTK_OBJECT (adjust), "COLORSEL", colorsel); + *spinbutton = gtk_spin_button_new (adjust, 10.0, 0); + gtk_signal_connect (GTK_OBJECT (*spinbutton), "focus_in_event", widget_focus_in, colorsel); + gtk_signal_connect (GTK_OBJECT (adjust), "value_changed", adjustment_changed, GINT_TO_POINTER (channel_type)); + label = gtk_label_new (text); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach_defaults (GTK_TABLE (table), label, i, i+1, j, j+1); + gtk_table_attach_defaults (GTK_TABLE (table), *spinbutton, i+1, i+2, j, j+1); - gtk_widget_queue_draw (colorsel->value_area); } static void -gtk_color_selection_draw_wheel_frame (GtkColorSelection *colorsel) +make_palette_frame (GtkColorSelection *colorsel, GtkWidget *table, gint i, gint j) { - GtkStyle *style; - gint w, h; + GtkWidget *frame; + ColorSelectionPrivate *priv; - style = gtk_widget_get_style (colorsel->wheel_area); - - w = colorsel->wheel_area->allocation.width; - h = colorsel->wheel_area->allocation.height; - - gdk_draw_arc (colorsel->wheel_area->window, style->black_gc, - FALSE, 1, 1, w - 1, h - 1, 30 * 64, 180 * 64); - gdk_draw_arc (colorsel->wheel_area->window, style->mid_gc[GTK_STATE_NORMAL], - FALSE, 0, 0, w, h, 30 * 64, 180 * 64); - - gdk_draw_arc (colorsel->wheel_area->window, style->bg_gc[GTK_STATE_NORMAL], - FALSE, 1, 1, w - 1, h - 1, 210 * 64, 180 * 64); - gdk_draw_arc (colorsel->wheel_area->window, style->light_gc[GTK_STATE_NORMAL], - FALSE, 0, 0, w, h, 210 * 64, 180 * 64); + priv = colorsel->private; + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + priv->custom_palette[i][j] = palette_new (colorsel); + gtk_widget_set_usize (priv->custom_palette[i][j], CUSTOM_PALETTE_ENTRY_WIDTH, CUSTOM_PALETTE_ENTRY_HEIGHT); + gtk_container_add (GTK_CONTAINER (frame), priv->custom_palette[i][j]); + gtk_table_attach_defaults (GTK_TABLE (table), frame, i, i+1, j, j+1); } static void -gtk_color_selection_draw_wheel (GtkColorSelection *colorsel, - gint resize) +update_color (GtkColorSelection *colorsel) { - gint x, y, i, wid, heig, n; - gdouble cx, cy, h, s, c[3]; - guchar bg[3]; - GtkStyle *style = gtk_widget_get_style (colorsel->wheel_area); - - wid = colorsel->wheel_area->allocation.width; - heig = colorsel->wheel_area->allocation.height; - - if (resize) - { - if (colorsel->wheel_buf != NULL) - g_free (colorsel->wheel_buf); - - colorsel->wheel_buf = g_new(guchar, 3 * wid); - } + ColorSelectionPrivate *priv = colorsel->private; + gchar entryval[12]; + gchar opacity_text[32]; + gchar *ptr; + priv->changing = TRUE; + color_sample_draw_samples (colorsel); + + gtk_hsv_set_color (GTK_HSV (priv->triangle_colorsel), + priv->color[COLORSEL_HUE], + priv->color[COLORSEL_SATURATION], + priv->color[COLORSEL_VALUE]); + gtk_adjustment_set_value (gtk_spin_button_get_adjustment + (GTK_SPIN_BUTTON (priv->hue_spinbutton)), + priv->color[COLORSEL_HUE] * 360); + gtk_adjustment_set_value (gtk_spin_button_get_adjustment + (GTK_SPIN_BUTTON (priv->sat_spinbutton)), + priv->color[COLORSEL_SATURATION] * 255); + gtk_adjustment_set_value (gtk_spin_button_get_adjustment + (GTK_SPIN_BUTTON (priv->val_spinbutton)), + priv->color[COLORSEL_VALUE] * 255); + gtk_adjustment_set_value (gtk_spin_button_get_adjustment + (GTK_SPIN_BUTTON (priv->red_spinbutton)), + priv->color[COLORSEL_RED] * 255); + gtk_adjustment_set_value (gtk_spin_button_get_adjustment + (GTK_SPIN_BUTTON (priv->green_spinbutton)), + priv->color[COLORSEL_GREEN] * 255); + gtk_adjustment_set_value (gtk_spin_button_get_adjustment + (GTK_SPIN_BUTTON (priv->blue_spinbutton)), + priv->color[COLORSEL_BLUE] * 255); + gtk_adjustment_set_value (gtk_range_get_adjustment + (GTK_RANGE (priv->opacity_slider)), + priv->color[COLORSEL_OPACITY] * 255); + + g_snprintf (opacity_text, 32, "%.0f", priv->color[COLORSEL_OPACITY] * 255); + gtk_entry_set_text (GTK_ENTRY (priv->opacity_entry), opacity_text); + + g_snprintf (entryval, 11, "#%2X%2X%2X", + (guint) (255 * priv->color[COLORSEL_RED]), + (guint) (255 * priv->color[COLORSEL_GREEN]), + (guint) (255 * priv->color[COLORSEL_BLUE])); + + for (ptr = entryval; *ptr; ptr++) + if (*ptr == ' ') + *ptr = '0'; + gtk_entry_set_text (GTK_ENTRY (priv->hex_entry), entryval); + priv->changing = FALSE; +} - cx = (gdouble) (wid) / 2.0; - cy = (gdouble) (heig) / 2.0; +static void +add_button_pressed (GtkWidget *button, GtkColorSelection *colorsel) +{ + gint i, j; + ColorSelectionPrivate *priv; - bg[0] = style->bg[GTK_STATE_NORMAL].red >> 8; - bg[1] = style->bg[GTK_STATE_NORMAL].green >> 8; - bg[2] = style->bg[GTK_STATE_NORMAL].blue >> 8; + priv = colorsel->private; - for (y = 0; y < heig; y++) + for (j = 0; j < CUSTOM_PALETTE_HEIGHT; j++) { - i = 0; - for (x = 0; x < wid; x++) + for (i = 0; i < CUSTOM_PALETTE_WIDTH; i++) { - if (gtk_color_selection_eval_wheel (x, y, cx, cy, &h, &s)) - { - for (n = 0; n < 3; n++) - colorsel->wheel_buf[i++] = bg[n]; - } - else + /* Either last_palette is set and we're on it, or it's an empty palette */ + if ((priv->last_palette && priv->last_palette == priv->custom_palette[i][j]) || + ((priv->last_palette == NULL) && (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (priv->custom_palette[i][j]), + "color_set")) == 0))) { - gtk_color_selection_hsv_to_rgb (h, s, 1.0, &c[0], &c[1], &c[2]); - for (n = 0; n < 3; n++) - colorsel->wheel_buf[i++] = (guchar) (255.0 * c[n]); + palette_set_color (priv->custom_palette[i][j], colorsel, priv->color); + /* forward the selection */ + if ((i == CUSTOM_PALETTE_WIDTH - 1) && (j == CUSTOM_PALETTE_HEIGHT - 1)) + gtk_widget_grab_focus (priv->custom_palette[0][0]); + else if (i == CUSTOM_PALETTE_WIDTH - 1) + gtk_widget_grab_focus (priv->custom_palette[0][j + 1]); + else + gtk_widget_grab_focus (priv->custom_palette[i + 1][j]); + return; } } + } + /* the palette is totally full. Add to the first one totally arbitrarily */ + palette_set_color (priv->custom_palette[0][0], colorsel, priv->color); + /* forward the selection */ + gtk_widget_grab_focus (priv->custom_palette[1][0]); +} + +GtkType +gtk_color_selection_get_type (void) +{ + static GtkType color_selection_type = 0; + + if (!color_selection_type) + { + static const GtkTypeInfo color_selection_info = + { + "GtkColorSelection", + sizeof (GtkColorSelection), + sizeof (GtkColorSelectionClass), + (GtkClassInitFunc) gtk_color_selection_class_init, + (GtkObjectInitFunc) gtk_color_selection_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; - gtk_preview_draw_row (GTK_PREVIEW (colorsel->wheel_area), colorsel->wheel_buf, 0, y, wid); + color_selection_type = gtk_type_unique (gtk_vbox_get_type (), &color_selection_info); } - if (colorsel->wheel_area->window) - { - GdkPixmap *pm = NULL; - GdkGC *pmgc = NULL; - GdkColor col; - gint w, h; - - pm = gdk_pixmap_new (colorsel->wheel_area->window, wid, heig, 1); - pmgc = gdk_gc_new (pm); - - col.pixel = 0; - gdk_gc_set_foreground(pmgc, &col); - gdk_draw_rectangle(pm, pmgc, TRUE, 0, 0, wid, heig); - col.pixel = 1; - - gdk_gc_set_foreground(pmgc, &col); - gdk_draw_arc (pm, pmgc, TRUE, 0, 0, wid, heig, 0, 360*64); - - w = colorsel->wheel_area->allocation.width; - h = colorsel->wheel_area->allocation.height; - - gdk_draw_arc (pm, pmgc, - FALSE, 1, 1, w - 1, h - 1, 30 * 64, 180 * 64); - gdk_draw_arc (pm, pmgc, - FALSE, 0, 0, w, h, 30 * 64, 180 * 64); - gdk_draw_arc (pm, pmgc, - FALSE, 1, 1, w - 1, h - 1, 210 * 64, 180 * 64); - gdk_draw_arc (pm, pmgc, - FALSE, 0, 0, w, h, 210 * 64, 180 * 64); - gdk_window_shape_combine_mask (colorsel->wheel_area->window, pm, 0, 0); - gdk_pixmap_unref (pm); - gdk_gc_destroy (pmgc); - } + return color_selection_type; } static void -gtk_color_selection_draw_sample (GtkColorSelection *colorsel, - gint resize) +gtk_color_selection_class_init (GtkColorSelectionClass *klass) { - gint x, y, i, wid, heig, f, half, n; - guchar c[3 * 2], cc[3 * 4], *cp = c; - gdouble o, oldo; + GtkObjectClass *object_class; - wid = colorsel->sample_area->allocation.width; - heig = colorsel->sample_area->allocation.height; - half = wid >> 1; + object_class = (GtkObjectClass*) klass; - if (resize) - { - if (colorsel->sample_buf != NULL) - g_free (colorsel->sample_buf); + parent_class = gtk_type_class (gtk_vbox_get_type ()); - colorsel->sample_buf = g_new(guchar, 3 * wid); - } + color_selection_signals[COLOR_CHANGED] = + gtk_signal_new ("color_changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkColorSelectionClass, color_changed), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); - i = RED; - for (n = 0; n < 3; n++) - { - c[n] = (guchar) (255.0 * colorsel->old_values[i]); - c[n + 3] = (guchar) (255.0 * colorsel->values[i++]); - } - if (colorsel->use_opacity) - { - o = colorsel->values[OPACITY]; - oldo = colorsel->old_values[OPACITY]; + gtk_object_class_add_signals (object_class, color_selection_signals, LAST_SIGNAL); - for (n = 0; n < 3; n++) - { - cc[n] = (guchar) ((1.0 - oldo) * 192 + (oldo * (gdouble) c[n])); - cc[n + 3] = (guchar) ((1.0 - oldo) * 128 + (oldo * (gdouble) c[n])); - cc[n + 6] = (guchar) ((1.0 - o) * 192 + (o * (gdouble) c[n + 3])); - cc[n + 9] = (guchar) ((1.0 - o) * 128 + (o * (gdouble) c[n + 3])); - } - cp = cc; - } + object_class->destroy = gtk_color_selection_destroy; +} - for (y = 0; y < heig; y++) +/* widget functions */ +static void +gtk_color_selection_init (GtkColorSelection *colorsel) +{ + GtkWidget *top_hbox; + GtkWidget *top_right_vbox; + GtkWidget *table, *label, *hbox, *frame, *vbox; + GtkAdjustment *adjust; + GdkPixmap *dropper_pixmap; + GtkWidget *dropper_image; + GtkWidget *button; + GdkBitmap *mask = NULL; + gint i, j; + ColorSelectionPrivate *priv; + + priv = colorsel->private = g_new (ColorSelectionPrivate, 1); + priv->changing = FALSE; + priv->default_set = FALSE; + priv->last_palette = NULL; + priv->moving_dropper = FALSE; + + gtk_box_set_spacing (GTK_BOX (colorsel), 4); + top_hbox = gtk_hbox_new (FALSE, 8); + gtk_box_pack_start (GTK_BOX (colorsel), top_hbox, FALSE, FALSE, 0); + + vbox = gtk_vbox_new (FALSE, 4); + priv->triangle_colorsel = gtk_hsv_new (); + gtk_signal_connect (GTK_OBJECT (priv->triangle_colorsel), "changed", hsv_changed, colorsel); + gtk_hsv_set_metrics (GTK_HSV (priv->triangle_colorsel), 174, 15); + gtk_box_pack_start (GTK_BOX (top_hbox), vbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox), priv->triangle_colorsel, FALSE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 4); + gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + frame = gtk_frame_new (NULL); + gtk_widget_set_usize (frame, -1, 30); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + color_sample_new (colorsel); + gtk_container_add (GTK_CONTAINER (frame), priv->sample_area); + gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); + + button = gtk_button_new (); + gtk_signal_connect (GTK_OBJECT (button), "focus_in_event", widget_focus_in, colorsel); + gtk_widget_set_events (button, GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK); + gtk_object_set_data (GTK_OBJECT (button), "COLORSEL", colorsel); + gtk_signal_connect (GTK_OBJECT (button), "clicked", get_screen_color, NULL); + dropper_pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, gtk_widget_get_colormap (button), &mask, NULL, picker); + dropper_image = gtk_pixmap_new (dropper_pixmap, mask); + gtk_container_add (GTK_CONTAINER (button), dropper_image); + label = gtk_label_new (_("Color Picker")); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + + top_right_vbox = gtk_vbox_new (FALSE, 4); + gtk_box_pack_start (GTK_BOX (top_hbox), top_right_vbox, FALSE, FALSE, 0); + table = gtk_table_new (8, 6, FALSE); + gtk_box_pack_start (GTK_BOX (top_right_vbox), table, FALSE, FALSE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 4); + gtk_table_set_col_spacings (GTK_TABLE (table), 4); + + make_label_spinbutton (colorsel, &priv->hue_spinbutton, _("Hue:"), table, 0, 0, COLORSEL_HUE); + make_label_spinbutton (colorsel, &priv->sat_spinbutton, _("Saturation:"), table, 0, 1, COLORSEL_SATURATION); + make_label_spinbutton (colorsel, &priv->val_spinbutton, _("Value:"), table, 0, 2, COLORSEL_VALUE); + make_label_spinbutton (colorsel, &priv->red_spinbutton, _("Red:"), table, 6, 0, COLORSEL_RED); + make_label_spinbutton (colorsel, &priv->green_spinbutton, _("Green:"), table, 6, 1, COLORSEL_GREEN); + make_label_spinbutton (colorsel, &priv->blue_spinbutton, _("Blue:"), table, 6, 2, COLORSEL_BLUE); + gtk_table_attach_defaults (GTK_TABLE (table), gtk_hseparator_new (), 0, 8, 3, 4); + + priv->opacity_label = gtk_label_new (_("Opacity:")); + gtk_misc_set_alignment (GTK_MISC (priv->opacity_label), 1.0, 0.5); + gtk_table_attach_defaults (GTK_TABLE (table), priv->opacity_label, 0, 1, 4, 5); + adjust = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 255.0, 1.0, 1.0, 0.0)); + gtk_object_set_data (GTK_OBJECT (adjust), "COLORSEL", colorsel); + priv->opacity_slider = gtk_hscale_new (adjust); + gtk_scale_set_draw_value (GTK_SCALE (priv->opacity_slider), FALSE); + gtk_signal_connect (GTK_OBJECT(adjust), "value_changed", adjustment_changed, GINT_TO_POINTER (COLORSEL_OPACITY)); + gtk_table_attach_defaults (GTK_TABLE (table), priv->opacity_slider, 1, 7, 4, 5); + priv->opacity_entry = gtk_entry_new (); + gtk_widget_set_usize (priv->opacity_entry, 40, 0); + gtk_signal_connect (GTK_OBJECT (priv->opacity_entry), "focus_in_event", widget_focus_in, colorsel); + gtk_signal_connect (GTK_OBJECT (priv->opacity_entry), "activate", opacity_entry_changed, colorsel); + gtk_table_attach_defaults (GTK_TABLE (table), priv->opacity_entry, 7, 8, 4, 5); + + label = gtk_label_new (_("Hex Value:")); + gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 5, 6); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + priv->hex_entry = gtk_entry_new (); + gtk_signal_connect (GTK_OBJECT (priv->hex_entry), "activate", hex_changed, colorsel); + gtk_widget_set_usize (priv->hex_entry, 75, -1); + gtk_table_set_col_spacing (GTK_TABLE (table), 3, 25); + gtk_table_attach_defaults (GTK_TABLE (table), priv->hex_entry, 1, 5, 5, 6); + + /* Set up the palette */ + table = gtk_table_new (CUSTOM_PALETTE_HEIGHT, CUSTOM_PALETTE_WIDTH, TRUE); + gtk_table_set_row_spacings (GTK_TABLE (table), 1); + gtk_table_set_col_spacings (GTK_TABLE (table), 1); + for (i = 0; i < CUSTOM_PALETTE_WIDTH; i++) { - i = 0; - for (x = 0; x < wid; x++) + for (j = 0; j < CUSTOM_PALETTE_HEIGHT; j++) { - if (colorsel->use_opacity) - { - f = 3 * (((x % 32) < 16) ^ ((y % 32) < 16)); - f += (x > half) * 6; - } - else - f = (x > half) * 3; - - for (n = 0; n < 3; n++) - colorsel->sample_buf[i++] = cp[n + f]; + make_palette_frame (colorsel, table, i, j); } + } + priv->palette_frame = gtk_frame_new (_("Custom Palette")); + gtk_box_pack_end (GTK_BOX (top_right_vbox), priv->palette_frame, FALSE, FALSE, 0); + vbox = gtk_vbox_new (FALSE, 4); + gtk_container_add (GTK_CONTAINER (priv->palette_frame), vbox); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); + button = gtk_button_new_with_label (_("Set Color")); + gtk_signal_connect (GTK_OBJECT (button), "clicked", add_button_pressed, colorsel); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 4); + + gtk_widget_show_all (top_hbox); + + if (priv->use_opacity == FALSE) + { + gtk_widget_hide (priv->opacity_label); + gtk_widget_hide (priv->opacity_slider); + gtk_widget_hide (priv->opacity_entry); + } - gtk_preview_draw_row (GTK_PREVIEW (colorsel->sample_area), colorsel->sample_buf, 0, y, wid); + if (priv->use_palette == FALSE) + { + gtk_widget_hide (priv->palette_frame); } +} - gtk_widget_queue_draw (colorsel->sample_area); +static void +gtk_color_selection_destroy (GtkObject *object) +{ + g_free (GTK_COLOR_SELECTION (object)->private); } -static gint -gtk_color_selection_eval_wheel (gint x, gint y, - gdouble cx, gdouble cy, - gdouble *h, gdouble *s) + + +/** + * gtk_color_selection_new: + * @void: + * + * Creates a new GtkColorSelection. + * + * Return value: The new GtkColorSelection. + **/ +GtkWidget * +gtk_color_selection_new (void) { - gdouble r, rx, ry; + GtkColorSelection *colorsel; + ColorSelectionPrivate *priv; + gdouble color[4]; + color[0] = 1.0; + color[1] = 1.0; + color[2] = 1.0; + color[3] = 1.0; - rx = ((gdouble) x - cx); - ry = ((gdouble) y - cy); + colorsel = gtk_type_new (GTK_TYPE_COLOR_SELECTION); + priv = colorsel->private; + gtk_color_selection_set_color (colorsel, color); + gtk_color_selection_set_use_opacity (colorsel, FALSE); - rx = rx/cx; - ry = ry/cy; + /* We want to make sure that default_set is FALSE */ + /* This way the user can still set it */ + priv->default_set = FALSE; - r = sqrt (SQR (rx) + SQR (ry)); + return GTK_WIDGET (colorsel); +} - if (r != 0.0) - *h = atan2 (rx / r, ry / r); - else - *h = 0.0; - *s = r; - *h = 360.0 * (*h) / (2.0 * M_PI) + 180; +void +gtk_color_selection_set_update_policy (GtkColorSelection *colorsel, + GtkUpdateType policy) +{ + g_return_if_fail (colorsel != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); + /* */ + g_warning ("This function is deprecated."); +} - if (*s == 0.0) - *s = 0.00001; - else if (*s > 1.0) - { - *s = 1.0; - return TRUE; - } - return FALSE; +/** + * gtk_color_selection_get_use_opacity: + * @colorsel: A GtkColorSelection. + * + * Determines whether the colorsel can use opacity. + * + * Return value: TRUE if the @colorsel uses opacity. FALSE if it does't. + **/ +gboolean +gtk_color_selection_get_use_opacity (GtkColorSelection *colorsel) +{ + ColorSelectionPrivate *priv; + g_return_val_if_fail (colorsel != NULL, FALSE); + g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), FALSE); + + priv = colorsel->private; + return priv->use_opacity; } -static void -gtk_color_selection_hsv_to_rgb (gdouble h, gdouble s, gdouble v, - gdouble *r, gdouble *g, gdouble *b) +/** + * gtk_color_selection_set_use_opacity: + * @colorsel: A GtkColorSelection. + * @use_opacity: TRUE if @colorsel can set the opacity, FALSE otherwise. + * + * Sets the @colorsel to use or not use opacity. + * + **/ +void +gtk_color_selection_set_use_opacity (GtkColorSelection *colorsel, + gboolean use_opacity) { - gint i; - gdouble f, w, q, t; + ColorSelectionPrivate *priv; + g_return_if_fail (colorsel != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); - if (s == 0.0) - s = 0.000001; + priv = colorsel->private; + if (priv->use_opacity == use_opacity) + return; - if (h == -1.0) + priv->use_opacity = use_opacity; + if (use_opacity) { - *r = v; - *g = v; - *b = v; + gtk_widget_show (priv->opacity_slider); + gtk_widget_show (priv->opacity_label); + gtk_widget_show (priv->opacity_entry); } else { - if (h == 360.0) - h = 0.0; - h = h / 60.0; - i = (gint) h; - f = h - i; - w = v * (1.0 - s); - q = v * (1.0 - (s * f)); - t = v * (1.0 - (s * (1.0 - f))); - - switch (i) - { - case 0: - *r = v; - *g = t; - *b = w; - break; - case 1: - *r = q; - *g = v; - *b = w; - break; - case 2: - *r = w; - *g = v; - *b = t; - break; - case 3: - *r = w; - *g = q; - *b = v; - break; - case 4: - *r = t; - *g = w; - *b = v; - break; - case 5: - *r = v; - *g = w; - *b = q; - break; - } + gtk_widget_hide (priv->opacity_slider); + gtk_widget_hide (priv->opacity_label); + gtk_widget_hide (priv->opacity_entry); } + color_sample_set_use_opacity (colorsel); } -static void -gtk_color_selection_rgb_to_hsv (gdouble r, gdouble g, gdouble b, - gdouble *h, gdouble *s, gdouble *v) +/** + * gtk_color_selection_get_use_palette: + * @colorsel: A GtkColorSelection. + * + * Determines whether the palette is used. + * + * Return value: TRUE if the palette is used. FALSE if it isn't. + **/ +gboolean +gtk_color_selection_get_use_palette (GtkColorSelection *colorsel) { - double max, min, delta; + ColorSelectionPrivate *priv; + g_return_val_if_fail (colorsel != NULL, FALSE); + g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), FALSE); - max = r; - if (g > max) - max = g; - if (b > max) - max = b; - - min = r; - if (g < min) - min = g; - if (b < min) - min = b; + priv = colorsel->private; + return priv->use_palette; +} - *v = max; +/** + * gtk_color_selection_set_use_palette: + * @colorsel: A GtkColorSelection. + * @use_palette: TRUE if palette is to be visible, FALSE otherwise. + * + * Shows and hides the palette based upon the value of @use_palette. + * + **/ +void +gtk_color_selection_set_use_palette (GtkColorSelection *colorsel, + gboolean use_palette) +{ + ColorSelectionPrivate *priv; + g_return_if_fail (colorsel != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); - if (max != 0.0) - *s = (max - min) / max; - else - *s = 0.0; + priv = colorsel->private; + if (priv->use_palette == use_palette) + return; - if (*s == 0.0) - *h = -1.0; + priv->use_palette = use_palette; + if (use_palette) + gtk_widget_show (priv->palette_frame); else - { - delta = max - min; + gtk_widget_hide (priv->palette_frame); +} - if (r == max) - *h = (g - b) / delta; - else if (g == max) - *h = 2.0 + (b - r) / delta; - else if (b == max) - *h = 4.0 + (r - g) / delta; +/** + * gtk_color_selection_set_color: + * @colorsel: A GtkColorSelection. + * @color: A color to set the current color with. + * + * Sets the current color to be @color. The first time this is called, it will + * also set the original color to be @color too. + * + **/ +void +gtk_color_selection_set_color (GtkColorSelection *colorsel, + gdouble *color) +{ + ColorSelectionPrivate *priv; + gint i; - *h = *h * 60.0; + g_return_if_fail (colorsel != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); - if (*h < 0.0) - *h = *h + 360; + priv = colorsel->private; + priv->changing = TRUE; + priv->color[COLORSEL_RED] = color[0]; + priv->color[COLORSEL_GREEN] = color[1]; + priv->color[COLORSEL_BLUE] = color[2]; + priv->color[COLORSEL_OPACITY] = color[3]; + gtk_rgb_to_hsv (priv->color[COLORSEL_RED], + priv->color[COLORSEL_GREEN], + priv->color[COLORSEL_BLUE], + &priv->color[COLORSEL_HUE], + &priv->color[COLORSEL_SATURATION], + &priv->color[COLORSEL_VALUE]); + if (priv->default_set == FALSE) + { + for (i = 0; i < COLORSEL_NUM_CHANNELS; i++) + priv->old_color[i] = priv->color[i]; } + update_color (colorsel); + priv->default_set = TRUE; } -/***************************/ -/* GtkColorSelectionDialog */ -/***************************/ +/** + * gtk_color_selection_get_color: + * @colorsel: A GtkColorSelection. + * @color: A color to fill in with the current color. + * + * Sets @color to be the current color in the GtkColorSelection widget. + * + **/ +void +gtk_color_selection_get_color (GtkColorSelection *colorsel, + gdouble *color) +{ + ColorSelectionPrivate *priv; -GtkType -gtk_color_selection_dialog_get_type (void) + g_return_if_fail (colorsel != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); + + priv = colorsel->private; + color[0] = priv->color[COLORSEL_RED]; + color[1] = priv->color[COLORSEL_GREEN]; + color[2] = priv->color[COLORSEL_BLUE]; + color[3] = priv->use_opacity ? priv->color[COLORSEL_OPACITY] : 1.0; +} + +/** + * gtk_color_selection_get_old_color: + * @colorsel: A GtkColorSelection. + * @color: A color to set the original color with. + * + * Sets the 'original' color to be @color. This function should be called with + * some hesitations, as it might seem confusing to have that color change. + * Calling gtk_color_selection_set_color will also set this color the first + * time it is called. + * + **/ +void +gtk_color_selection_set_old_color (GtkColorSelection *colorsel, + gdouble *color) { - static GtkType color_selection_dialog_type = 0; + ColorSelectionPrivate *priv; - if (!color_selection_dialog_type) - { - GtkTypeInfo colorsel_diag_info = - { - "GtkColorSelectionDialog", - sizeof (GtkColorSelectionDialog), - sizeof (GtkColorSelectionDialogClass), - (GtkClassInitFunc) gtk_color_selection_dialog_class_init, - (GtkObjectInitFunc) gtk_color_selection_dialog_init, - /* reserved_1 */ NULL, - /* reserved_2 */ NULL, - (GtkClassInitFunc) NULL, - }; + g_return_if_fail (colorsel != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); - color_selection_dialog_type = gtk_type_unique (GTK_TYPE_WINDOW, &colorsel_diag_info); - } + priv = colorsel->private; + priv->changing = TRUE; + priv->old_color[COLORSEL_RED] = color[0]; + priv->old_color[COLORSEL_GREEN] = color[1]; + priv->old_color[COLORSEL_BLUE] = color[2]; + priv->old_color[COLORSEL_OPACITY] = color[3]; + gtk_rgb_to_hsv (priv->old_color[COLORSEL_RED], + priv->old_color[COLORSEL_GREEN], + priv->old_color[COLORSEL_BLUE], + &priv->old_color[COLORSEL_HUE], + &priv->old_color[COLORSEL_SATURATION], + &priv->old_color[COLORSEL_VALUE]); + color_sample_draw_samples (colorsel); + priv->default_set = TRUE; +} + +/** + * gtk_color_selection_get_old_color: + * @colorsel: A GtkColorSelection. + * @color: A color to fill in with the original color value. + * + * Fills @color in with the original color value. + * + **/ +void +gtk_color_selection_get_old_color (GtkColorSelection *colorsel, + gdouble *color) +{ + ColorSelectionPrivate *priv; + + g_return_if_fail (colorsel != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); - return color_selection_dialog_type; + priv = colorsel->private; + color[0] = priv->old_color[COLORSEL_RED]; + color[1] = priv->old_color[COLORSEL_GREEN]; + color[2] = priv->old_color[COLORSEL_BLUE]; + color[3] = priv->use_opacity ? priv->old_color[COLORSEL_OPACITY] : 1.0; } -static void -gtk_color_selection_dialog_class_init (GtkColorSelectionDialogClass *klass) +/** + * gtk_color_selection_set_palette_color: + * @colorsel: A GtkColorSelection. + * @x: The x coordinate of the palette. + * @y: The y coordinate of the palette. + * @color: A color to set the palette with. + * + * Set the palette located at (@x, @y) to have @color set as its color. + * + **/ +void +gtk_color_selection_set_palette_color (GtkColorSelection *colorsel, + gint x, + gint y, + gdouble *color) { - GtkObjectClass *object_class; + ColorSelectionPrivate *priv; - object_class = (GtkObjectClass*) klass; + g_return_if_fail (colorsel != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); + g_return_if_fail (x >= 0 && y >= 0 && x < CUSTOM_PALETTE_WIDTH && y < CUSTOM_PALETTE_HEIGHT); - color_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_WINDOW); + priv = colorsel->private; + palette_set_color (priv->custom_palette[x][y], colorsel, color); } -static void -gtk_color_selection_dialog_init (GtkColorSelectionDialog *colorseldiag) +/** + * gtk_color_selection_get_palette_color: + * @colorsel: A GtkColorSelection. + * @x: The x coordinate of the palette. + * @y: The y coordinate of the palette. + * @color: A color to fill in with the color value. + * + * Set @color to have the color found in the palette located at (@x, @y). If + * the palette is unset, it will leave the color unset. + * + * Return value: TRUE if the palette located at (@x, @y) has a color set. FALSE + * if it doesn't. + **/ +gboolean +gtk_color_selection_get_palette_color (GtkColorSelection *colorsel, + gint x, + gint y, + gdouble *color) { - GtkWidget *action_area, *frame; + ColorSelectionPrivate *priv; - gtk_widget_set_visual (GTK_WIDGET (colorseldiag), gdk_rgb_get_visual ()); - gtk_widget_set_colormap (GTK_WIDGET (colorseldiag), gdk_rgb_get_cmap ()); + g_return_val_if_fail (colorsel != NULL, FALSE); + g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), FALSE); + g_return_val_if_fail (x >= 0 && y >= 0 && x < CUSTOM_PALETTE_WIDTH && y < CUSTOM_PALETTE_HEIGHT, FALSE); - gtk_widget_push_visual (gdk_rgb_get_visual ()); - gtk_widget_push_colormap (gdk_rgb_get_cmap ()); + priv = colorsel->private; - colorseldiag->main_vbox = gtk_vbox_new (FALSE, 10); - gtk_container_set_border_width (GTK_CONTAINER (colorseldiag), 10); - gtk_container_add (GTK_CONTAINER (colorseldiag), colorseldiag->main_vbox); - gtk_widget_show (colorseldiag->main_vbox); + if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (priv->custom_palette[x][y]), "color_set")) == 0) + return FALSE; - frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); - gtk_container_add (GTK_CONTAINER (colorseldiag->main_vbox), frame); - gtk_widget_show (frame); - - colorseldiag->colorsel = gtk_color_selection_new (); - gtk_container_add (GTK_CONTAINER (frame), colorseldiag->colorsel); - gtk_widget_show (colorseldiag->colorsel); - - action_area = gtk_hbutton_box_new (); - gtk_button_box_set_layout(GTK_BUTTON_BOX(action_area), GTK_BUTTONBOX_END); - gtk_button_box_set_spacing(GTK_BUTTON_BOX(action_area), 5); - gtk_box_pack_end (GTK_BOX (colorseldiag->main_vbox), action_area, FALSE, FALSE, 0); - gtk_widget_show (action_area); - - colorseldiag->ok_button = gtk_button_new_with_label (_("OK")); - GTK_WIDGET_SET_FLAGS (colorseldiag->ok_button, GTK_CAN_DEFAULT); - gtk_box_pack_start (GTK_BOX (action_area), colorseldiag->ok_button, TRUE, TRUE, 0); - gtk_widget_grab_default (colorseldiag->ok_button); - gtk_widget_show (colorseldiag->ok_button); - - colorseldiag->cancel_button = gtk_button_new_with_label (_("Cancel")); - GTK_WIDGET_SET_FLAGS (colorseldiag->cancel_button, GTK_CAN_DEFAULT); - gtk_box_pack_start (GTK_BOX (action_area), colorseldiag->cancel_button, TRUE, TRUE, 0); - gtk_widget_show (colorseldiag->cancel_button); - - colorseldiag->help_button = gtk_button_new_with_label (_("Help")); - GTK_WIDGET_SET_FLAGS (colorseldiag->help_button, GTK_CAN_DEFAULT); - gtk_box_pack_start (GTK_BOX (action_area), colorseldiag->help_button, TRUE, TRUE, 0); - gtk_widget_show (colorseldiag->help_button); - - gtk_widget_pop_colormap (); - gtk_widget_pop_visual (); + palette_get_color (priv->custom_palette[x][y], color); + return TRUE; } -GtkWidget* -gtk_color_selection_dialog_new (const gchar *title) +/** + * gtk_color_selection_unset_palette_color: + * @colorsel: A GtkColorSelection. + * @x: The x coordinate of the palette. + * @y: The y coordinate of the palette. + * + * Change the palette located at (@x, @y) to have no color set. + * + **/ +void +gtk_color_selection_unset_palette_color (GtkColorSelection *colorsel, + gint x, + gint y) { - GtkColorSelectionDialog *colorseldiag; + ColorSelectionPrivate *priv; - colorseldiag = gtk_type_new (GTK_TYPE_COLOR_SELECTION_DIALOG); - gtk_window_set_title (GTK_WINDOW (colorseldiag), title); + g_return_if_fail (colorsel != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); + g_return_if_fail (x >= 0 && y >= 0 && x < CUSTOM_PALETTE_WIDTH && y < CUSTOM_PALETTE_HEIGHT); + + priv = colorsel->private; + palette_unset_color (priv->custom_palette[x][y]); +} + +/** + * gtk_color_selection_is_adjusting: + * @colorsel: A GtkColorSelection. + * + * Gets the current state of the @colorsel. + * + * Return value: TRUE if the user is currently dragging a color around, and FALSE + * if the selection has stopped. + **/ +gboolean +gtk_color_selection_is_adjusting (GtkColorSelection *colorsel) +{ + ColorSelectionPrivate *priv; + + g_return_val_if_fail (colorsel != NULL, FALSE); + g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), FALSE); + + priv = colorsel->private; - return GTK_WIDGET (colorseldiag); + return (gtk_hsv_is_adjusting (GTK_HSV (priv->triangle_colorsel))); } diff --git a/gtk/gtkcolorsel.h b/gtk/gtkcolorsel.h index 14e622e7d1..56f11bd806 100644 --- a/gtk/gtkcolorsel.h +++ b/gtk/gtkcolorsel.h @@ -1,4 +1,5 @@ /* GTK - The GIMP Toolkit + * Copyright (C) 2000 Red Hat, Inc. * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or @@ -23,132 +24,87 @@ * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ +#ifndef __GTK_COLOR_SELECTION_H__ +#define __GTK_COLOR_SELECTION_H__ -#ifndef __GTK_COLORSEL_H__ -#define __GTK_COLORSEL_H__ - -#include <gtk/gtkwindow.h> +#include <gtk/gtkdialog.h> #include <gtk/gtkvbox.h> -#include <gtk/gtkframe.h> -#include <gtk/gtkpreview.h> -#include <gtk/gtkbutton.h> -#include <gtk/gtkentry.h> -#include <gtk/gtkhbox.h> -#include <gtk/gtklabel.h> -#include <gtk/gtkmain.h> -#include <gtk/gtksignal.h> -#include <gtk/gtkmisc.h> -#include <gtk/gtkrange.h> -#include <gtk/gtkscale.h> -#include <gtk/gtkhscale.h> -#include <gtk/gtktable.h> -#include <gtk/gtkeventbox.h> - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ - -#define GTK_TYPE_COLOR_SELECTION (gtk_color_selection_get_type ()) -#define GTK_COLOR_SELECTION(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_COLOR_SELECTION, GtkColorSelection)) -#define GTK_COLOR_SELECTION_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_SELECTION, GtkColorSelectionClass)) -#define GTK_IS_COLOR_SELECTION(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_COLOR_SELECTION)) -#define GTK_IS_COLOR_SELECTION_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_SELECTION)) -#define GTK_COLOR_SELECTION_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_COLOR_SELECTION, GtkColorSelectionClass)) +#define GTK_TYPE_COLOR_SELECTION (gtk_color_selection_get_type ()) +#define GTK_COLOR_SELECTION(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_COLOR_SELECTION, GtkColorSelection)) +#define GTK_COLOR_SELECTION_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_SELECTION, GtkColorSelectionClass)) +#define GTK_IS_COLOR_SELECTION(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_COLOR_SELECTION)) +#define GTK_IS_COLOR_SELECTION_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), GTK_TYPE_COLOR_SELECTION)) +#define GTK_COLOR_SELECTION_GET_CLASS(obj) (GTK_CHECK_GET_CLAS ((obj), GTK_TYPE_COLOR_SELECTION, GtkColorSelectionClass)) -#define GTK_TYPE_COLOR_SELECTION_DIALOG (gtk_color_selection_dialog_get_type ()) -#define GTK_COLOR_SELECTION_DIALOG(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_COLOR_SELECTION_DIALOG, GtkColorSelectionDialog)) -#define GTK_COLOR_SELECTION_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_SELECTION_DIALOG, GtkColorSelectionDialogClass)) -#define GTK_IS_COLOR_SELECTION_DIALOG(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_COLOR_SELECTION_DIALOG)) -#define GTK_IS_COLOR_SELECTION_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_SELECTION_DIALOG)) -#define GTK_COLOR_SELECTION_DIALOG_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_COLOR_SELECTION_DIALOG, GtkColorSelectionDialogClass)) +/* Number of elements in the custom palatte */ +#define CUSTOM_PALETTE_WIDTH 10 +#define CUSTOM_PALETTE_HEIGHT 2 -typedef struct _GtkColorSelection GtkColorSelection; -typedef struct _GtkColorSelectionClass GtkColorSelectionClass; - -typedef struct _GtkColorSelectionDialog GtkColorSelectionDialog; -typedef struct _GtkColorSelectionDialogClass GtkColorSelectionDialogClass; +typedef struct _GtkColorSelection GtkColorSelection; +typedef struct _GtkColorSelectionClass GtkColorSelectionClass; struct _GtkColorSelection { - GtkVBox vbox; - - GtkWidget *wheel_area; - GtkWidget *value_area; - GtkWidget *sample_area; - GtkWidget *sample_area_eb; - - GtkWidget *scales[8]; - GtkWidget *entries[8]; - GtkWidget *opacity_label; - - GdkGC *wheel_gc; - GdkGC *value_gc; - GdkGC *sample_gc; - - GtkUpdateType policy; - gint use_opacity; - gint timer_active; - gint timer_tag; - gdouble values[8]; - gdouble old_values[8]; - - guchar *wheel_buf; - guchar *value_buf; - guchar *sample_buf; + GtkVBox parent; + + /* < private > */ + gpointer private; }; struct _GtkColorSelectionClass { GtkVBoxClass parent_class; - void (* color_changed) (GtkColorSelection *colorsel); -}; - -struct _GtkColorSelectionDialog -{ - GtkWindow window; - - GtkWidget *colorsel; - GtkWidget *main_vbox; - GtkWidget *ok_button; - GtkWidget *reset_button; - GtkWidget *cancel_button; - GtkWidget *help_button; -}; - -struct _GtkColorSelectionDialogClass -{ - GtkWindowClass parent_class; + void (*color_changed) (GtkColorSelection *color_selection); }; -/* ColorSelection */ +/* ColorSelection */ GtkType gtk_color_selection_get_type (void); - -GtkWidget* gtk_color_selection_new (void); - -void gtk_color_selection_set_update_policy (GtkColorSelection *colorsel, - GtkUpdateType policy); - -void gtk_color_selection_set_opacity (GtkColorSelection *colorsel, - gint use_opacity); - -void gtk_color_selection_set_color (GtkColorSelection *colorsel, - gdouble *color); - -void gtk_color_selection_get_color (GtkColorSelection *colorsel, - gdouble *color); - -/* ColorSelectionDialog */ - -GtkType gtk_color_selection_dialog_get_type (void); - -GtkWidget* gtk_color_selection_dialog_new (const gchar *title); +GtkWidget *gtk_color_selection_new (void); +void gtk_color_selection_set_update_policy (GtkColorSelection *colorsel, + GtkUpdateType policy); +gboolean gtk_color_selection_get_use_opacity (GtkColorSelection *colorsel); +void gtk_color_selection_set_use_opacity (GtkColorSelection *colorsel, + gboolean use_opacity); +gboolean gtk_color_selection_get_use_palette (GtkColorSelection *colorsel); +void gtk_color_selection_set_use_palette (GtkColorSelection *colorsel, + gboolean use_palette); + +/* The Color set is an array of doubles, of the following format: + * color[0] = red_channel; + * color[1] = green_channel; + * color[2] = blue_channel; + * color[3] = alpha_channel; + */ +void gtk_color_selection_set_color (GtkColorSelection *colorsel, + gdouble *color); +void gtk_color_selection_get_color (GtkColorSelection *colorsel, + gdouble *color); +void gtk_color_selection_set_old_color (GtkColorSelection *colorsel, + gdouble *color); +void gtk_color_selection_get_old_color (GtkColorSelection *colorsel, + gdouble *color); +void gtk_color_selection_set_palette_color (GtkColorSelection *colorsel, + gint x, + gint y, + gdouble *color); +gboolean gtk_color_selection_get_palette_color (GtkColorSelection *colorsel, + gint x, + gint y, + gdouble *color); +void gtk_color_selection_unset_palette_color(GtkColorSelection *colorsel, + gint x, + gint y); +gboolean gtk_color_selection_is_adjusting (GtkColorSelection *colorsel); #ifdef __cplusplus @@ -156,4 +112,4 @@ GtkWidget* gtk_color_selection_dialog_new (const gchar *title); #endif /* __cplusplus */ -#endif /* __GTK_COLORSEL_H__ */ +#endif /* __GTK_COLOR_SELECTION_H__ */ diff --git a/gtk/gtkcolorseldialog.c b/gtk/gtkcolorseldialog.c new file mode 100644 index 0000000000..c884ca96dd --- /dev/null +++ b/gtk/gtkcolorseldialog.c @@ -0,0 +1,138 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ +#include <glib.h> +#include "gtkcolorseldialog.h" +#include "gtkframe.h" +#include "gtkhbbox.h" +#include "gtkbutton.h" + + +static void gtk_color_selection_dialog_class_init (GtkColorSelectionDialogClass *klass); +static void gtk_color_selection_dialog_init (GtkColorSelectionDialog *colorseldiag); + +static GtkWindowClass *color_selection_dialog_parent_class = NULL; + + +/***************************/ +/* GtkColorSelectionDialog */ +/***************************/ + +GtkType +gtk_color_selection_dialog_get_type (void) +{ + static GtkType color_selection_dialog_type = 0; + + if (!color_selection_dialog_type) + { + GtkTypeInfo colorsel_diag_info = + { + "GtkColorSelectionDialog", + sizeof (GtkColorSelectionDialog), + sizeof (GtkColorSelectionDialogClass), + (GtkClassInitFunc) gtk_color_selection_dialog_class_init, + (GtkObjectInitFunc) gtk_color_selection_dialog_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + color_selection_dialog_type = gtk_type_unique (GTK_TYPE_DIALOG, &colorsel_diag_info); + } + + return color_selection_dialog_type; +} + +static void +gtk_color_selection_dialog_class_init (GtkColorSelectionDialogClass *klass) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) klass; + + color_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_DIALOG); +} + +static void +gtk_color_selection_dialog_init (GtkColorSelectionDialog *colorseldiag) +{ + GtkWidget *action_area_button_box, *frame; + + gtk_widget_set_visual (GTK_WIDGET (colorseldiag), gdk_rgb_get_visual ()); + gtk_widget_set_colormap (GTK_WIDGET (colorseldiag), gdk_rgb_get_cmap ()); + + gtk_widget_push_visual (gdk_rgb_get_visual ()); + gtk_widget_push_colormap (gdk_rgb_get_cmap ()); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (colorseldiag)->vbox), frame); + gtk_container_set_border_width (GTK_CONTAINER (frame), 10); + gtk_widget_show (frame); + + colorseldiag->colorsel = gtk_color_selection_new (); + gtk_color_selection_set_use_palette (GTK_COLOR_SELECTION(colorseldiag->colorsel), FALSE); + gtk_color_selection_set_use_opacity (GTK_COLOR_SELECTION(colorseldiag->colorsel), FALSE); + gtk_container_add (GTK_CONTAINER (frame), colorseldiag->colorsel); + gtk_widget_show (colorseldiag->colorsel); + + action_area_button_box = gtk_hbutton_box_new (); + gtk_button_box_set_layout (GTK_BUTTON_BOX(action_area_button_box), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing (GTK_BUTTON_BOX(action_area_button_box), 5); + gtk_box_pack_end (GTK_BOX (GTK_DIALOG (colorseldiag)->action_area), action_area_button_box, TRUE, TRUE, 0); + gtk_widget_show (action_area_button_box); + + colorseldiag->ok_button = gtk_button_new_with_label (_("OK")); + GTK_WIDGET_SET_FLAGS (colorseldiag->ok_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area_button_box), colorseldiag->ok_button, TRUE, TRUE, 0); + gtk_widget_grab_default (colorseldiag->ok_button); + gtk_widget_show (colorseldiag->ok_button); + + colorseldiag->cancel_button = gtk_button_new_with_label (_("Cancel")); + GTK_WIDGET_SET_FLAGS (colorseldiag->cancel_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area_button_box), colorseldiag->cancel_button, TRUE, TRUE, 0); + gtk_widget_show (colorseldiag->cancel_button); + + colorseldiag->help_button = gtk_button_new_with_label (_("Help")); + GTK_WIDGET_SET_FLAGS (colorseldiag->help_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area_button_box), colorseldiag->help_button, TRUE, TRUE, 0); + gtk_widget_show (colorseldiag->help_button); + + gtk_widget_pop_colormap (); + gtk_widget_pop_visual (); +} + +GtkWidget* +gtk_color_selection_dialog_new (const gchar *title) +{ + GtkColorSelectionDialog *colorseldiag; + + colorseldiag = gtk_type_new (GTK_TYPE_COLOR_SELECTION_DIALOG); + gtk_window_set_title (GTK_WINDOW (colorseldiag), title); + gtk_window_set_policy(GTK_WINDOW (colorseldiag), FALSE, FALSE, TRUE); + + return GTK_WIDGET (colorseldiag); +} + diff --git a/gtk/gtkcolorseldialog.h b/gtk/gtkcolorseldialog.h new file mode 100644 index 0000000000..ba6530cc21 --- /dev/null +++ b/gtk/gtkcolorseldialog.h @@ -0,0 +1,76 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ +#ifndef __GTK_COLOR_SELECTION_DIALOG_H__ +#define __GTK_COLOR_SELECTION_DIALOG_H__ + +#include <gtk/gtkdialog.h> +#include <gtk/gtkcolorsel.h> +#include <gtk/gtkvbox.h> +#include "gtkintl.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GTK_TYPE_COLOR_SELECTION_DIALOG (gtk_color_selection_dialog_get_type ()) +#define GTK_COLOR_SELECTION_DIALOG(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_COLOR_SELECTION_DIALOG, GtkColorSelectionDialog)) +#define GTK_COLOR_SELECTION_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_SELECTION_DIALOG, GtkColorSelectionDialogClass)) +#define GTK_IS_COLOR_SELECTION_DIALOG(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_COLOR_SELECTION_DIALOG)) +#define GTK_IS_COLOR_SELECTION_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_SELECTION_DIALOG)) +#define GTK_COLOR_SELECTION_DIALOG_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_COLOR_SELECTION_DIALOG, GtkColorSelectionDialogClass)) + + +typedef struct _GtkColorSelectionDialog GtkColorSelectionDialog; +typedef struct _GtkColorSelectionDialogClass GtkColorSelectionDialogClass; + + +struct _GtkColorSelectionDialog +{ + GtkDialog dialog; + + GtkWidget *colorsel; + GtkWidget *ok_button; + GtkWidget *cancel_button; + GtkWidget *help_button; +}; + +struct _GtkColorSelectionDialogClass +{ + GtkDialogClass parent_class; +}; + + +/* ColorSelectionDialog */ +GtkType gtk_color_selection_dialog_get_type (void); +GtkWidget* gtk_color_selection_dialog_new (const gchar *title); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_COLOR_SELECTION_DIALOG_H__ */ diff --git a/gtk/gtkhsv.c b/gtk/gtkhsv.c new file mode 100644 index 0000000000..568a140892 --- /dev/null +++ b/gtk/gtkhsv.c @@ -0,0 +1,1407 @@ +/* HSV color selector for GTK+ + * + * Copyright (C) 1999 The Free Software Foundation + * + * Authors: Simon Budig <Simon.Budig@unix-ag.org> (original code) + * Federico Mena-Quintero <federico@gimp.org> (cleanup for GTK+) + * Jonathan Blandford <jrb@redhat.com> (cleanup for GTK+) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <math.h> +#include "gtksignal.h" +#include "gtkhsv.h" + + + +/* Default width/height */ +#define DEFAULT_SIZE 100 + +/* Default ring width */ +#define DEFAULT_RING_WIDTH 10 + + + +/* Dragging modes */ +typedef enum { + DRAG_NONE, + DRAG_H, + DRAG_SV +} DragMode; + +/* Private part of the GtkHSV structure */ +typedef struct { + /* Color value */ + double h; + double s; + double v; + + /* Size and ring width */ + int size; + int ring_width; + + /* Window for capturing events */ + GdkWindow *window; + + /* GC for drawing */ + GdkGC *gc; + + /* Dragging mode */ + DragMode mode; +} HSVPrivate; + + + +/* Signal IDs */ + +enum { + CHANGED, + LAST_SIGNAL +}; + +static void gtk_hsv_class_init (GtkHSVClass *class); +static void gtk_hsv_init (GtkHSV *hsv); +static void gtk_hsv_destroy (GtkObject *object); + +static void gtk_hsv_map (GtkWidget *widget); +static void gtk_hsv_unmap (GtkWidget *widget); +static void gtk_hsv_realize (GtkWidget *widget); +static void gtk_hsv_unrealize (GtkWidget *widget); +static void gtk_hsv_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void gtk_hsv_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gint gtk_hsv_button_press (GtkWidget *widget, GdkEventButton *event); +static gint gtk_hsv_button_release (GtkWidget *widget, GdkEventButton *event); +static gint gtk_hsv_motion (GtkWidget *widget, GdkEventMotion *event); +static gint gtk_hsv_expose (GtkWidget *widget, GdkEventExpose *event); + +static guint hsv_signals[LAST_SIGNAL]; + +static GtkWidgetClass *parent_class; + + + +/** + * gtk_hsv_get_type: + * @void: + * + * Registers the &GtkHSV class if necessary, and returns the type ID associated + * to it. + * + * Return value: The type ID of the &GtkHSV class. + **/ +GtkType +gtk_hsv_get_type (void) +{ + static GtkType hsv_type = 0; + + if (!hsv_type) { + static const GtkTypeInfo hsv_info = { + "GtkHSV", + sizeof (GtkHSV), + sizeof (GtkHSVClass), + (GtkClassInitFunc) gtk_hsv_class_init, + (GtkObjectInitFunc) gtk_hsv_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + hsv_type = gtk_type_unique (gtk_widget_get_type (), &hsv_info); + } + + return hsv_type; +} + +/* Class initialization function for the HSV color selector */ +static void +gtk_hsv_class_init (GtkHSVClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass *) class; + widget_class = (GtkWidgetClass *) class; + + parent_class = gtk_type_class (gtk_widget_get_type ()); + + hsv_signals[CHANGED] = + gtk_signal_new ("changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkHSVClass, changed), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, hsv_signals, LAST_SIGNAL); + + object_class->destroy = gtk_hsv_destroy; + + widget_class->map = gtk_hsv_map; + widget_class->unmap = gtk_hsv_unmap; + widget_class->realize = gtk_hsv_realize; + widget_class->unrealize = gtk_hsv_unrealize; + widget_class->size_request = gtk_hsv_size_request; + widget_class->size_allocate = gtk_hsv_size_allocate; + widget_class->button_press_event = gtk_hsv_button_press; + widget_class->button_release_event = gtk_hsv_button_release; + widget_class->motion_notify_event = gtk_hsv_motion; + widget_class->expose_event = gtk_hsv_expose; +} + +/* Object initialization function for the HSV color selector */ +static void +gtk_hsv_init (GtkHSV *hsv) +{ + HSVPrivate *priv; + + priv = g_new0 (HSVPrivate, 1); + hsv->priv = priv; + + GTK_WIDGET_SET_FLAGS (hsv, GTK_NO_WINDOW); + + priv->h = 0.0; + priv->s = 0.0; + priv->v = 0.0; + + priv->size = DEFAULT_SIZE; + priv->ring_width = DEFAULT_RING_WIDTH; +} + +/* Destroy handler for the HSV color selector */ +static void +gtk_hsv_destroy (GtkObject *object) +{ + GtkHSV *hsv; + HSVPrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_HSV (object)); + + hsv = GTK_HSV (object); + priv = hsv->priv; + + g_free (priv); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + + + +/* Default signal handlers */ + +/* Map handler for the HSV color selector */ +static void +gtk_hsv_map (GtkWidget *widget) +{ + GtkHSV *hsv; + HSVPrivate *priv; + + hsv = GTK_HSV (widget); + priv = hsv->priv; + + if (GTK_WIDGET_MAPPED (widget)) + return; + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + gdk_window_show (priv->window); +} + +/* Unmap handler for the HSV color selector */ +static void +gtk_hsv_unmap (GtkWidget *widget) +{ + GtkHSV *hsv; + HSVPrivate *priv; + + hsv = GTK_HSV (widget); + priv = hsv->priv; + + if (!GTK_WIDGET_MAPPED (widget)) + return; + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + + gdk_window_hide (priv->window); +} + +/* Realize handler for the HSV color selector */ +static void +gtk_hsv_realize (GtkWidget *widget) +{ + GtkHSV *hsv; + HSVPrivate *priv; + GdkWindowAttr attr; + int attr_mask; + GdkWindow *parent_window; + + hsv = GTK_HSV (widget); + priv = hsv->priv; + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + /* Create window */ + + attr.window_type = GDK_WINDOW_CHILD; + attr.x = widget->allocation.x; + attr.y = widget->allocation.y; + attr.width = widget->allocation.width; + attr.height = widget->allocation.height; + attr.wclass = GDK_INPUT_ONLY; + attr.event_mask = gtk_widget_get_events (widget); + attr.event_mask |= (GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_POINTER_MOTION_MASK); + + attr_mask = GDK_WA_X | GDK_WA_Y; + + parent_window = gtk_widget_get_parent_window (widget); + + widget->window = parent_window; + gdk_window_ref (widget->window); + + priv->window = gdk_window_new (parent_window, &attr, attr_mask); + gdk_window_set_user_data (priv->window, hsv); + + widget->style = gtk_style_attach (widget->style, widget->window); + + /* Create GC */ + + priv->gc = gdk_gc_new (parent_window); +} + +/* Unrealize handler for the HSV color selector */ +static void +gtk_hsv_unrealize (GtkWidget *widget) +{ + GtkHSV *hsv; + HSVPrivate *priv; + + hsv = GTK_HSV (widget); + priv = hsv->priv; + + gdk_window_set_user_data (priv->window, NULL); + gdk_window_destroy (priv->window); + priv->window = NULL; + + gdk_gc_unref (priv->gc); + priv->gc = NULL; + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + +/* Size_request handler for the HSV color selector */ +static void +gtk_hsv_size_request (GtkWidget *widget, GtkRequisition *requisition) +{ + GtkHSV *hsv; + HSVPrivate *priv; + + hsv = GTK_HSV (widget); + priv = hsv->priv; + + requisition->width = priv->size; + requisition->height = priv->size; +} + +/* Size_allocate handler for the HSV color selector */ +static void +gtk_hsv_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + GtkHSV *hsv; + HSVPrivate *priv; + + hsv = GTK_HSV (widget); + priv = hsv->priv; + + widget->allocation = *allocation; + + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (priv->window, + allocation->x, + allocation->y, + allocation->width, + allocation->height); +} + + + +/* Utility functions */ + +#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11) + +/* Converts from HSV to RGB */ +static void +hsv_to_rgb (double *h, double *s, double *v) +{ + double hue, saturation, value; + double f, p, q, t; + + if (*s == 0.0) { + *h = *v; + *s = *v; + *v = *v; /* heh */ + } else { + hue = *h * 6.0; + saturation = *s; + value = *v; + + if (hue == 6.0) + hue = 0.0; + + f = hue - (int) hue; + p = value * (1.0 - saturation); + q = value * (1.0 - saturation * f); + t = value * (1.0 - saturation * (1.0 - f)); + + switch ((int) hue) { + case 0: + *h = value; + *s = t; + *v = p; + break; + + case 1: + *h = q; + *s = value; + *v = p; + break; + + case 2: + *h = p; + *s = value; + *v = t; + break; + + case 3: + *h = p; + *s = q; + *v = value; + break; + + case 4: + *h = t; + *s = p; + *v = value; + break; + + case 5: + *h = value; + *s = p; + *v = q; + break; + + default: + g_assert_not_reached (); + } + } +} + +/* Converts from RGB to HSV */ +static void +rgb_to_hsv (double *r, double *g, double *b) +{ + double red, green, blue; + double h, s, v; + double min, max; + double delta; + + red = *r; + green = *g; + blue = *b; + + h = 0.0; + + if (red > green) { + if (red > blue) + max = red; + else + max = blue; + + if (green < blue) + min = green; + else + min = blue; + } else { + if (green > blue) + max = green; + else + max = blue; + + if (red < blue) + min = red; + else + min = blue; + } + + v = max; + + if (max != 0.0) + s = (max - min) / max; + else + s = 0.0; + + if (s == 0.0) + h = 0.0; + else { + delta = max - min; + + if (red == max) + h = (green - blue) / delta; + else if (green == max) + h = 2 + (blue - red) / delta; + else if (blue == max) + h = 4 + (red - green) / delta; + + h /= 6.0; + + if (h < 0.0) + h += 1.0; + else if (h > 1.0) + h -= 1.0; + } + + *r = h; + *g = s; + *b = v; +} + +/* Computes the vertices of the saturation/value triangle */ +static void +compute_triangle (GtkHSV *hsv, int *hx, int *hy, int *sx, int *sy, int *vx, int *vy) +{ + HSVPrivate *priv; + double center; + double inner, outer; + double angle; + + priv = hsv->priv; + + center = priv->size / 2.0; + outer = priv->size / 2.0; + inner = outer - priv->ring_width; + angle = priv->h * 2.0 * M_PI; + + *hx = floor (center + cos (angle) * inner + 0.5); + *hy = floor (center - sin (angle) * inner + 0.5); + *sx = floor (center + cos (angle + 2.0 * M_PI / 3.0) * inner + 0.5); + *sy = floor (center - sin (angle + 2.0 * M_PI / 3.0) * inner + 0.5); + *vx = floor (center + cos (angle + 4.0 * M_PI / 3.0) * inner + 0.5); + *vy = floor (center - sin (angle + 4.0 * M_PI / 3.0) * inner + 0.5); +} + +/* Computes whether a point is inside the hue ring */ +static gboolean +is_in_ring (GtkHSV *hsv, double x, double y) +{ + HSVPrivate *priv; + double dx, dy, dist; + double center, inner, outer; + + priv = hsv->priv; + + center = priv->size / 2.0; + outer = priv->size / 2.0; + inner = outer - priv->ring_width; + + dx = x - center; + dy = center - y; + dist = dx * dx + dy * dy; + + return (dist >= inner * inner && dist <= outer * outer); +} + +/* Computes a saturation/value pair based on the mouse coordinates */ +static void +compute_sv (GtkHSV *hsv, double x, double y, double *s, double *v) +{ + HSVPrivate *priv; + int ihx, ihy, isx, isy, ivx, ivy; + double hx, hy, sx, sy, vx, vy; + double center; + + priv = hsv->priv; + + compute_triangle (hsv, &ihx, &ihy, &isx, &isy, &ivx, &ivy); + center = priv->size / 2.0; + hx = ihx - center; + hy = center - ihy; + sx = isx - center; + sy = center - isy; + vx = ivx - center; + vy = center - ivy; + x -= center; + y = center - y; + + if (vx * (x - sx) + vy * (y - sy) < 0.0) { + *s = 1.0; + *v = (((x - sx) * (hx - sx) + (y - sy) * (hy-sy)) + / ((hx - sx) * (hx - sx) + (hy - sy) * (hy - sy))); + + if (*v < 0.0) + *v = 0.0; + else if (*v > 1.0) + *v = 1.0; + } else if (hx * (x - sx) + hy * (y - sy) < 0.0) { + *s = 0.0; + *v = (((x - sx) * (vx - sx) + (y - sy) * (vy - sy)) + / ((vx - sx) * (vx - sx) + (vy - sy) * (vy - sy))); + + if (*v < 0.0) + *v = 0.0; + else if (*v > 1.0) + *v = 1.0; + } else if (sx * (x - hx) + sy * (y - hy) < 0.0) { + *v = 1.0; + *s = (((x - vx) * (hx - vx) + (y - vy) * (hy - vy)) / + ((hx - vx) * (hx - vx) + (hy - vy) * (hy - vy))); + + if (*s < 0.0) + *s = 0.0; + else if (*s > 1.0) + *s = 1.0; + } else { + *v = (((x - sx) * (hy - vy) - (y - sy) * (hx - vx)) + / ((vx - sx) * (hy - vy) - (vy - sy) * (hx - vx))); + + if (*v<= 0.0) { + *v = 0.0; + *s = 0.0; + } else { + if (*v > 1.0) + *v = 1.0; + + *s = (y - sy - *v * (vy - sy)) / (*v * (hy - vy)); + if (*s < 0.0) + *s = 0.0; + else if (*s > 1.0) + *s = 1.0; + } + } +} + +/* Computes whether a point is inside the saturation/value triangle */ +static gboolean +is_in_triangle (GtkHSV *hsv, double x, double y) +{ + int hx, hy, sx, sy, vx, vy; + double det, s, v; + + compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy); + + det = (vx - sx) * (hy - sy) - (vy - sy) * (hx - sx); + + s = ((x - sx) * (hy - sy) - (y - sy) * (hx - sx)) / det; + v = ((vx - sx) * (y - sy) - (vy - sy) * (x - sx)) / det; + + return (s >= 0.0 && v >= 0.0 && s + v <= 1.0); +} + +/* Computes a value based on the mouse coordinates */ +static double +compute_v (GtkHSV *hsv, double x, double y) +{ + HSVPrivate *priv; + double center; + double dx, dy; + double angle; + + priv = hsv->priv; + + center = priv->size / 2.0; + dx = x - center; + dy = center - y; + + angle = atan2 (dy, dx); + if (angle < 0.0) + angle += 2.0 * M_PI; + + return angle / (2.0 * M_PI); +} + + + +/* Event handlers */ + +static void +set_cross_grab (GtkHSV *hsv, guint32 time) +{ + HSVPrivate *priv; + GdkCursor *cursor; + + priv = hsv->priv; + + cursor = gdk_cursor_new (GDK_CROSSHAIR); + gdk_pointer_grab (priv->window, FALSE, + (GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK + | GDK_BUTTON_RELEASE_MASK), + NULL, + cursor, + time); + gdk_cursor_destroy (cursor); + +} + +/* Button_press_event handler for the HSV color selector */ +static gint +gtk_hsv_button_press (GtkWidget *widget, GdkEventButton *event) +{ + GtkHSV *hsv; + HSVPrivate *priv; + double x, y; + + hsv = GTK_HSV (widget); + priv = hsv->priv; + + if (priv->mode != DRAG_NONE || event->button != 1) + return FALSE; + + x = event->x; + y = event->y; + + if (is_in_ring (hsv, x, y)) { + priv->mode = DRAG_H; + set_cross_grab (hsv, event->time); + + gtk_hsv_set_color (hsv, + compute_v (hsv, x, y), + priv->s, + priv->v); + + return TRUE; + } + + if (is_in_triangle (hsv, x, y)) { + double s, v; + + priv->mode = DRAG_SV; + set_cross_grab (hsv, event->time); + + compute_sv (hsv, x, y, &s, &v); + gtk_hsv_set_color (hsv, priv->h, s, v); + return TRUE; + } + + return FALSE; +} + +/* Button_release_event handler for the HSV color selector */ +static gint +gtk_hsv_button_release (GtkWidget *widget, GdkEventButton *event) +{ + GtkHSV *hsv; + HSVPrivate *priv; + DragMode mode; + double x, y; + + hsv = GTK_HSV (widget); + priv = hsv->priv; + + if (priv->mode == DRAG_NONE || event->button != 1) + return FALSE; + + /* Set the drag mode to DRAG_NONE so that signal handlers for "catched" + * can see that this is the final color state. + */ + + mode = priv->mode; + priv->mode = DRAG_NONE; + + x = event->x; + y = event->y; + + if (mode == DRAG_H) + gtk_hsv_set_color (hsv, compute_v (hsv, x, y), priv->s, priv->v); + else if (mode == DRAG_SV) { + double s, v; + + compute_sv (hsv, x, y, &s, &v); + gtk_hsv_set_color (hsv, priv->h, s, v); + } else + g_assert_not_reached (); + + gdk_pointer_ungrab (event->time); + + return TRUE; +} + +/* Motion_notify_event handler for the HSV color selector */ +static gint +gtk_hsv_motion (GtkWidget *widget, GdkEventMotion *event) +{ + GtkHSV *hsv; + HSVPrivate *priv; + double x, y; + gint ix, iy; + GdkModifierType mods; + + hsv = GTK_HSV (widget); + priv = hsv->priv; + + if (priv->mode == DRAG_NONE) + return FALSE; + + if (event->is_hint) { + gdk_window_get_pointer (priv->window, &ix, &iy, &mods); + x = ix; + y = iy; + } else { + x = event->x; + y = event->y; + } + + if (priv->mode == DRAG_H) { + gtk_hsv_set_color (hsv, compute_v (hsv, x, y), priv->s, priv->v); + return TRUE; + } else if (priv->mode == DRAG_SV) { + double s, v; + + compute_sv (hsv, x, y, &s, &v); + gtk_hsv_set_color (hsv, priv->h, s, v); + return TRUE; + } + + g_assert_not_reached (); + return FALSE; +} + + + +/* Redrawing */ + +/* Paints the hue ring */ +static void +paint_ring (GtkHSV *hsv, GdkDrawable *drawable, int x, int y, int width, int height) +{ + HSVPrivate *priv; + int xx, yy; + double dx, dy, dist; + double center; + double inner, outer; + guchar *buf, *p; + double angle; + double hue; + double r, g, b; + GdkBitmap *mask; + GdkGC *gc; + GdkColor color; + + priv = hsv->priv; + + center = priv->size / 2.0; + + outer = priv->size / 2.0; + inner = outer - priv->ring_width; + + /* Paint the ring */ + + buf = g_new (guchar, width * height * 3); + + for (yy = 0; yy < height; yy++) { + p = buf + yy * width * 3; + + dy = -(yy + y - center); + + for (xx = 0; xx < width; xx++) { + dx = xx + x - center; + + dist = dx * dx + dy * dy; + if (dist < (inner * inner) || dist > (outer * outer)) { + *p++ = 0; + *p++ = 0; + *p++ = 0; + continue; + } + + angle = atan2 (dy, dx); + if (angle < 0.0) + angle += 2.0 * M_PI; + + hue = angle / (2.0 * M_PI); + + r = hue; + g = 1.0; + b = 1.0; + hsv_to_rgb (&r, &g, &b); + + *p++ = floor (r * 255 + 0.5); + *p++ = floor (g * 255 + 0.5); + *p++ = floor (b * 255 + 0.5); + } + } + + /* Create clipping mask */ + + mask = gdk_pixmap_new (NULL, width, height, 1); + gc = gdk_gc_new (mask); + + color.pixel = 0; + gdk_gc_set_foreground (gc, &color); + gdk_draw_rectangle (mask, gc, TRUE, + 0, 0, width, height); + + + color.pixel = 1; + gdk_gc_set_foreground (gc, &color); + gdk_draw_arc (mask, gc, TRUE, + -x, -y, + priv->size - 1, priv->size - 1, + 0, 360 * 64); + + color.pixel = 0; + gdk_gc_set_foreground (gc, &color); + gdk_draw_arc (mask, gc, TRUE, + -x + priv->ring_width - 1, -y + priv->ring_width - 1, + priv->size - 2 * priv->ring_width + 1, priv->size - 2 * priv->ring_width + 1, + 0, 360 * 64); + + gdk_gc_unref (gc); + + gdk_gc_set_clip_mask (priv->gc, mask); + gdk_gc_set_clip_origin (priv->gc, 0, 0); + + /* Draw ring */ + + gdk_draw_rgb_image_dithalign (drawable, priv->gc, 0, 0, width, height, + GDK_RGB_DITHER_MAX, + buf, + width * 3, + x, y); + + /* Draw value marker */ + + r = priv->h; + g = 1.0; + b = 1.0; + hsv_to_rgb (&r, &g, &b); + + if (INTENSITY (r, g, b) > 0.5) + gdk_rgb_gc_set_foreground (priv->gc, 0x000000); + else + gdk_rgb_gc_set_foreground (priv->gc, 0xffffff); + + gdk_draw_line (drawable, priv->gc, + -x + center, -y + center, + -x + center + cos (priv->h * 2.0 * M_PI) * center, + -y + center - sin (priv->h * 2.0 * M_PI) * center); + + gdk_gc_set_clip_mask (priv->gc, NULL); + gdk_bitmap_unref (mask); + + g_free (buf); + + /* Draw ring outline */ + + gdk_rgb_gc_set_foreground (priv->gc, 0x000000); + + gdk_draw_arc (drawable, priv->gc, FALSE, + -x, -y, + priv->size - 1, priv->size - 1, + 0, 360 * 64); + gdk_draw_arc (drawable, priv->gc, FALSE, + -x + priv->ring_width - 1, -y + priv->ring_width - 1, + priv->size - 2 * priv->ring_width + 1, priv->size - 2 * priv->ring_width + 1, + 0, 360 * 64); +} + +/* Converts an HSV triplet to an integer RGB triplet */ +static void +get_color (double h, double s, double v, int *r, int *g, int *b) +{ + hsv_to_rgb (&h, &s, &v); + + *r = floor (h * 255 + 0.5); + *g = floor (s * 255 + 0.5); + *b = floor (v * 255 + 0.5); +} + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +#define LERP(a, b, v1, v2, i) (((v2) - (v1) != 0) \ + ? ((a) + ((b) - (a)) * ((i) - (v1)) / ((v2) - (v1))) \ + : (a)) + +/* Paints the HSV triangle */ +static void +paint_triangle (GtkHSV *hsv, GdkDrawable *drawable, int x, int y, int width, int height) +{ + HSVPrivate *priv; + int hx, hy, sx, sy, vx, vy; /* HSV vertices */ + int x1, y1, r1, g1, b1; /* First vertex in scanline order */ + int x2, y2, r2, g2, b2; /* Second vertex */ + int x3, y3, r3, g3, b3; /* Third vertex */ + int t; + guchar *buf, *p; + int xl, xr, rl, rr, gl, gr, bl, br; /* Scanline data */ + int xx, yy; + GdkBitmap *mask; + GdkGC *gc; + GdkColor color; + GdkPoint points[3]; + double r, g, b; + + priv = hsv->priv; + + /* Compute triangle's vertices */ + + compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy); + + x1 = hx; + y1 = hy; + get_color (priv->h, 1.0, 1.0, &r1, &g1, &b1); + + x2 = sx; + y2 = sy; + get_color (priv->h, 1.0, 0.0, &r2, &g2, &b2); + + x3 = vx; + y3 = vy; + get_color (priv->h, 0.0, 1.0, &r3, &g3, &b3); + + if (y2 > y3) { + SWAP (x2, x3, t); + SWAP (y2, y3, t); + SWAP (r2, r3, t); + SWAP (g2, g3, t); + SWAP (b2, b3, t); + } + + if (y1 > y3) { + SWAP (x1, x3, t); + SWAP (y1, y3, t); + SWAP (r1, r3, t); + SWAP (g1, g3, t); + SWAP (b1, b3, t); + } + + if (y1 > y2) { + SWAP (x1, x2, t); + SWAP (y1, y2, t); + SWAP (r1, r2, t); + SWAP (g1, g2, t); + SWAP (b1, b2, t); + } + + /* Shade the triangle */ + + buf = g_new (guchar, width * height * 3); + + for (yy = 0; yy < height; yy++) { + p = buf + yy * width * 3; + + if (yy + y < y1 || yy + y > y3) + for (xx = 0; xx < width; xx++) { + *p++ = 0; + *p++ = 0; + *p++ = 0; + } + else { + if (yy + y < y2) { + xl = LERP (x1, x2, y1, y2, yy + y); + + rl = LERP (r1, r2, y1, y2, yy + y); + gl = LERP (g1, g2, y1, y2, yy + y); + bl = LERP (b1, b2, y1, y2, yy + y); + } else { + xl = LERP (x2, x3, y2, y3, yy + y); + + rl = LERP (r2, r3, y2, y3, yy + y); + gl = LERP (g2, g3, y2, y3, yy + y); + bl = LERP (b2, b3, y2, y3, yy + y); + } + + xr = LERP (x1, x3, y1, y3, yy + y); + + rr = LERP (r1, r3, y1, y3, yy + y); + gr = LERP (g1, g3, y1, y3, yy + y); + br = LERP (b1, b3, y1, y3, yy + y); + + if (xl > xr) { + SWAP (xl, xr, t); + SWAP (rl, rr, t); + SWAP (gl, gr, t); + SWAP (bl, br, t); + } + + for (xx = 0; xx < width; xx++) { + if (xx + x < xl || xx + x > xr) { + *p++ = 0; + *p++ = 0; + *p++ = 0; + } else { + *p++ = LERP (rl, rr, xl, xr, xx + x); + *p++ = LERP (gl, gr, xl, xr, xx + x); + *p++ = LERP (bl, br, xl, xr, xx + x); + } + } + } + } + + /* Create clipping mask */ + + mask = gdk_pixmap_new (NULL, width, height, 1); + gc = gdk_gc_new (mask); + + color.pixel = 0; + gdk_gc_set_foreground (gc, &color); + gdk_draw_rectangle (mask, gc, TRUE, + 0, 0, width, height); + + color.pixel = 1; + gdk_gc_set_foreground (gc, &color); + + points[0].x = x1 - x; + points[0].y = y1 - y; + points[1].x = x2 - x; + points[1].y = y2 - y; + points[2].x = x3 - x; + points[2].y = y3 - y; + gdk_draw_polygon (mask, gc, TRUE, points, 3); + + gdk_gc_unref (gc); + + gdk_gc_set_clip_mask (priv->gc, mask); + gdk_gc_set_clip_origin (priv->gc, 0, 0); + + /* Draw triangle */ + + gdk_draw_rgb_image_dithalign (drawable, priv->gc, 0, 0, width, height, + GDK_RGB_DITHER_MAX, + buf, + width * 3, + x, y); + + gdk_gc_set_clip_mask (priv->gc, NULL); + gdk_bitmap_unref (mask); + + g_free (buf); + + /* Draw triangle outline */ + + gdk_rgb_gc_set_foreground (priv->gc, 0x000000); + + gdk_draw_polygon (drawable, priv->gc, FALSE, points, 3); + + /* Draw value marker */ + + xx = floor (sx + (vx - sx) * priv->v + (hx - vx) * priv->s * priv->v + 0.5); + yy = floor (sy + (vy - sy) * priv->v + (hy - vy) * priv->s * priv->v + 0.5); + + r = priv->h; + g = priv->s; + b = priv->v; + hsv_to_rgb (&r, &g, &b); + + if (INTENSITY (r, g, b) > 0.5) + gdk_rgb_gc_set_foreground (priv->gc, 0x000000); + else + gdk_rgb_gc_set_foreground (priv->gc, 0xffffff); + + gdk_draw_arc (drawable, priv->gc, FALSE, + xx - 3, yy - 3, + 6, 6, + 0, 360 * 64); + gdk_draw_arc (drawable, priv->gc, FALSE, + xx - 2, yy - 2, + 4, 4, + 0, 360 * 64); +} + +/* Paints the contents of the HSV color selector */ +static void +paint (GtkHSV *hsv, GdkDrawable *drawable, int x, int y, int width, int height) +{ + paint_ring (hsv, drawable, x, y, width, height); + paint_triangle (hsv, drawable, x, y, width, height); +} + +/* Expose_event handler for the HSV color selector */ +static gint +gtk_hsv_expose (GtkWidget *widget, GdkEventExpose *event) +{ + GtkHSV *hsv; + HSVPrivate *priv; + GdkRectangle rect, dest; + GdkPixmap *pixmap; + + hsv = GTK_HSV (widget); + priv = hsv->priv; + + if (!(GTK_WIDGET_DRAWABLE (widget) && event->window == widget->window)) + return FALSE; + + rect.x = widget->allocation.x; + rect.y = widget->allocation.y; + rect.width = widget->allocation.width; + rect.height = widget->allocation.height; + + if (!gdk_rectangle_intersect (&event->area, &rect, &dest)) + return FALSE; + + pixmap = gdk_pixmap_new (widget->window, dest.width, dest.height, + gtk_widget_get_visual (widget)->depth); + + rect = dest; + rect.x = 0; + rect.y = 0; + + gdk_draw_rectangle (pixmap, + widget->style->bg_gc[GTK_WIDGET_STATE (widget)], + TRUE, + 0, 0, dest.width, dest.height); + paint (hsv, pixmap, + dest.x - widget->allocation.x, dest.y - widget->allocation.y, + dest.width, dest.height); + + gdk_draw_pixmap (widget->window, + priv->gc, + pixmap, + 0, 0, + dest.x, + dest.y, + event->area.width, event->area.height); + + gdk_pixmap_unref (pixmap); + + return FALSE; +} + + + +/** + * gtk_hsv_new: + * @void: + * + * Creates a new HSV color selector. + * + * Return value: A newly-created HSV color selector. + **/ +GtkWidget * +gtk_hsv_new (void) +{ + return GTK_WIDGET (gtk_type_new (gtk_hsv_get_type ())); +} + +/** + * gtk_hsv_set_color: + * @hsv: An HSV color selector. + * @h: Hue. + * @s: Saturation. + * @v: Value. + * + * Sets the current color in an HSV color selector. Color component values must + * be in the [0.0, 1.0] range. + **/ +void +gtk_hsv_set_color (GtkHSV *hsv, double h, double s, double v) +{ + HSVPrivate *priv; + + g_return_if_fail (hsv != NULL); + g_return_if_fail (GTK_IS_HSV (hsv)); + g_return_if_fail (h >= 0.0 && h <= 1.0); + g_return_if_fail (s >= 0.0 && s <= 1.0); + g_return_if_fail (v >= 0.0 && v <= 1.0); + + priv = hsv->priv; + + priv->h = h; + priv->s = s; + priv->v = v; + + gtk_signal_emit (GTK_OBJECT (hsv), hsv_signals[CHANGED]); + + gtk_widget_queue_draw (GTK_WIDGET (hsv)); +} + +/** + * gtk_hsv_get_color: + * @hsv: An HSV color selector. + * @h: Return value for the hue. + * @s: Return value for the saturation. + * @v: Return value for the value. + * + * Queries the current color in an HSV color selector. Returned values will be + * in the [0.0, 1.0] range. + **/ +void +gtk_hsv_get_color (GtkHSV *hsv, double *h, double *s, double *v) +{ + HSVPrivate *priv; + + g_return_if_fail (hsv != NULL); + g_return_if_fail (GTK_IS_HSV (hsv)); + + priv = hsv->priv; + + if (h) + *h = priv->h; + + if (s) + *s = priv->s; + + if (v) + *v = priv->v; +} + +/** + * gtk_hsv_set_metrics: + * @hsv: An HSV color selector. + * @size: Diameter for the hue ring. + * @ring_width: Width of the hue ring. + * + * Sets the size and ring width of an HSV color selector. + **/ +void +gtk_hsv_set_metrics (GtkHSV *hsv, int size, int ring_width) +{ + HSVPrivate *priv; + int same_size; + + g_return_if_fail (hsv != NULL); + g_return_if_fail (GTK_IS_HSV (hsv)); + g_return_if_fail (size > 0); + g_return_if_fail (ring_width > 0); + g_return_if_fail (2 * ring_width + 1 <= size); + + priv = hsv->priv; + + same_size = (priv->size == size); + + priv->size = size; + priv->ring_width = ring_width; + + if (same_size) + gtk_widget_queue_draw (GTK_WIDGET (hsv)); + else + gtk_widget_queue_resize (GTK_WIDGET (hsv)); +} + +/** + * gtk_hsv_get_metrics: + * @hsv: An HSV color selector. + * @size: Return value for the diameter of the hue ring. + * @ring_width: Return value for the width of the hue ring. + * + * Queries the size and ring width of an HSV color selector. + **/ +void +gtk_hsv_get_metrics (GtkHSV *hsv, int *size, int *ring_width) +{ + HSVPrivate *priv; + + g_return_if_fail (hsv != NULL); + g_return_if_fail (GTK_IS_HSV (hsv)); + + priv = hsv->priv; + + if (size) + *size = priv->size; + + if (ring_width) + *ring_width = priv->ring_width; +} + +/** + * gtk_hsv_is_adjusting: + * @hsv: + * + * An HSV color selector can be said to be adjusting if multiple rapid changes + * are being made to its value, for example, when the user is adjusting the + * value with the mouse. This function queries whether the HSV color selector + * is being adjusted or not. + * + * Return value: TRUE if clients can ignore changes to the color value, since + * they may be transitory, or FALSE if they should consider the color value + * status to be final. + **/ +gboolean +gtk_hsv_is_adjusting (GtkHSV *hsv) +{ + HSVPrivate *priv; + + g_return_val_if_fail (hsv != NULL, FALSE); + g_return_val_if_fail (GTK_IS_HSV (hsv), FALSE); + + priv = hsv->priv; + return (priv->mode != DRAG_NONE); +} + +/** + * gtk_hsv_to_rgb: + * @h: Hue. + * @s: Saturation. + * @v: Value. + * @r: Return value for the red component. + * @g: Return value for the green component. + * @b: Return value for the blue component. + * + * Converts a color from HSV space to RGB. Input values must be in the + * [0.0, 1.0] range; output values will be in the same range. + **/ +void +gtk_hsv_to_rgb (double h, double s, double v, double *r, double *g, double *b) +{ + g_return_if_fail (h >= 0.0 && h <= 1.0); + g_return_if_fail (s >= 0.0 && s <= 1.0); + g_return_if_fail (v >= 0.0 && v <= 1.0); + + hsv_to_rgb (&h, &s, &v); + + if (r) + *r = h; + + if (g) + *g = s; + + if (b) + *b = v; +} + +/** + * gtk_hsv_to_rgb: + * @r: Red. + * @g: Green. + * @b: Blue. + * @h: Return value for the hue component. + * @s: Return value for the saturation component. + * @v: Return value for the value component. + * + * Converts a color from RGB space to HSV. Input values must be in the + * [0.0, 1.0] range; output values will be in the same range. + **/ +void +gtk_rgb_to_hsv (double r, double g, double b, double *h, double *s, double *v) +{ + g_return_if_fail (r >= 0.0 && r <= 1.0); + g_return_if_fail (g >= 0.0 && g <= 1.0); + g_return_if_fail (b >= 0.0 && b <= 1.0); + + rgb_to_hsv (&r, &g, &b); + + if (h) + *h = r; + + if (s) + *s = g; + + if (v) + *v = b; +} diff --git a/gtk/gtkhsv.h b/gtk/gtkhsv.h new file mode 100644 index 0000000000..ffe6ff7fc0 --- /dev/null +++ b/gtk/gtkhsv.h @@ -0,0 +1,83 @@ +/* HSV color selector for GTK+ + * + * Copyright (C) 1999 The Free Software Foundation + * + * Authors: Simon Budig <Simon.Budig@unix-ag.org> (original code) + * Federico Mena-Quintero <federico@gimp.org> (cleanup for GTK+) + * Jonathan Blandford <jrb@redhat.com> (cleanup for GTK+) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTK_HSV_H__ +#define __GTK_HSV_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <gtk/gtkwidget.h> + + + +#define GTK_TYPE_HSV (gtk_hsv_get_type ()) +#define GTK_HSV(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_HSV, GtkHSV)) +#define GTK_HSV_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_HSV, GtkHSV)) +#define GTK_IS_HSV(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_HSV)) +#define GTK_IS_HSV_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_HSV)) + + +typedef struct _GtkHSV GtkHSV; +typedef struct _GtkHSVClass GtkHSVClass; + +struct _GtkHSV { + GtkWidget widget; + + /* Private data */ + gpointer priv; +}; + +struct _GtkHSVClass { + GtkWidgetClass parent_class; + + /* Notification signals */ + + void (* changed) (GtkHSV *hsv); +}; + + +GtkType gtk_hsv_get_type (void); + +GtkWidget *gtk_hsv_new (void); + +void gtk_hsv_set_color (GtkHSV *hsv, double h, double s, double v); +void gtk_hsv_get_color (GtkHSV *hsv, double *h, double *s, double *v); + +void gtk_hsv_set_metrics (GtkHSV *hsv, int size, int ring_width); +void gtk_hsv_get_metrics (GtkHSV *hsv, int *size, int *ring_width); + +gboolean gtk_hsv_is_adjusting (GtkHSV *hsv); + +void gtk_hsv_to_rgb (double h, double s, double v, double *r, double *g, double *b); +void gtk_rgb_to_hsv (double r, double g, double b, double *h, double *s, double *v); + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/gtk/testgtk.c b/gtk/testgtk.c index df1b4940de..7a431e9d95 100644 --- a/gtk/testgtk.c +++ b/gtk/testgtk.c @@ -5179,6 +5179,28 @@ color_selection_changed (GtkWidget *w, gtk_color_selection_get_color(colorsel,color); } +static void +opacity_toggled_cb (GtkWidget *w, + GtkColorSelectionDialog *cs) +{ + GtkColorSelection *colorsel; + + colorsel = GTK_COLOR_SELECTION (cs->colorsel); + gtk_color_selection_set_use_opacity (colorsel, + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))); +} + +static void +palette_toggled_cb (GtkWidget *w, + GtkColorSelectionDialog *cs) +{ + GtkColorSelection *colorsel; + + colorsel = GTK_COLOR_SELECTION (cs->colorsel); + gtk_color_selection_set_use_palette (colorsel, + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))); +} + void create_color_selection (void) { @@ -5186,22 +5208,37 @@ create_color_selection (void) if (!window) { + GtkWidget *options_hbox; + GtkWidget *check_button; + window = gtk_color_selection_dialog_new ("color selection dialog"); - gtk_color_selection_set_opacity ( + gtk_color_selection_set_use_opacity ( GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (window)->colorsel), TRUE); - gtk_color_selection_set_update_policy( - GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (window)->colorsel), - GTK_UPDATE_CONTINUOUS); - gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE); gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &window); + options_hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), options_hbox, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (options_hbox), 10); + + check_button = gtk_check_button_new_with_label ("Show Opacity"); + gtk_box_pack_start (GTK_BOX (options_hbox), check_button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (check_button), "toggled", + GTK_SIGNAL_FUNC (opacity_toggled_cb), window); + + check_button = gtk_check_button_new_with_label ("Show Palette"); + gtk_box_pack_end (GTK_BOX (options_hbox), check_button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (check_button), "toggled", + GTK_SIGNAL_FUNC (palette_toggled_cb), window); + + gtk_widget_show_all (options_hbox); + gtk_signal_connect ( GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (window)->colorsel), "color_changed", |