mirror of https://github.com/GNOME/gimp.git
1941 lines
42 KiB
C
1941 lines
42 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "appenv.h"
|
|
#include "actionarea.h"
|
|
#include "color_select.h"
|
|
#include "colormaps.h"
|
|
#include "errors.h"
|
|
#include "gimprc.h"
|
|
#include "session.h"
|
|
#include "color_area.h" /* for color_area_draw_rect */
|
|
|
|
#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 {
|
|
unsigned char *buffer;
|
|
int y;
|
|
int width;
|
|
int height;
|
|
int *values;
|
|
ColorSelectFillUpdateProc update;
|
|
};
|
|
|
|
static void color_select_update (ColorSelectP, ColorSelectUpdateType);
|
|
static void color_select_update_caller (ColorSelectP);
|
|
static void color_select_update_values (ColorSelectP);
|
|
static void color_select_update_rgb_values (ColorSelectP);
|
|
static void color_select_update_hsv_values (ColorSelectP);
|
|
static void color_select_update_pos (ColorSelectP);
|
|
static void color_select_update_sliders (ColorSelectP, int);
|
|
static void color_select_update_entries (ColorSelectP, int);
|
|
static void color_select_update_colors (ColorSelectP, int);
|
|
|
|
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 *, ColorSelectP);
|
|
static gint color_select_xy_events (GtkWidget *, GdkEvent *, ColorSelectP);
|
|
static gint color_select_z_expose (GtkWidget *, GdkEventExpose *, ColorSelectP);
|
|
static gint color_select_z_events (GtkWidget *, GdkEvent *, ColorSelectP);
|
|
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, int *);
|
|
|
|
static void color_select_draw_z_marker (ColorSelectP, int);
|
|
static void color_select_draw_xy_marker (ColorSelectP, int);
|
|
|
|
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 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,
|
|
};
|
|
|
|
static ActionAreaItem action_items[2] =
|
|
{
|
|
{ "OK", color_select_ok_callback, NULL, NULL },
|
|
{ "Cancel", color_select_cancel_callback, NULL, NULL },
|
|
};
|
|
|
|
ColorSelectP
|
|
color_select_new (int r,
|
|
int g,
|
|
int b,
|
|
ColorSelectCallback callback,
|
|
void *client_data,
|
|
int wants_updates)
|
|
{
|
|
/* static char *toggle_titles[6] = { "Hue", "Saturation", "Value", "Red", "Green", "Blue" }; */
|
|
static char *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 };
|
|
|
|
ColorSelectP csp;
|
|
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;
|
|
char buffer[16];
|
|
int i;
|
|
|
|
csp = g_malloc (sizeof (_ColorSelect));
|
|
|
|
csp->callback = callback;
|
|
csp->client_data = client_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 = gtk_vbox_new (FALSE, 2);
|
|
gtk_container_border_width (GTK_CONTAINER (main_vbox), 2);
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (csp->shell)->vbox), main_vbox, TRUE, TRUE, 0);
|
|
gtk_widget_show (main_vbox);
|
|
|
|
main_hbox = gtk_hbox_new (FALSE, 2);
|
|
gtk_container_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);
|
|
|
|
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);
|
|
|
|
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_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 */
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
/* 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_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 ();
|
|
sprintf (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 ();
|
|
sprintf(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), 55, 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);
|
|
|
|
/* 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;
|
|
}
|
|
|
|
void
|
|
color_select_show (ColorSelectP csp)
|
|
{
|
|
if (csp)
|
|
gtk_widget_show (csp->shell);
|
|
}
|
|
|
|
void
|
|
color_select_hide (ColorSelectP csp)
|
|
{
|
|
if (csp)
|
|
gtk_widget_hide (csp->shell);
|
|
}
|
|
|
|
void
|
|
color_select_free (ColorSelectP csp)
|
|
{
|
|
if (csp)
|
|
{
|
|
gtk_widget_destroy (csp->shell);
|
|
gdk_gc_destroy (csp->gc);
|
|
g_free (csp);
|
|
}
|
|
}
|
|
|
|
void
|
|
color_select_set_color (ColorSelectP csp,
|
|
int r,
|
|
int g,
|
|
int b,
|
|
int 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 (ColorSelectP 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 (ColorSelectP 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 (ColorSelectP 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 (ColorSelectP csp)
|
|
{
|
|
float h, s, v;
|
|
float 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 (ColorSelectP csp)
|
|
{
|
|
int r, g, b;
|
|
float h, s, v;
|
|
int min, max;
|
|
int 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 (ColorSelectP 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 (ColorSelectP csp,
|
|
int skip)
|
|
{
|
|
int 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 (ColorSelectP csp,
|
|
int skip)
|
|
{
|
|
char buffer[16];
|
|
int i;
|
|
|
|
if (csp)
|
|
{
|
|
for (i = 0; i < 6; i++)
|
|
if (i != skip)
|
|
{
|
|
sprintf (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);
|
|
}
|
|
|
|
sprintf(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 (ColorSelectP csp,
|
|
int which)
|
|
{
|
|
GdkWindow *window;
|
|
GdkColor color;
|
|
int red, green, blue;
|
|
int 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];
|
|
}
|
|
|
|
gdk_window_get_size (window, &width, &height);
|
|
|
|
store_color (&color.pixel, red, green, blue);
|
|
|
|
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 *w,
|
|
gpointer client_data)
|
|
{
|
|
ColorSelectP csp;
|
|
|
|
csp = (ColorSelectP) client_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 *w,
|
|
GdkEvent *e,
|
|
gpointer client_data)
|
|
{
|
|
color_select_cancel_callback (w, client_data);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static void
|
|
color_select_cancel_callback (GtkWidget *w,
|
|
gpointer client_data)
|
|
{
|
|
ColorSelectP csp;
|
|
|
|
csp = (ColorSelectP) client_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,
|
|
ColorSelectP csp)
|
|
{
|
|
if (!csp->gc)
|
|
csp->gc = gdk_gc_new (widget->window);
|
|
|
|
color_select_draw_xy_marker (csp, 1);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
color_select_xy_events (GtkWidget *widget,
|
|
GdkEvent *event,
|
|
ColorSelectP csp)
|
|
{
|
|
GdkEventButton *bevent;
|
|
GdkEventMotion *mevent;
|
|
int tx, ty;
|
|
|
|
switch (event->type)
|
|
{
|
|
case GDK_BUTTON_PRESS:
|
|
bevent = (GdkEventButton *) event;
|
|
|
|
color_select_draw_xy_marker (csp, 1);
|
|
|
|
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, 1);
|
|
|
|
color_select_update (csp, UPDATE_VALUES);
|
|
break;
|
|
|
|
case GDK_BUTTON_RELEASE:
|
|
bevent = (GdkEventButton *) event;
|
|
|
|
color_select_draw_xy_marker (csp, 1);
|
|
|
|
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, 1);
|
|
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, 1);
|
|
|
|
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, 1);
|
|
color_select_update (csp, UPDATE_VALUES);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
color_select_z_expose (GtkWidget *widget,
|
|
GdkEventExpose *event,
|
|
ColorSelectP csp)
|
|
{
|
|
if (!csp->gc)
|
|
csp->gc = gdk_gc_new (widget->window);
|
|
|
|
color_select_draw_z_marker (csp, 1);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
color_select_z_events (GtkWidget *widget,
|
|
GdkEvent *event,
|
|
ColorSelectP csp)
|
|
{
|
|
GdkEventButton *bevent;
|
|
GdkEventMotion *mevent;
|
|
int tx, ty;
|
|
|
|
switch (event->type)
|
|
{
|
|
case GDK_BUTTON_PRESS:
|
|
bevent = (GdkEventButton *) event;
|
|
|
|
color_select_draw_z_marker (csp, 1);
|
|
|
|
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, 1);
|
|
color_select_update (csp, UPDATE_VALUES);
|
|
break;
|
|
|
|
case GDK_BUTTON_RELEASE:
|
|
bevent = (GdkEventButton *) event;
|
|
|
|
color_select_draw_z_marker (csp, 1);
|
|
|
|
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, 1);
|
|
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, 1);
|
|
|
|
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, 1);
|
|
color_select_update (csp, UPDATE_VALUES);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
color_select_color_events (GtkWidget *widget,
|
|
GdkEvent *event)
|
|
{
|
|
ColorSelectP csp;
|
|
|
|
csp = (ColorSelectP) 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)
|
|
{
|
|
ColorSelectP csp;
|
|
int old_values[6];
|
|
int update_z_marker;
|
|
int update_xy_marker;
|
|
int i, j;
|
|
|
|
csp = (ColorSelectP) 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, 1);
|
|
color_select_update (csp, UPDATE_POS | UPDATE_XY_COLOR);
|
|
color_select_draw_z_marker (csp, 1);
|
|
}
|
|
else
|
|
{
|
|
if (update_z_marker)
|
|
color_select_draw_z_marker (csp, 1);
|
|
if (update_xy_marker)
|
|
color_select_draw_xy_marker (csp, 1);
|
|
|
|
color_select_update (csp, UPDATE_POS);
|
|
|
|
if (update_z_marker)
|
|
color_select_draw_z_marker (csp, 1);
|
|
if (update_xy_marker)
|
|
color_select_draw_xy_marker (csp, 1);
|
|
}
|
|
|
|
color_select_update (csp, UPDATE_NEW_COLOR);
|
|
}
|
|
}
|
|
|
|
static void
|
|
color_select_entry_update (GtkWidget *w,
|
|
gpointer data)
|
|
{
|
|
ColorSelectP csp;
|
|
int old_values[6];
|
|
int update_z_marker;
|
|
int update_xy_marker;
|
|
int i, j;
|
|
|
|
csp = (ColorSelectP) data;
|
|
|
|
if (csp)
|
|
{
|
|
for (i = 0; i < 6; i++)
|
|
if (csp->entries[i] == w)
|
|
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, 1);
|
|
color_select_update (csp, UPDATE_POS | UPDATE_XY_COLOR);
|
|
color_select_draw_z_marker (csp, 1);
|
|
}
|
|
else
|
|
{
|
|
if (update_z_marker)
|
|
color_select_draw_z_marker (csp, 1);
|
|
if (update_xy_marker)
|
|
color_select_draw_xy_marker (csp, 1);
|
|
|
|
color_select_update (csp, UPDATE_POS);
|
|
|
|
if (update_z_marker)
|
|
color_select_draw_z_marker (csp, 1);
|
|
if (update_xy_marker)
|
|
color_select_draw_xy_marker (csp, 1);
|
|
}
|
|
|
|
color_select_update (csp, UPDATE_NEW_COLOR);
|
|
}
|
|
}
|
|
|
|
static void
|
|
color_select_toggle_update (GtkWidget *w,
|
|
gpointer data)
|
|
{
|
|
ColorSelectP csp;
|
|
ColorSelectFillType type = HUE;
|
|
int i;
|
|
|
|
if (!GTK_TOGGLE_BUTTON (w)->active)
|
|
return;
|
|
|
|
csp = (ColorSelectP) data;
|
|
|
|
if (csp)
|
|
{
|
|
for (i = 0; i < 6; i++)
|
|
if (w == 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 *w,
|
|
GdkEvent *event,
|
|
gpointer data)
|
|
{
|
|
ColorSelectP csp;
|
|
gchar buffer[8];
|
|
gchar *hex_color;
|
|
guint hex_rgb;
|
|
|
|
csp = (ColorSelectP) data;
|
|
|
|
if (csp)
|
|
{
|
|
hex_color = g_strdup (gtk_entry_get_text (GTK_ENTRY (csp->hex_entry)));
|
|
|
|
sprintf(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,
|
|
int *values)
|
|
{
|
|
ColorSelectFill csf;
|
|
int 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 (ColorSelectP csp,
|
|
int update)
|
|
{
|
|
int width;
|
|
int y;
|
|
|
|
if (csp->gc)
|
|
{
|
|
y = (Z_DEF_HEIGHT - 1) - ((Z_DEF_HEIGHT - 1) * csp->pos[2]) / 255;
|
|
width = csp->z_color->requisition.width;
|
|
if (width <= 0)
|
|
return;
|
|
|
|
gdk_gc_set_function (csp->gc, GDK_INVERT);
|
|
gdk_draw_line (csp->z_color->window, csp->gc, 0, y, width, y);
|
|
gdk_gc_set_function (csp->gc, GDK_COPY);
|
|
}
|
|
}
|
|
|
|
static void
|
|
color_select_draw_xy_marker (ColorSelectP csp,
|
|
int update)
|
|
{
|
|
int width;
|
|
int height;
|
|
int x, y;
|
|
|
|
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;
|
|
if ((width <= 0) || (height <= 0))
|
|
return;
|
|
|
|
gdk_gc_set_function (csp->gc, GDK_INVERT);
|
|
gdk_draw_line (csp->xy_color->window, csp->gc, 0, y, width, y);
|
|
gdk_draw_line (csp->xy_color->window, csp->gc, x, 0, x, height);
|
|
gdk_gc_set_function (csp->gc, GDK_COPY);
|
|
}
|
|
}
|
|
|
|
static void
|
|
color_select_update_red (ColorSelectFill *csf)
|
|
{
|
|
unsigned char *p;
|
|
int 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)
|
|
{
|
|
unsigned char *p;
|
|
int 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)
|
|
{
|
|
unsigned char *p;
|
|
int 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)
|
|
{
|
|
unsigned char *p;
|
|
float h, f;
|
|
int r, g, b;
|
|
int 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)
|
|
{
|
|
unsigned char *p;
|
|
int s;
|
|
int 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)
|
|
{
|
|
unsigned char *p;
|
|
int v;
|
|
int 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)
|
|
{
|
|
unsigned char *p;
|
|
int i, r, b;
|
|
float 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)
|
|
{
|
|
unsigned char *p;
|
|
int i, r, g;
|
|
float 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)
|
|
{
|
|
unsigned char *p;
|
|
int i, g, r;
|
|
float 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)
|
|
{
|
|
unsigned char *p;
|
|
float h, v, s, ds;
|
|
int f;
|
|
int 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)
|
|
{
|
|
unsigned char *p;
|
|
float h, v, dv, s;
|
|
int f;
|
|
int 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)
|
|
{
|
|
unsigned char *p;
|
|
float h, v, dv, s;
|
|
int f;
|
|
int 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;
|
|
}
|
|
}
|