gimp/app/color_select.c

2257 lines
50 KiB
C

/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "appenv.h"
#include "actionarea.h"
#include "color_select.h"
#include "colormaps.h"
#include "errors.h"
#include "gimpdnd.h"
#include "gimprc.h"
#include "session.h"
#include "color_area.h" /* for color_area_draw_rect */
#include "libgimp/color_selector.h"
#include "libgimp/gimpintl.h"
#define XY_DEF_WIDTH 240
#define XY_DEF_HEIGHT 240
#define Z_DEF_WIDTH 15
#define Z_DEF_HEIGHT 240
#define COLOR_AREA_WIDTH 74
#define COLOR_AREA_HEIGHT 20
#define COLOR_AREA_MASK GDK_EXPOSURE_MASK | \
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | \
GDK_BUTTON1_MOTION_MASK | GDK_ENTER_NOTIFY_MASK
typedef enum
{
HUE = 0,
SATURATION,
VALUE,
RED,
GREEN,
BLUE,
HUE_SATURATION,
HUE_VALUE,
SATURATION_VALUE,
RED_GREEN,
RED_BLUE,
GREEN_BLUE
} ColorSelectFillType;
typedef enum
{
UPDATE_VALUES = 1 << 0,
UPDATE_POS = 1 << 1,
UPDATE_XY_COLOR = 1 << 2,
UPDATE_Z_COLOR = 1 << 3,
UPDATE_NEW_COLOR = 1 << 4,
UPDATE_ORIG_COLOR = 1 << 5,
UPDATE_CALLER = 1 << 6
} ColorSelectUpdateType;
typedef struct _ColorSelectFill ColorSelectFill;
typedef void (*ColorSelectFillUpdateProc) (ColorSelectFill *);
struct _ColorSelectFill
{
guchar *buffer;
gint y;
gint width;
gint height;
gint *values;
ColorSelectFillUpdateProc update;
};
static GtkWidget * color_select_widget_new (ColorSelect *, gint, gint, gint);
static void color_select_drag_new_color (GtkWidget *,
guchar *, guchar *, guchar *,
gpointer);
static void color_select_drop_new_color (GtkWidget *,
guchar, guchar, guchar,
gpointer);
static void color_select_drag_old_color (GtkWidget *,
guchar *, guchar *, guchar *,
gpointer);
static void color_select_update (ColorSelect *,
ColorSelectUpdateType);
static void color_select_update_caller (ColorSelect *);
static void color_select_update_values (ColorSelect *);
static void color_select_update_rgb_values (ColorSelect *);
static void color_select_update_hsv_values (ColorSelect *);
static void color_select_update_pos (ColorSelect *);
static void color_select_update_sliders (ColorSelect *, gint);
static void color_select_update_entries (ColorSelect *, gint);
static void color_select_update_colors (ColorSelect *, gint);
static void color_select_ok_callback (GtkWidget *, gpointer);
static void color_select_cancel_callback (GtkWidget *, gpointer);
static gint color_select_delete_callback (GtkWidget *, GdkEvent *, gpointer);
static gint color_select_xy_expose (GtkWidget *, GdkEventExpose *,
ColorSelect *);
static gint color_select_xy_events (GtkWidget *, GdkEvent *,
ColorSelect *);
static gint color_select_z_expose (GtkWidget *, GdkEventExpose *,
ColorSelect *);
static gint color_select_z_events (GtkWidget *, GdkEvent *,
ColorSelect *);
static gint color_select_color_events (GtkWidget *, GdkEvent *);
static void color_select_slider_update (GtkAdjustment *, gpointer);
static void color_select_entry_update (GtkWidget *, gpointer);
static void color_select_toggle_update (GtkWidget *, gpointer);
static gint color_select_hex_entry_leave (GtkWidget *, GdkEvent *, gpointer);
static void color_select_image_fill (GtkWidget *, ColorSelectFillType,
gint *);
static void color_select_draw_z_marker (ColorSelect *, GdkRectangle *);
static void color_select_draw_xy_marker (ColorSelect *, GdkRectangle *);
static void color_select_update_red (ColorSelectFill *);
static void color_select_update_green (ColorSelectFill *);
static void color_select_update_blue (ColorSelectFill *);
static void color_select_update_hue (ColorSelectFill *);
static void color_select_update_saturation (ColorSelectFill *);
static void color_select_update_value (ColorSelectFill *);
static void color_select_update_red_green (ColorSelectFill *);
static void color_select_update_red_blue (ColorSelectFill *);
static void color_select_update_green_blue (ColorSelectFill *);
static void color_select_update_hue_saturation (ColorSelectFill *);
static void color_select_update_hue_value (ColorSelectFill *);
static void color_select_update_saturation_value (ColorSelectFill *);
static GtkWidget * color_select_notebook_new (gint, gint, gint,
GimpColorSelector_Callback,
void *, void **);
static void color_select_notebook_free (void *);
static void color_select_notebook_setcolor (void *, gint, gint, gint,
gboolean);
static void color_select_notebook_update_callback (gint, gint, gint,
ColorSelectState,
void *);
/* Static variables */
static ColorSelectFillUpdateProc update_procs[] =
{
color_select_update_hue,
color_select_update_saturation,
color_select_update_value,
color_select_update_red,
color_select_update_green,
color_select_update_blue,
color_select_update_hue_saturation,
color_select_update_hue_value,
color_select_update_saturation_value,
color_select_update_red_green,
color_select_update_red_blue,
color_select_update_green_blue,
};
/* dnd stuff */
static GtkTargetEntry color_select_target_table[] =
{
GIMP_TARGET_COLOR
};
static guint n_color_select_targets = (sizeof (color_select_target_table) /
sizeof (color_select_target_table[0]));
ColorSelect *
color_select_new (gint r,
gint g,
gint b,
ColorSelectCallback callback,
gpointer data,
gboolean wants_updates)
{
ColorSelect *csp;
GtkWidget *main_vbox;
static ActionAreaItem action_items[] =
{
{ N_("OK"), color_select_ok_callback, NULL, NULL },
{ N_("Cancel"), color_select_cancel_callback, NULL, NULL }
};
csp = g_new (ColorSelect, 1);
csp->callback = callback;
csp->client_data = data;
csp->z_color_fill = HUE;
csp->xy_color_fill = SATURATION_VALUE;
csp->gc = NULL;
csp->wants_updates = wants_updates;
csp->values[RED] = csp->orig_values[0] = r;
csp->values[GREEN] = csp->orig_values[1] = g;
csp->values[BLUE] = csp->orig_values[2] = b;
color_select_update_hsv_values (csp);
color_select_update_pos (csp);
csp->shell = gtk_dialog_new ();
gtk_window_set_wmclass (GTK_WINDOW (csp->shell), "color_selection", "Gimp");
gtk_window_set_title (GTK_WINDOW (csp->shell), _("Color Selection"));
gtk_window_set_policy (GTK_WINDOW (csp->shell), FALSE, FALSE, FALSE);
/* handle the wm close signal */
gtk_signal_connect (GTK_OBJECT (csp->shell), "delete_event",
(GtkSignalFunc) color_select_delete_callback, csp);
main_vbox = color_select_widget_new (csp, r, g, b);
gtk_widget_show (main_vbox);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (csp->shell)->vbox), main_vbox,
TRUE, TRUE, 0);
/* The action area */
action_items[0].user_data = csp;
action_items[1].user_data = csp;
if (csp->wants_updates)
{
action_items[0].label = _("Close");
action_items[1].label = _("Revert to Old Color");
}
else
{
action_items[0].label = _("OK");
action_items[1].label = _("Cancel");
}
build_action_area (GTK_DIALOG (csp->shell), action_items, 2, 0);
color_select_image_fill (csp->z_color, csp->z_color_fill, csp->values);
color_select_image_fill (csp->xy_color, csp->xy_color_fill, csp->values);
gtk_widget_show (csp->shell);
return csp;
}
static GtkWidget *
color_select_widget_new (ColorSelect *csp,
gint r,
gint g,
gint b)
{
static gchar *toggle_titles[6] = { "H", "S", "V", "R", "G", "B" };
static gfloat slider_max_vals[6] = { 360, 100, 100, 255, 255, 255 };
static gfloat slider_incs[6] = { 0.1, 0.1, 0.1, 1.0, 1.0, 1.0 };
GtkWidget *main_vbox;
GtkWidget *main_hbox;
GtkWidget *xy_frame;
GtkWidget *z_frame;
GtkWidget *colors_frame;
GtkWidget *colors_hbox;
GtkWidget *right_vbox;
GtkWidget *table;
GtkWidget *slider;
GtkWidget *hex_hbox;
GtkWidget *label;
GSList *group;
gchar buffer[16];
gint i;
main_vbox = gtk_vbox_new (FALSE, 2);
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 2);
main_hbox = gtk_hbox_new (FALSE, 2);
gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 0);
gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, TRUE, TRUE, 2);
gtk_widget_show (main_hbox);
/* The x/y component preview */
xy_frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (xy_frame), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (main_hbox), xy_frame, FALSE, FALSE, 2);
gtk_widget_show (xy_frame);
csp->xy_color = gtk_preview_new (GTK_PREVIEW_COLOR);
gtk_preview_set_dither (GTK_PREVIEW (csp->xy_color), GDK_RGB_DITHER_MAX);
gtk_preview_size (GTK_PREVIEW (csp->xy_color), XY_DEF_WIDTH, XY_DEF_HEIGHT);
gtk_widget_set_events (csp->xy_color, COLOR_AREA_MASK);
gtk_signal_connect_after (GTK_OBJECT (csp->xy_color), "expose_event",
(GtkSignalFunc) color_select_xy_expose,
csp);
gtk_signal_connect (GTK_OBJECT (csp->xy_color), "event",
(GtkSignalFunc) color_select_xy_events,
csp);
gtk_container_add (GTK_CONTAINER (xy_frame), csp->xy_color);
gtk_widget_show (csp->xy_color);
/* dnd stuff */
gtk_drag_dest_set (csp->xy_color,
GTK_DEST_DEFAULT_HIGHLIGHT |
GTK_DEST_DEFAULT_MOTION |
GTK_DEST_DEFAULT_DROP,
color_select_target_table, n_color_select_targets,
GDK_ACTION_COPY);
gimp_dnd_color_dest_set (csp->xy_color, color_select_drop_new_color, csp);
/* The z component preview */
z_frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (z_frame), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (main_hbox), z_frame, FALSE, FALSE, 2);
gtk_widget_show (z_frame);
csp->z_color = gtk_preview_new (GTK_PREVIEW_COLOR);
gtk_preview_set_dither (GTK_PREVIEW (csp->z_color), GDK_RGB_DITHER_MAX);
gtk_preview_size (GTK_PREVIEW (csp->z_color), Z_DEF_WIDTH, Z_DEF_HEIGHT);
gtk_widget_set_events (csp->z_color, COLOR_AREA_MASK);
gtk_signal_connect_after (GTK_OBJECT (csp->z_color), "expose_event",
(GtkSignalFunc) color_select_z_expose,
csp);
gtk_signal_connect (GTK_OBJECT (csp->z_color), "event",
(GtkSignalFunc) color_select_z_events,
csp);
gtk_container_add (GTK_CONTAINER (z_frame), csp->z_color);
gtk_widget_show (csp->z_color);
/* The right vertical box with old/new color area and color space sliders */
right_vbox = gtk_vbox_new (FALSE, 2);
gtk_container_set_border_width (GTK_CONTAINER (right_vbox), 0);
gtk_box_pack_start (GTK_BOX (main_hbox), right_vbox, TRUE, TRUE, 0);
gtk_widget_show (right_vbox);
/* The old/new color area frame and hbox */
colors_frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (colors_frame), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (right_vbox), colors_frame, FALSE, FALSE, 0);
gtk_widget_show (colors_frame);
colors_hbox = gtk_hbox_new (TRUE, 2);
gtk_container_add (GTK_CONTAINER (colors_frame), colors_hbox);
gtk_widget_show (colors_hbox);
/* The new color area */
csp->new_color = gtk_drawing_area_new ();
gtk_drawing_area_size (GTK_DRAWING_AREA (csp->new_color),
COLOR_AREA_WIDTH, COLOR_AREA_HEIGHT);
gtk_widget_set_events (csp->new_color, GDK_EXPOSURE_MASK);
gtk_signal_connect (GTK_OBJECT (csp->new_color), "event",
(GtkSignalFunc) color_select_color_events,
csp);
gtk_object_set_user_data (GTK_OBJECT (csp->new_color), csp);
gtk_box_pack_start (GTK_BOX (colors_hbox), csp->new_color, TRUE, TRUE, 0);
gtk_widget_show (csp->new_color);
/* dnd stuff */
gtk_drag_source_set (csp->new_color,
GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
color_select_target_table, n_color_select_targets,
GDK_ACTION_COPY | GDK_ACTION_MOVE);
gimp_dnd_color_source_set (csp->new_color, color_select_drag_new_color, csp);
gtk_drag_dest_set (csp->new_color,
GTK_DEST_DEFAULT_HIGHLIGHT |
GTK_DEST_DEFAULT_MOTION |
GTK_DEST_DEFAULT_DROP,
color_select_target_table, n_color_select_targets,
GDK_ACTION_COPY);
gimp_dnd_color_dest_set (csp->new_color, color_select_drop_new_color, csp);
/* The old color area */
csp->orig_color = gtk_drawing_area_new ();
gtk_drawing_area_size (GTK_DRAWING_AREA (csp->orig_color),
COLOR_AREA_WIDTH, COLOR_AREA_HEIGHT);
gtk_widget_set_events (csp->orig_color, GDK_EXPOSURE_MASK);
gtk_signal_connect (GTK_OBJECT (csp->orig_color), "event",
(GtkSignalFunc) color_select_color_events,
csp);
gtk_object_set_user_data (GTK_OBJECT (csp->orig_color), csp);
gtk_box_pack_start (GTK_BOX (colors_hbox), csp->orig_color, TRUE, TRUE, 0);
gtk_widget_show (csp->orig_color);
/* dnd stuff */
gtk_drag_source_set (csp->orig_color,
GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
color_select_target_table, n_color_select_targets,
GDK_ACTION_COPY | GDK_ACTION_MOVE);
gimp_dnd_color_source_set (csp->orig_color, color_select_drag_old_color, csp);
/* The color space sliders, toggle buttons and entries */
table = gtk_table_new (6, 3, FALSE);
gtk_table_set_row_spacings (GTK_TABLE (table), 3);
gtk_table_set_col_spacings (GTK_TABLE (table), 3);
gtk_container_set_border_width (GTK_CONTAINER (table), 2);
gtk_box_pack_start (GTK_BOX (right_vbox), table, TRUE, TRUE, 0);
gtk_widget_show (table);
group = NULL;
for (i = 0; i < 6; i++)
{
csp->toggles[i] =
gtk_radio_button_new_with_label (group, toggle_titles[i]);
group = gtk_radio_button_group (GTK_RADIO_BUTTON (csp->toggles[i]));
gtk_table_attach (GTK_TABLE (table), csp->toggles[i],
0, 1, i, i+1, GTK_FILL, GTK_EXPAND, 0, 0);
gtk_signal_connect (GTK_OBJECT (csp->toggles[i]), "toggled",
(GtkSignalFunc) color_select_toggle_update,
csp);
gtk_widget_show (csp->toggles[i]);
csp->slider_data[i] =
GTK_ADJUSTMENT (gtk_adjustment_new (csp->values[i], 0.0,
slider_max_vals[i],
slider_incs[i],
1.0, 0.0));
slider = gtk_hscale_new (csp->slider_data[i]);
gtk_table_attach (GTK_TABLE (table), slider, 1, 2, i, i+1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 0);
gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_TOP);
gtk_scale_set_draw_value (GTK_SCALE (slider), FALSE);
gtk_signal_connect (GTK_OBJECT (csp->slider_data[i]), "value_changed",
(GtkSignalFunc) color_select_slider_update,
csp);
gtk_widget_show (slider);
csp->entries[i] = gtk_entry_new ();
g_snprintf (buffer, sizeof (buffer), "%d", csp->values[i]);
gtk_entry_set_text (GTK_ENTRY (csp->entries[i]), buffer);
gtk_widget_set_usize (GTK_WIDGET (csp->entries[i]), 40, 0);
gtk_table_attach (GTK_TABLE (table), csp->entries[i],
2, 3, i, i+1, GTK_FILL, GTK_EXPAND, 0, 0);
gtk_signal_connect (GTK_OBJECT (csp->entries[i]), "changed",
(GtkSignalFunc) color_select_entry_update,
csp);
gtk_widget_show (csp->entries[i]);
}
/* The hex triplet entry */
hex_hbox = gtk_hbox_new (FALSE, 3);
gtk_box_pack_start (GTK_BOX (right_vbox), hex_hbox, FALSE, FALSE, 0);
gtk_widget_show (hex_hbox);
csp->hex_entry = gtk_entry_new ();
g_snprintf (buffer, sizeof (buffer), "#%.2x%.2x%.2x", r, g, b);
gtk_entry_set_text (GTK_ENTRY (csp->hex_entry), buffer);
gtk_widget_set_usize (GTK_WIDGET (csp->hex_entry), 75, 0);
gtk_box_pack_end (GTK_BOX (hex_hbox), csp->hex_entry, FALSE, FALSE, 2);
gtk_signal_connect (GTK_OBJECT (csp->hex_entry), "focus_out_event",
(GtkSignalFunc) color_select_hex_entry_leave,
csp);
gtk_widget_show (csp->hex_entry);
label = gtk_label_new (_("Hex Triplet:"));
gtk_box_pack_end (GTK_BOX (hex_hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
return main_vbox;
}
static void
color_select_drag_new_color (GtkWidget *widget,
guchar *r,
guchar *g,
guchar *b,
gpointer data)
{
ColorSelect *csp;
csp = (ColorSelect *) data;
*r = (guchar) csp->values[RED];
*g = (guchar) csp->values[GREEN];
*b = (guchar) csp->values[BLUE];
}
static void
color_select_drop_new_color (GtkWidget *widget,
guchar r,
guchar g,
guchar b,
gpointer data)
{
ColorSelect *csp;
csp = (ColorSelect *) data;
csp->values[RED] = (gint) r;
csp->values[GREEN] = (gint) g;
csp->values[BLUE] = (gint) b;
color_select_update_hsv_values (csp);
color_select_update_pos (csp);
color_select_update_sliders (csp, -1);
color_select_update_entries (csp, -1);
color_select_update_colors (csp, 0);
color_select_update (csp, UPDATE_Z_COLOR);
color_select_update (csp, UPDATE_XY_COLOR);
}
static void
color_select_drag_old_color (GtkWidget *widget,
guchar *r,
guchar *g,
guchar *b,
gpointer data)
{
ColorSelect *csp;
csp = (ColorSelect *) data;
*r = (guchar) csp->orig_values[0];
*g = (guchar) csp->orig_values[1];
*b = (guchar) csp->orig_values[2];
}
/* Register the GIMP colour selector with the color notebook */
void
color_select_init (void)
{
GimpColorSelectorMethods methods =
{
color_select_notebook_new,
color_select_notebook_free,
color_select_notebook_setcolor
};
gimp_color_selector_register ("GIMP", &methods);
}
void
color_select_show (ColorSelect *csp)
{
if (csp)
gtk_widget_show (csp->shell);
}
void
color_select_hide (ColorSelect *csp)
{
if (csp)
gtk_widget_hide (csp->shell);
}
void
color_select_free (ColorSelect *csp)
{
if (csp)
{
if (csp->shell)
gtk_widget_destroy (csp->shell);
gdk_gc_destroy (csp->gc);
g_free (csp);
}
}
void
color_select_set_color (ColorSelect *csp,
gint r,
gint g,
gint b,
gboolean set_current)
{
if (csp)
{
csp->orig_values[0] = r;
csp->orig_values[1] = g;
csp->orig_values[2] = b;
color_select_update_colors (csp, 1);
if (set_current)
{
csp->values[RED] = r;
csp->values[GREEN] = g;
csp->values[BLUE] = b;
color_select_update_hsv_values (csp);
color_select_update_pos (csp);
color_select_update_sliders (csp, -1);
color_select_update_entries (csp, -1);
color_select_update_colors (csp, 0);
color_select_update (csp, UPDATE_Z_COLOR);
color_select_update (csp, UPDATE_XY_COLOR);
}
}
}
static void
color_select_update (ColorSelect *csp,
ColorSelectUpdateType update)
{
if (csp)
{
if (update & UPDATE_POS)
color_select_update_pos (csp);
if (update & UPDATE_VALUES)
{
color_select_update_values (csp);
color_select_update_sliders (csp, -1);
color_select_update_entries (csp, -1);
if (!(update & UPDATE_NEW_COLOR))
color_select_update_colors (csp, 0);
}
if (update & UPDATE_XY_COLOR)
{
color_select_image_fill (csp->xy_color, csp->xy_color_fill, csp->values);
gtk_widget_draw (csp->xy_color, NULL);
}
if (update & UPDATE_Z_COLOR)
{
color_select_image_fill (csp->z_color, csp->z_color_fill, csp->values);
gtk_widget_draw (csp->z_color, NULL);
}
if (update & UPDATE_NEW_COLOR)
color_select_update_colors (csp, 0);
if (update & UPDATE_ORIG_COLOR)
color_select_update_colors (csp, 1);
/*if (update & UPDATE_CALLER)*/
color_select_update_caller (csp);
}
}
static void
color_select_update_caller (ColorSelect *csp)
{
if (csp && csp->wants_updates && csp->callback)
{
(* csp->callback) (csp->values[RED],
csp->values[GREEN],
csp->values[BLUE],
COLOR_SELECT_UPDATE,
csp->client_data);
}
}
static void
color_select_update_values (ColorSelect *csp)
{
if (csp)
{
switch (csp->z_color_fill)
{
case RED:
csp->values[BLUE] = csp->pos[0];
csp->values[GREEN] = csp->pos[1];
csp->values[RED] = csp->pos[2];
break;
case GREEN:
csp->values[BLUE] = csp->pos[0];
csp->values[RED] = csp->pos[1];
csp->values[GREEN] = csp->pos[2];
break;
case BLUE:
csp->values[GREEN] = csp->pos[0];
csp->values[RED] = csp->pos[1];
csp->values[BLUE] = csp->pos[2];
break;
case HUE:
csp->values[VALUE] = csp->pos[0] * 100 / 255;
csp->values[SATURATION] = csp->pos[1] * 100 / 255;
csp->values[HUE] = csp->pos[2] * 360 / 255;
break;
case SATURATION:
csp->values[VALUE] = csp->pos[0] * 100 / 255;
csp->values[HUE] = csp->pos[1] * 360 / 255;
csp->values[SATURATION] = csp->pos[2] * 100 / 255;
break;
case VALUE:
csp->values[SATURATION] = csp->pos[0] * 100 / 255;
csp->values[HUE] = csp->pos[1] * 360 / 255;
csp->values[VALUE] = csp->pos[2] * 100 / 255;
break;
}
switch (csp->z_color_fill)
{
case RED:
case GREEN:
case BLUE:
color_select_update_hsv_values (csp);
break;
case HUE:
case SATURATION:
case VALUE:
color_select_update_rgb_values (csp);
break;
}
}
}
static void
color_select_update_rgb_values (ColorSelect *csp)
{
gfloat h, s, v;
gfloat f, p, q, t;
if (csp)
{
h = csp->values[HUE];
s = csp->values[SATURATION] / 100.0;
v = csp->values[VALUE] / 100.0;
if (s == 0)
{
csp->values[RED] = v * 255;
csp->values[GREEN] = v * 255;
csp->values[BLUE] = v * 255;
}
else
{
if (h == 360)
h = 0;
h /= 60;
f = h - (int) h;
p = v * (1 - s);
q = v * (1 - (s * f));
t = v * (1 - (s * (1 - f)));
switch ((int) h)
{
case 0:
csp->values[RED] = v * 255;
csp->values[GREEN] = t * 255;
csp->values[BLUE] = p * 255;
break;
case 1:
csp->values[RED] = q * 255;
csp->values[GREEN] = v * 255;
csp->values[BLUE] = p * 255;
break;
case 2:
csp->values[RED] = p * 255;
csp->values[GREEN] = v * 255;
csp->values[BLUE] = t * 255;
break;
case 3:
csp->values[RED] = p * 255;
csp->values[GREEN] = q * 255;
csp->values[BLUE] = v * 255;
break;
case 4:
csp->values[RED] = t * 255;
csp->values[GREEN] = p * 255;
csp->values[BLUE] = v * 255;
break;
case 5:
csp->values[RED] = v * 255;
csp->values[GREEN] = p * 255;
csp->values[BLUE] = q * 255;
break;
}
}
}
}
static void
color_select_update_hsv_values (ColorSelect *csp)
{
gint r, g, b;
gfloat h, s, v;
gint min, max;
gint delta;
if (csp)
{
r = csp->values[RED];
g = csp->values[GREEN];
b = csp->values[BLUE];
if (r > g)
{
if (r > b)
max = r;
else
max = b;
if (g < b)
min = g;
else
min = b;
}
else
{
if (g > b)
max = g;
else
max = b;
if (r < b)
min = r;
else
min = b;
}
v = max;
if (max != 0)
s = (max - min) / (float) max;
else
s = 0;
if (s == 0)
h = 0;
else
{
h = 0;
delta = max - min;
if (r == max)
h = (g - b) / (float) delta;
else if (g == max)
h = 2 + (b - r) / (float) delta;
else if (b == max)
h = 4 + (r - g) / (float) delta;
h *= 60;
if (h < 0)
h += 360;
}
csp->values[HUE] = h;
csp->values[SATURATION] = s * 100;
csp->values[VALUE] = v * 100 / 255;
}
}
static void
color_select_update_pos (ColorSelect *csp)
{
if (csp)
{
switch (csp->z_color_fill)
{
case RED:
csp->pos[0] = csp->values[BLUE];
csp->pos[1] = csp->values[GREEN];
csp->pos[2] = csp->values[RED];
break;
case GREEN:
csp->pos[0] = csp->values[BLUE];
csp->pos[1] = csp->values[RED];
csp->pos[2] = csp->values[GREEN];
break;
case BLUE:
csp->pos[0] = csp->values[GREEN];
csp->pos[1] = csp->values[RED];
csp->pos[2] = csp->values[BLUE];
break;
case HUE:
csp->pos[0] = csp->values[VALUE] * 255 / 100;
csp->pos[1] = csp->values[SATURATION] * 255 / 100;
csp->pos[2] = csp->values[HUE] * 255 / 360;
break;
case SATURATION:
csp->pos[0] = csp->values[VALUE] * 255 / 100;
csp->pos[1] = csp->values[HUE] * 255 / 360;
csp->pos[2] = csp->values[SATURATION] * 255 / 100;
break;
case VALUE:
csp->pos[0] = csp->values[SATURATION] * 255 / 100;
csp->pos[1] = csp->values[HUE] * 255 / 360;
csp->pos[2] = csp->values[VALUE] * 255 / 100;
break;
}
}
}
static void
color_select_update_sliders (ColorSelect *csp,
gint skip)
{
gint i;
if (csp)
{
for (i = 0; i < 6; i++)
if (i != skip)
{
csp->slider_data[i]->value = (gfloat) csp->values[i];
gtk_signal_handler_block_by_data (GTK_OBJECT (csp->slider_data[i]), csp);
gtk_signal_emit_by_name (GTK_OBJECT (csp->slider_data[i]), "value_changed");
gtk_signal_handler_unblock_by_data (GTK_OBJECT (csp->slider_data[i]), csp);
}
}
}
static void
color_select_update_entries (ColorSelect *csp,
gint skip)
{
gchar buffer[16];
gint i;
if (csp)
{
for (i = 0; i < 6; i++)
if (i != skip)
{
g_snprintf (buffer, sizeof (buffer), "%d", csp->values[i]);
gtk_signal_handler_block_by_data (GTK_OBJECT (csp->entries[i]), csp);
gtk_entry_set_text (GTK_ENTRY (csp->entries[i]), buffer);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (csp->entries[i]), csp);
}
g_snprintf (buffer, sizeof (buffer), "#%.2x%.2x%.2x",
csp->values[RED],
csp->values[GREEN],
csp->values[BLUE]);
gtk_entry_set_text (GTK_ENTRY (csp->hex_entry), buffer);
}
}
static void
color_select_update_colors (ColorSelect *csp,
gint which)
{
GdkWindow *window;
GdkColor color;
gint red, green, blue;
gint width, height;
if (csp)
{
if (which)
{
window = csp->orig_color->window;
color.pixel = old_color_pixel;
red = csp->orig_values[0];
green = csp->orig_values[1];
blue = csp->orig_values[2];
}
else
{
window = csp->new_color->window;
color.pixel = new_color_pixel;
red = csp->values[RED];
green = csp->values[GREEN];
blue = csp->values[BLUE];
}
/* if we haven't yet been realised, there's no need to redraw
* anything. */
if (!window)
return;
color.pixel = get_color (red, green, blue);
gdk_window_get_size (window, &width, &height);
if (csp->gc)
{
#ifdef OLD_COLOR_AREA
gdk_gc_set_foreground (csp->gc, &color);
gdk_draw_rectangle (window, csp->gc, 1,
0, 0, width, height);
#else
color_area_draw_rect (window, csp->gc,
0, 0, width, height,
red, green, blue);
#endif
}
}
}
static void
color_select_ok_callback (GtkWidget *widget,
gpointer data)
{
ColorSelect *csp;
csp = (ColorSelect *) data;
if (csp)
{
if (csp->callback)
(* csp->callback) (csp->values[RED],
csp->values[GREEN],
csp->values[BLUE],
COLOR_SELECT_OK,
csp->client_data);
}
}
static gint
color_select_delete_callback (GtkWidget *widget,
GdkEvent *event,
gpointer data)
{
color_select_cancel_callback (widget, data);
return TRUE;
}
static void
color_select_cancel_callback (GtkWidget *widget,
gpointer data)
{
ColorSelect *csp;
csp = (ColorSelect *) data;
if (csp)
{
if (csp->callback)
(* csp->callback) (csp->orig_values[0],
csp->orig_values[1],
csp->orig_values[2],
COLOR_SELECT_CANCEL,
csp->client_data);
}
}
static gint
color_select_xy_expose (GtkWidget *widget,
GdkEventExpose *event,
ColorSelect *csp)
{
if (!csp->gc)
csp->gc = gdk_gc_new (widget->window);
color_select_draw_xy_marker (csp, &event->area);
return FALSE;
}
static gint
color_select_xy_events (GtkWidget *widget,
GdkEvent *event,
ColorSelect *csp)
{
GdkEventButton *bevent;
GdkEventMotion *mevent;
gint tx, ty;
switch (event->type)
{
case GDK_BUTTON_PRESS:
bevent = (GdkEventButton *) event;
color_select_draw_xy_marker (csp, NULL);
csp->pos[0] = (bevent->x * 255) / (XY_DEF_WIDTH - 1);
csp->pos[1] = 255 - (bevent->y * 255) / (XY_DEF_HEIGHT - 1);
if (csp->pos[0] < 0)
csp->pos[0] = 0;
if (csp->pos[0] > 255)
csp->pos[0] = 255;
if (csp->pos[1] < 0)
csp->pos[1] = 0;
if (csp->pos[1] > 255)
csp->pos[1] = 255;
gdk_pointer_grab (csp->xy_color->window, FALSE,
GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON1_MOTION_MASK |
GDK_BUTTON_RELEASE_MASK,
NULL, NULL, bevent->time);
color_select_draw_xy_marker (csp, NULL);
color_select_update (csp, UPDATE_VALUES);
break;
case GDK_BUTTON_RELEASE:
bevent = (GdkEventButton *) event;
color_select_draw_xy_marker (csp, NULL);
csp->pos[0] = (bevent->x * 255) / (XY_DEF_WIDTH - 1);
csp->pos[1] = 255 - (bevent->y * 255) / (XY_DEF_HEIGHT - 1);
if (csp->pos[0] < 0)
csp->pos[0] = 0;
if (csp->pos[0] > 255)
csp->pos[0] = 255;
if (csp->pos[1] < 0)
csp->pos[1] = 0;
if (csp->pos[1] > 255)
csp->pos[1] = 255;
gdk_pointer_ungrab (bevent->time);
color_select_draw_xy_marker (csp, NULL);
color_select_update (csp, UPDATE_VALUES);
break;
case GDK_MOTION_NOTIFY:
mevent = (GdkEventMotion *) event;
if (mevent->is_hint)
{
gdk_window_get_pointer (widget->window, &tx, &ty, NULL);
mevent->x = tx;
mevent->y = ty;
}
color_select_draw_xy_marker (csp, NULL);
csp->pos[0] = (mevent->x * 255) / (XY_DEF_WIDTH - 1);
csp->pos[1] = 255 - (mevent->y * 255) / (XY_DEF_HEIGHT - 1);
if (csp->pos[0] < 0)
csp->pos[0] = 0;
if (csp->pos[0] > 255)
csp->pos[0] = 255;
if (csp->pos[1] < 0)
csp->pos[1] = 0;
if (csp->pos[1] > 255)
csp->pos[1] = 255;
color_select_draw_xy_marker (csp, NULL);
color_select_update (csp, UPDATE_VALUES);
break;
default:
break;
}
return FALSE;
}
static gint
color_select_z_expose (GtkWidget *widget,
GdkEventExpose *event,
ColorSelect *csp)
{
if (!csp->gc)
csp->gc = gdk_gc_new (widget->window);
color_select_draw_z_marker (csp, &event->area);
return FALSE;
}
static gint
color_select_z_events (GtkWidget *widget,
GdkEvent *event,
ColorSelect *csp)
{
GdkEventButton *bevent;
GdkEventMotion *mevent;
gint tx, ty;
switch (event->type)
{
case GDK_BUTTON_PRESS:
bevent = (GdkEventButton *) event;
color_select_draw_z_marker (csp, NULL);
csp->pos[2] = 255 - (bevent->y * 255) / (Z_DEF_HEIGHT - 1);
if (csp->pos[2] < 0)
csp->pos[2] = 0;
if (csp->pos[2] > 255)
csp->pos[2] = 255;
gdk_pointer_grab (csp->z_color->window, FALSE,
GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON1_MOTION_MASK |
GDK_BUTTON_RELEASE_MASK,
NULL, NULL, bevent->time);
color_select_draw_z_marker (csp, NULL);
color_select_update (csp, UPDATE_VALUES);
break;
case GDK_BUTTON_RELEASE:
bevent = (GdkEventButton *) event;
color_select_draw_z_marker (csp, NULL);
csp->pos[2] = 255 - (bevent->y * 255) / (Z_DEF_HEIGHT - 1);
if (csp->pos[2] < 0)
csp->pos[2] = 0;
if (csp->pos[2] > 255)
csp->pos[2] = 255;
gdk_pointer_ungrab (bevent->time);
color_select_draw_z_marker (csp, NULL);
color_select_update (csp, UPDATE_VALUES | UPDATE_XY_COLOR);
break;
case GDK_MOTION_NOTIFY:
mevent = (GdkEventMotion *) event;
if (mevent->is_hint)
{
gdk_window_get_pointer (widget->window, &tx, &ty, NULL);
mevent->x = tx;
mevent->y = ty;
}
color_select_draw_z_marker (csp, NULL);
csp->pos[2] = 255 - (mevent->y * 255) / (Z_DEF_HEIGHT - 1);
if (csp->pos[2] < 0)
csp->pos[2] = 0;
if (csp->pos[2] > 255)
csp->pos[2] = 255;
color_select_draw_z_marker (csp, NULL);
color_select_update (csp, UPDATE_VALUES);
break;
default:
break;
}
return FALSE;
}
static gint
color_select_color_events (GtkWidget *widget,
GdkEvent *event)
{
ColorSelect *csp;
csp = (ColorSelect *) gtk_object_get_user_data (GTK_OBJECT (widget));
if (!csp)
return FALSE;
switch (event->type)
{
case GDK_EXPOSE:
if (!csp->gc)
csp->gc = gdk_gc_new (widget->window);
if (widget == csp->new_color)
color_select_update (csp, UPDATE_NEW_COLOR);
else if (widget == csp->orig_color)
color_select_update (csp, UPDATE_ORIG_COLOR);
break;
default:
break;
}
return FALSE;
}
static void
color_select_slider_update (GtkAdjustment *adjustment,
gpointer data)
{
ColorSelect *csp;
gint old_values[6];
gint update_z_marker;
gint update_xy_marker;
gint i, j;
csp = (ColorSelect *) data;
if (csp)
{
for (i = 0; i < 6; i++)
if (csp->slider_data[i] == adjustment)
break;
for (j = 0; j < 6; j++)
old_values[j] = csp->values[j];
csp->values[i] = (int) adjustment->value;
if ((i >= HUE) && (i <= VALUE))
color_select_update_rgb_values (csp);
else if ((i >= RED) && (i <= BLUE))
color_select_update_hsv_values (csp);
color_select_update_sliders (csp, i);
color_select_update_entries (csp, -1);
update_z_marker = 0;
update_xy_marker = 0;
for (j = 0; j < 6; j++)
{
if (j == csp->z_color_fill)
{
if (old_values[j] != csp->values[j])
update_z_marker = 1;
}
else
{
if (old_values[j] != csp->values[j])
update_xy_marker = 1;
}
}
if (update_z_marker)
{
color_select_draw_z_marker (csp, NULL);
color_select_update (csp, UPDATE_POS | UPDATE_XY_COLOR);
color_select_draw_z_marker (csp, NULL);
}
else
{
if (update_z_marker)
color_select_draw_z_marker (csp, NULL);
if (update_xy_marker)
color_select_draw_xy_marker (csp, NULL);
color_select_update (csp, UPDATE_POS);
if (update_z_marker)
color_select_draw_z_marker (csp, NULL);
if (update_xy_marker)
color_select_draw_xy_marker (csp, NULL);
}
color_select_update (csp, UPDATE_NEW_COLOR);
}
}
static void
color_select_entry_update (GtkWidget *widget,
gpointer data)
{
ColorSelect *csp;
int old_values[6];
int update_z_marker;
int update_xy_marker;
gint i, j;
csp = (ColorSelect *) data;
if (csp)
{
for (i = 0; i < 6; i++)
if (csp->entries[i] == widget)
break;
for (j = 0; j < 6; j++)
old_values[j] = csp->values[j];
csp->values[i] = atoi (gtk_entry_get_text (GTK_ENTRY (csp->entries[i])));
if (csp->values[i] == old_values[i])
return;
if ((i >= HUE) && (i <= VALUE))
color_select_update_rgb_values (csp);
else if ((i >= RED) && (i <= BLUE))
color_select_update_hsv_values (csp);
color_select_update_entries (csp, i);
color_select_update_sliders (csp, -1);
update_z_marker = 0;
update_xy_marker = 0;
for (j = 0; j < 6; j++)
{
if (j == csp->z_color_fill)
{
if (old_values[j] != csp->values[j])
update_z_marker = 1;
}
else
{
if (old_values[j] != csp->values[j])
update_xy_marker = 1;
}
}
if (update_z_marker)
{
color_select_draw_z_marker (csp, NULL);
color_select_update (csp, UPDATE_POS | UPDATE_XY_COLOR);
color_select_draw_z_marker (csp, NULL);
}
else
{
if (update_z_marker)
color_select_draw_z_marker (csp, NULL);
if (update_xy_marker)
color_select_draw_xy_marker (csp, NULL);
color_select_update (csp, UPDATE_POS);
if (update_z_marker)
color_select_draw_z_marker (csp, NULL);
if (update_xy_marker)
color_select_draw_xy_marker (csp, NULL);
}
color_select_update (csp, UPDATE_NEW_COLOR);
}
}
static void
color_select_toggle_update (GtkWidget *widget,
gpointer data)
{
ColorSelect *csp;
ColorSelectFillType type = HUE;
gint i;
if (!GTK_TOGGLE_BUTTON (widget)->active)
return;
csp = (ColorSelect *) data;
if (csp)
{
for (i = 0; i < 6; i++)
if (widget == csp->toggles[i])
type = (ColorSelectFillType) i;
switch (type)
{
case HUE:
csp->z_color_fill = HUE;
csp->xy_color_fill = SATURATION_VALUE;
break;
case SATURATION:
csp->z_color_fill = SATURATION;
csp->xy_color_fill = HUE_VALUE;
break;
case VALUE:
csp->z_color_fill = VALUE;
csp->xy_color_fill = HUE_SATURATION;
break;
case RED:
csp->z_color_fill = RED;
csp->xy_color_fill = GREEN_BLUE;
break;
case GREEN:
csp->z_color_fill = GREEN;
csp->xy_color_fill = RED_BLUE;
break;
case BLUE:
csp->z_color_fill = BLUE;
csp->xy_color_fill = RED_GREEN;
break;
default:
break;
}
color_select_update (csp, UPDATE_POS);
color_select_update (csp, UPDATE_Z_COLOR | UPDATE_XY_COLOR);
}
}
static gint
color_select_hex_entry_leave (GtkWidget *widget,
GdkEvent *event,
gpointer data)
{
ColorSelect *csp;
gchar buffer[8];
gchar *hex_color;
guint hex_rgb;
csp = (ColorSelect *) data;
if (csp)
{
hex_color = g_strdup (gtk_entry_get_text (GTK_ENTRY (csp->hex_entry)));
g_snprintf(buffer, sizeof (buffer), "#%.2x%.2x%.2x",
csp->values[RED],
csp->values[GREEN],
csp->values[BLUE]);
if ((strlen (hex_color) == 7) &&
(g_strcasecmp (buffer, hex_color) != 0))
{
if ((sscanf (hex_color, "#%x", &hex_rgb) == 1) &&
(hex_rgb < (1 << 24)))
color_select_set_color (csp,
(hex_rgb & 0xff0000) >> 16,
(hex_rgb & 0x00ff00) >> 8,
hex_rgb & 0x0000ff,
TRUE);
}
g_free (hex_color);
}
return FALSE;
}
static void
color_select_image_fill (GtkWidget *preview,
ColorSelectFillType type,
gint *values)
{
ColorSelectFill csf;
gint height;
csf.buffer = g_malloc (preview->requisition.width * 3);
csf.update = update_procs[type];
csf.y = -1;
csf.width = preview->requisition.width;
csf.height = preview->requisition.height;
csf.values = values;
height = csf.height;
if (height > 0)
while (height--)
{
(* csf.update) (&csf);
gtk_preview_draw_row (GTK_PREVIEW (preview),
csf.buffer, 0, csf.y, csf.width);
}
g_free (csf.buffer);
}
static void
color_select_draw_z_marker (ColorSelect *csp,
GdkRectangle *clip)
{
gint width;
gint height;
gint y;
gint minx;
gint miny;
if (csp->gc)
{
y = (Z_DEF_HEIGHT - 1) - ((Z_DEF_HEIGHT - 1) * csp->pos[2]) / 255;
width = csp->z_color->requisition.width;
height = csp->z_color->requisition.height;
minx = 0;
miny = 0;
if (width <= 0)
return;
if (clip)
{
width = MIN(width, clip->x + clip->width);
height = MIN(height, clip->y + clip->height);
minx = MAX(0, clip->x);
miny = MAX(0, clip->y);
}
if (y >= miny && y < height)
{
gdk_gc_set_function (csp->gc, GDK_INVERT);
gdk_draw_line (csp->z_color->window, csp->gc, minx, y, width - 1, y);
gdk_gc_set_function (csp->gc, GDK_COPY);
}
}
}
static void
color_select_draw_xy_marker (ColorSelect *csp,
GdkRectangle *clip)
{
gint width;
gint height;
gint x, y;
gint minx, miny;
if (csp->gc)
{
x = ((XY_DEF_WIDTH - 1) * csp->pos[0]) / 255;
y = (XY_DEF_HEIGHT - 1) - ((XY_DEF_HEIGHT - 1) * csp->pos[1]) / 255;
width = csp->xy_color->requisition.width;
height = csp->xy_color->requisition.height;
minx = 0;
miny = 0;
if ((width <= 0) || (height <= 0))
return;
gdk_gc_set_function (csp->gc, GDK_INVERT);
if (clip)
{
width = MIN(width, clip->x + clip->width);
height = MIN(height, clip->y + clip->height);
minx = MAX(0, clip->x);
miny = MAX(0, clip->y);
}
if (y >= miny && y < height)
gdk_draw_line (csp->xy_color->window, csp->gc, minx, y, width - 1, y);
if (x >= minx && x < width)
gdk_draw_line (csp->xy_color->window, csp->gc, x, miny, x, height - 1);
gdk_gc_set_function (csp->gc, GDK_COPY);
}
}
static void
color_select_update_red (ColorSelectFill *csf)
{
guchar *p;
gint i, r;
p = csf->buffer;
csf->y += 1;
r = (csf->height - csf->y + 1) * 255 / csf->height;
if (r < 0)
r = 0;
if (r > 255)
r = 255;
for (i = 0; i < csf->width; i++)
{
*p++ = r;
*p++ = 0;
*p++ = 0;
}
}
static void
color_select_update_green (ColorSelectFill *csf)
{
guchar *p;
gint i, g;
p = csf->buffer;
csf->y += 1;
g = (csf->height - csf->y + 1) * 255 / csf->height;
if (g < 0)
g = 0;
if (g > 255)
g = 255;
for (i = 0; i < csf->width; i++)
{
*p++ = 0;
*p++ = g;
*p++ = 0;
}
}
static void
color_select_update_blue (ColorSelectFill *csf)
{
guchar *p;
gint i, b;
p = csf->buffer;
csf->y += 1;
b = (csf->height - csf->y + 1) * 255 / csf->height;
if (b < 0)
b = 0;
if (b > 255)
b = 255;
for (i = 0; i < csf->width; i++)
{
*p++ = 0;
*p++ = 0;
*p++ = b;
}
}
static void
color_select_update_hue (ColorSelectFill *csf)
{
guchar *p;
gfloat h, f;
gint r, g, b;
gint i;
p = csf->buffer;
csf->y += 1;
h = csf->y * 360 / csf->height;
h = 360 - h;
if (h < 0)
h = 0;
if (h >= 360)
h = 0;
h /= 60;
f = (h - (int) h) * 255;
r = g = b = 0;
switch ((int) h)
{
case 0:
r = 255;
g = f;
b = 0;
break;
case 1:
r = 255 - f;
g = 255;
b = 0;
break;
case 2:
r = 0;
g = 255;
b = f;
break;
case 3:
r = 0;
g = 255 - f;
b = 255;
break;
case 4:
r = f;
g = 0;
b = 255;
break;
case 5:
r = 255;
g = 0;
b = 255 - f;
break;
}
for (i = 0; i < csf->width; i++)
{
*p++ = r;
*p++ = g;
*p++ = b;
}
}
static void
color_select_update_saturation (ColorSelectFill *csf)
{
guchar *p;
gint s;
gint i;
p = csf->buffer;
csf->y += 1;
s = csf->y * 255 / csf->height;
if (s < 0)
s = 0;
if (s > 255)
s = 255;
s = 255 - s;
for (i = 0; i < csf->width; i++)
{
*p++ = s;
*p++ = s;
*p++ = s;
}
}
static void
color_select_update_value (ColorSelectFill *csf)
{
guchar *p;
gint v;
gint i;
p = csf->buffer;
csf->y += 1;
v = csf->y * 255 / csf->height;
if (v < 0)
v = 0;
if (v > 255)
v = 255;
v = 255 - v;
for (i = 0; i < csf->width; i++)
{
*p++ = v;
*p++ = v;
*p++ = v;
}
}
static void
color_select_update_red_green (ColorSelectFill *csf)
{
guchar *p;
gint i, r, b;
gfloat g, dg;
p = csf->buffer;
csf->y += 1;
b = csf->values[BLUE];
r = (csf->height - csf->y + 1) * 255 / csf->height;
if (r < 0)
r = 0;
if (r > 255)
r = 255;
g = 0;
dg = 255.0 / csf->width;
for (i = 0; i < csf->width; i++)
{
*p++ = r;
*p++ = g;
*p++ = b;
g += dg;
}
}
static void
color_select_update_red_blue (ColorSelectFill *csf)
{
guchar *p;
gint i, r, g;
gfloat b, db;
p = csf->buffer;
csf->y += 1;
g = csf->values[GREEN];
r = (csf->height - csf->y + 1) * 255 / csf->height;
if (r < 0)
r = 0;
if (r > 255)
r = 255;
b = 0;
db = 255.0 / csf->width;
for (i = 0; i < csf->width; i++)
{
*p++ = r;
*p++ = g;
*p++ = b;
b += db;
}
}
static void
color_select_update_green_blue (ColorSelectFill *csf)
{
guchar *p;
gint i, g, r;
gfloat b, db;
p = csf->buffer;
csf->y += 1;
r = csf->values[RED];
g = (csf->height - csf->y + 1) * 255 / csf->height;
if (g < 0)
g = 0;
if (g > 255)
g = 255;
b = 0;
db = 255.0 / csf->width;
for (i = 0; i < csf->width; i++)
{
*p++ = r;
*p++ = g;
*p++ = b;
b += db;
}
}
static void
color_select_update_hue_saturation (ColorSelectFill *csf)
{
guchar *p;
gfloat h, v, s, ds;
gint f;
gint i;
p = csf->buffer;
csf->y += 1;
h = 360 - (csf->y * 360 / csf->height);
if (h < 0)
h = 0;
if (h > 359)
h = 359;
h /= 60;
f = (h - (int) h) * 255;
s = 0;
ds = 1.0 / csf->width;
v = csf->values[VALUE] / 100.0;
switch ((int) h)
{
case 0:
for (i = 0; i < csf->width; i++)
{
*p++ = v * 255;
*p++ = v * (255 - (s * (255 - f)));
*p++ = v * 255 * (1 - s);
s += ds;
}
break;
case 1:
for (i = 0; i < csf->width; i++)
{
*p++ = v * (255 - s * f);
*p++ = v * 255;
*p++ = v * 255 * (1 - s);
s += ds;
}
break;
case 2:
for (i = 0; i < csf->width; i++)
{
*p++ = v * 255 * (1 - s);
*p++ = v *255;
*p++ = v * (255 - (s * (255 - f)));
s += ds;
}
break;
case 3:
for (i = 0; i < csf->width; i++)
{
*p++ = v * 255 * (1 - s);
*p++ = v * (255 - s * f);
*p++ = v * 255;
s += ds;
}
break;
case 4:
for (i = 0; i < csf->width; i++)
{
*p++ = v * (255 - (s * (255 - f)));
*p++ = v * (255 * (1 - s));
*p++ = v * 255;
s += ds;
}
break;
case 5:
for (i = 0; i < csf->width; i++)
{
*p++ = v * 255;
*p++ = v * 255 * (1 - s);
*p++ = v * (255 - s * f);
s += ds;
}
break;
}
}
static void
color_select_update_hue_value (ColorSelectFill *csf)
{
guchar *p;
gfloat h, v, dv, s;
gint f;
gint i;
p = csf->buffer;
csf->y += 1;
h = 360 - (csf->y * 360 / csf->height);
if (h < 0)
h = 0;
if (h > 359)
h = 359;
h /= 60;
f = (h - (int) h) * 255;
v = 0;
dv = 1.0 / csf->width;
s = csf->values[SATURATION] / 100.0;
switch ((int) h)
{
case 0:
for (i = 0; i < csf->width; i++)
{
*p++ = v * 255;
*p++ = v * (255 - (s * (255 - f)));
*p++ = v * 255 * (1 - s);
v += dv;
}
break;
case 1:
for (i = 0; i < csf->width; i++)
{
*p++ = v * (255 - s * f);
*p++ = v * 255;
*p++ = v * 255 * (1 - s);
v += dv;
}
break;
case 2:
for (i = 0; i < csf->width; i++)
{
*p++ = v * 255 * (1 - s);
*p++ = v *255;
*p++ = v * (255 - (s * (255 - f)));
v += dv;
}
break;
case 3:
for (i = 0; i < csf->width; i++)
{
*p++ = v * 255 * (1 - s);
*p++ = v * (255 - s * f);
*p++ = v * 255;
v += dv;
}
break;
case 4:
for (i = 0; i < csf->width; i++)
{
*p++ = v * (255 - (s * (255 - f)));
*p++ = v * (255 * (1 - s));
*p++ = v * 255;
v += dv;
}
break;
case 5:
for (i = 0; i < csf->width; i++)
{
*p++ = v * 255;
*p++ = v * 255 * (1 - s);
*p++ = v * (255 - s * f);
v += dv;
}
break;
}
}
static void
color_select_update_saturation_value (ColorSelectFill *csf)
{
guchar *p;
gfloat h, v, dv, s;
gint f;
gint i;
p = csf->buffer;
csf->y += 1;
s = (float) csf->y / csf->height;
if (s < 0)
s = 0;
if (s > 1)
s = 1;
s = 1 - s;
h = (float) csf->values[HUE];
if (h >= 360)
h -= 360;
h /= 60;
f = (h - (int) h) * 255;
v = 0;
dv = 1.0 / csf->width;
switch ((int) h)
{
case 0:
for (i = 0; i < csf->width; i++)
{
*p++ = v * 255;
*p++ = v * (255 - (s * (255 - f)));
*p++ = v * 255 * (1 - s);
v += dv;
}
break;
case 1:
for (i = 0; i < csf->width; i++)
{
*p++ = v * (255 - s * f);
*p++ = v * 255;
*p++ = v * 255 * (1 - s);
v += dv;
}
break;
case 2:
for (i = 0; i < csf->width; i++)
{
*p++ = v * 255 * (1 - s);
*p++ = v *255;
*p++ = v * (255 - (s * (255 - f)));
v += dv;
}
break;
case 3:
for (i = 0; i < csf->width; i++)
{
*p++ = v * 255 * (1 - s);
*p++ = v * (255 - s * f);
*p++ = v * 255;
v += dv;
}
break;
case 4:
for (i = 0; i < csf->width; i++)
{
*p++ = v * (255 - (s * (255 - f)));
*p++ = v * (255 * (1 - s));
*p++ = v * 255;
v += dv;
}
break;
case 5:
for (i = 0; i < csf->width; i++)
{
*p++ = v * 255;
*p++ = v * 255 * (1 - s);
*p++ = v * (255 - s * f);
v += dv;
}
break;
}
}
/*****************************/
/* Colour notebook glue */
typedef struct
{
GimpColorSelector_Callback callback;
gpointer *client_data;
ColorSelect *csp;
GtkWidget *main_vbox;
} notebook_glue;
static GtkWidget *
color_select_notebook_new (gint r,
gint g,
gint b,
GimpColorSelector_Callback callback,
gpointer data,
/* RETURNS: */
void **selector_data)
{
ColorSelect *csp;
notebook_glue *glue;
glue = g_new (notebook_glue, 1);
csp = g_new (ColorSelect, 1);
glue->csp = csp;
glue->callback = callback;
glue->client_data = data;
csp->callback = color_select_notebook_update_callback;
csp->client_data = glue;
csp->z_color_fill = HUE;
csp->xy_color_fill = SATURATION_VALUE;
csp->gc = NULL;
csp->wants_updates = TRUE;
csp->values[RED] = csp->orig_values[0] = r;
csp->values[GREEN] = csp->orig_values[1] = g;
csp->values[BLUE] = csp->orig_values[2] = b;
color_select_update_hsv_values (csp);
color_select_update_pos (csp);
glue->main_vbox = color_select_widget_new (csp, r, g, b);
/* the shell is provided by the notebook */
csp->shell = NULL;
color_select_image_fill (csp->z_color, csp->z_color_fill, csp->values);
color_select_image_fill (csp->xy_color, csp->xy_color_fill, csp->values);
(*selector_data) = glue;
return glue->main_vbox;
}
static void
color_select_notebook_free (void *data)
{
notebook_glue *glue = data;
color_select_free (glue->csp);
/* don't need to destroy the widget, since it's done by the caller
* of this function */
g_free (glue);
}
static void
color_select_notebook_setcolor (void *data,
int r, int g, int b, int set_current)
{
notebook_glue *glue = data;
color_select_set_color (glue->csp, r, g, b, set_current);
}
static void
color_select_notebook_update_callback (gint r,
gint g,
gint b,
ColorSelectState state,
void *data)
{
notebook_glue *glue = data;
switch (state)
{
case COLOR_SELECT_UPDATE:
glue->callback (glue->client_data, r, g, b);
break;
default:
g_warning ("state %d can't happen!", state);
break;
}
}